diff --git a/build.gradle b/build.gradle index ccbba32..2c3b903 100644 --- a/build.gradle +++ b/build.gradle @@ -45,6 +45,13 @@ dependencies { // Spring Test 의존성 추가 testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' + + //QueryDsl 의존성 추가 + implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' + annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta" + annotationProcessor "jakarta.annotation:jakarta.annotation-api" + annotationProcessor "jakarta.persistence:jakarta.persistence-api" + } tasks.named('test') { diff --git a/src/main/java/one/kiosk/controller/MenuController.java b/src/main/java/one/kiosk/controller/MenuController.java new file mode 100644 index 0000000..49f20b8 --- /dev/null +++ b/src/main/java/one/kiosk/controller/MenuController.java @@ -0,0 +1,89 @@ +package one.kiosk.controller; + +import lombok.RequiredArgsConstructor; +import one.kiosk.dto.ApiResponse; +import one.kiosk.dto.MenuReturnDto; +import one.kiosk.dto.MenuUpdateDto; +import one.kiosk.dto.MenuUploadDto; +import one.kiosk.entity.MenuEntity; +import one.kiosk.exception.GlobalExceptionHandler; +import one.kiosk.service.MenuService; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; + +import java.util.List; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/menu") +public class MenuController { + + private final MenuService menuService; + + //메뉴 등록 + @PostMapping("/upload") + public ResponseEntity> upload(@RequestHeader("Authorization") String token, @RequestBody MenuUploadDto menuUploadDto) { + + //토큰의 "Bearer " 지우기 + String tokenId = token.replace("Bearer ", ""); + + menuService.upload(menuUploadDto, tokenId); + //메뉴 등록 성공 + return ResponseEntity.status(HttpStatus.CREATED) + .body(new ApiResponse<>(true,"메뉴가 등록되었습니다.",null)); + } + + //메뉴 검색 + @GetMapping("search/{id}") + public ResponseEntity> upload(@RequestHeader("Authorization") String token,@PathVariable Long id) { + + //토큰의 "Bearer " 지우기 + String tokenId = token.replace("Bearer ", ""); + + MenuReturnDto menuReturnDto = menuService.find(id,tokenId); + + if (menuReturnDto == null) { + throw new GlobalExceptionHandler.MenuNotFoundException("메뉴를 찾을 수 없습니다"); + } + + //메뉴 검색 성공 + return ResponseEntity.status(HttpStatus.OK) + .body(new ApiResponse<>(true,"메뉴 정보를 조회합니다",menuReturnDto)); + } + + //메뉴 전체조회 + @GetMapping("/total") + public ResponseEntity>> total(@RequestHeader("Authorization") String token) { + //토큰의 "Bearer " 지우기 + String tokenId = token.replace("Bearer ", ""); + List menuDtos = menuService.findAll(tokenId); + + return ResponseEntity.status(HttpStatus.OK) + .body(new ApiResponse<>(true,"전체 메뉴를 조회합니다",menuDtos)); + } + + //메뉴 수정 + @PutMapping("/update") + public ResponseEntity> update(@RequestHeader("Authorization") String token, @RequestBody MenuUpdateDto menuUpdateDto) { + //토큰의 "Bearer " 지우기 + String tokenId = token.replace("Bearer ", ""); + menuService.update(menuUpdateDto,tokenId); + //수정 완료 + return ResponseEntity.status(HttpStatus.OK) + .body(new ApiResponse<>(true,"메뉴정보 수정이 완료되었습니다.",null)); + } + + //메뉴 삭제 + @DeleteMapping("/delete/{id}") + public ResponseEntity> delete(@RequestHeader("Authorization") String token, @PathVariable Long id) { + //토큰의 "Bearer " 지우기 + String tokenId = token.replace("Bearer ", ""); + menuService.delete(id,tokenId); + //삭제 성공 + return ResponseEntity.status(HttpStatus.OK) + .body(new ApiResponse<>(true,"메뉴를 삭제하였습니다.",null)); + } +} diff --git a/src/main/java/one/kiosk/dto/ApiResponse.java b/src/main/java/one/kiosk/dto/ApiResponse.java new file mode 100644 index 0000000..865eb21 --- /dev/null +++ b/src/main/java/one/kiosk/dto/ApiResponse.java @@ -0,0 +1,12 @@ +package one.kiosk.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class ApiResponse { + private boolean success; + private String message; + private T data; +} diff --git a/src/main/java/one/kiosk/dto/InfoDto.java b/src/main/java/one/kiosk/dto/InfoDto.java new file mode 100644 index 0000000..4546aa4 --- /dev/null +++ b/src/main/java/one/kiosk/dto/InfoDto.java @@ -0,0 +1,13 @@ +package one.kiosk.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import one.kiosk.jwt.MemberRole; + +@Data +@AllArgsConstructor +public class InfoDto { + private String username; + private String company; + private MemberRole role; +} \ No newline at end of file diff --git a/src/main/java/one/kiosk/dto/MenuOptionReturnDto.java b/src/main/java/one/kiosk/dto/MenuOptionReturnDto.java new file mode 100644 index 0000000..a3b5483 --- /dev/null +++ b/src/main/java/one/kiosk/dto/MenuOptionReturnDto.java @@ -0,0 +1,19 @@ +package one.kiosk.dto; + +import lombok.*; +import one.kiosk.entity.MenuOptionEntity; + +@Data +@NoArgsConstructor +@Getter +@Setter +public class MenuOptionReturnDto { + private String optionname; + private int price; + + public MenuOptionReturnDto(String optionname, int price) { + this.optionname = optionname; + this.price = price; + } +} + diff --git a/src/main/java/one/kiosk/dto/MenuReturnDto.java b/src/main/java/one/kiosk/dto/MenuReturnDto.java new file mode 100644 index 0000000..ad2fc66 --- /dev/null +++ b/src/main/java/one/kiosk/dto/MenuReturnDto.java @@ -0,0 +1,42 @@ +package one.kiosk.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import one.kiosk.entity.MenuEntity; +import one.kiosk.jwt.JWTUtil; + +import java.util.List; + +@Data +@NoArgsConstructor +public class MenuReturnDto { + + private String menuname; + private int price; + private String category; + private String imageUrl; + private List option; + + // 생성자(전체조회용) + public MenuReturnDto(String menuname, int price, String category, String imgUrl, List menuOptions) { + this.menuname = menuname; + this.price = price; + this.category = category; + this.imageUrl = imgUrl; + this.option = menuOptions; + } + //메뉴 entity와 검색을 통해 나온 이미지의 url을 함께 dto에 저장. 전체 메뉴옵션을 함께 리턴(단일조회용) + public static MenuReturnDto toMenuReturnDto(MenuEntity menuEntity, String imageUrl, List optionReturnDto) { + MenuReturnDto dto = new MenuReturnDto(); + dto.setMenuname(menuEntity.getMenuname()); + dto.setPrice(menuEntity.getPrice()); + dto.setCategory(menuEntity.getCategory()); + dto.setImageUrl(imageUrl); + dto.setOption(optionReturnDto); + return dto; + } + +} + diff --git a/src/main/java/one/kiosk/dto/MenuUpdateDto.java b/src/main/java/one/kiosk/dto/MenuUpdateDto.java new file mode 100644 index 0000000..859f1c1 --- /dev/null +++ b/src/main/java/one/kiosk/dto/MenuUpdateDto.java @@ -0,0 +1,18 @@ +package one.kiosk.dto; + +import lombok.*; +import one.kiosk.entity.MenuEntity; + +@Data +@AllArgsConstructor +@Getter +@Builder +public class MenuUpdateDto { + + private Long id; + private String menuname; + private int price; + private String category; + private Long imageId; + +} diff --git a/src/main/java/one/kiosk/dto/MenuUploadDto.java b/src/main/java/one/kiosk/dto/MenuUploadDto.java new file mode 100644 index 0000000..9ccdd48 --- /dev/null +++ b/src/main/java/one/kiosk/dto/MenuUploadDto.java @@ -0,0 +1,32 @@ +package one.kiosk.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import one.kiosk.entity.Image; +import one.kiosk.entity.MenuEntity; +import one.kiosk.jwt.JWTUtil; + +@Data +@AllArgsConstructor +@Builder +public class MenuUploadDto { + private String menuname; + private int price; + private String category; + private Long adminId; + private Image imageId; + + + public MenuEntity toMenuEntity() { + return MenuEntity.builder() + .menuname(this.menuname) + .price(this.price) + .category(this.category) + .adminId(this.adminId) + .imageId(this.imageId).build(); + } + +} + diff --git a/src/main/java/one/kiosk/entity/MenuEntity.java b/src/main/java/one/kiosk/entity/MenuEntity.java new file mode 100644 index 0000000..498ffa4 --- /dev/null +++ b/src/main/java/one/kiosk/entity/MenuEntity.java @@ -0,0 +1,47 @@ +package one.kiosk.entity; + +import jakarta.persistence.*; +import lombok.*; +import one.kiosk.jwt.MemberRole; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; + +import java.time.LocalDateTime; +import java.util.List; + +@Entity +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Data +@Getter +@Setter +@Table(name = "tbl_menu") +public class MenuEntity extends DateEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "menu_id") + private Long menuId; + + @Column(name = "menuname", nullable = false) + private String menuname; + + @Column(name = "price", nullable = false) + private int price; + + @Column(name = "category", nullable = false) + private String category; + + //jwt 토큰에서 추출한 id를 저장 + @Column(name = "admin_id", nullable = false) + private Long adminId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "image_id") // 외래키 설정 + private Image imageId; + + + + +} diff --git a/src/main/java/one/kiosk/entity/MenuOptionEntity.java b/src/main/java/one/kiosk/entity/MenuOptionEntity.java new file mode 100644 index 0000000..d213b74 --- /dev/null +++ b/src/main/java/one/kiosk/entity/MenuOptionEntity.java @@ -0,0 +1,23 @@ +package one.kiosk.entity; + +import jakarta.persistence.*; +import lombok.Data; +import lombok.Getter; +import lombok.Setter; + +@Data +@Entity +@Table(name = "tbl_menuoption") +public class MenuOptionEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "menuop_id") + private Long menuopid; + + @Column(name = "optionname") + private String optionname; + + @Column(name = "price") + private int price; + +} diff --git a/src/main/java/one/kiosk/exception/GlobalExceptionHandler.java b/src/main/java/one/kiosk/exception/GlobalExceptionHandler.java index eff1975..b6df004 100644 --- a/src/main/java/one/kiosk/exception/GlobalExceptionHandler.java +++ b/src/main/java/one/kiosk/exception/GlobalExceptionHandler.java @@ -48,6 +48,31 @@ public CustomAuthenticationException(String message) { } } + // 내부 클래스 : 메뉴 crud 예외들 + public static class MenuUplaodException extends RuntimeException { + public MenuUplaodException(String message) {super(message);} + } + + public static class MenuNotFoundException extends RuntimeException { + public MenuNotFoundException(String message) {super(message);} + } + + public static class MenuNotExistException extends RuntimeException { + public MenuNotExistException(String message) {super(message);} + } + + public static class MenuUpdateException extends RuntimeException { + public MenuUpdateException(String message) {super(message);} + } + + public static class MenuDeleteException extends RuntimeException { + public MenuDeleteException(String message) {super(message);} + } + + public static class UserUnmatchException extends RuntimeException { + public UserUnmatchException(String message) {super(message);} + } + // 예외 처리 메서드들 @ExceptionHandler(UserNotFoundException.class) public ResponseEntity handleUserNotFoundException(UserNotFoundException ex) { @@ -105,4 +130,40 @@ public ResponseEntity handleGeneralException(Exception ex) { logger.error("Unhandled Exception: ", ex); return createResponse(HttpStatus.INTERNAL_SERVER_ERROR, "서버 내부 오류가 발생했습니다."); } + + @ExceptionHandler(MenuUplaodException.class) + public ResponseEntity handleMenuUplaodException(MenuUplaodException ex) { + logger.error("MenuUplaodException: ", ex); + return createResponse(HttpStatus.BAD_REQUEST,"메뉴 등록에 실패하였습니다."); + } + + @ExceptionHandler(MenuNotFoundException.class) + public ResponseEntity handleMenuNotFoundException(MenuNotFoundException ex) { + logger.error("MenuNotFoundException: ", ex); + return createResponse(HttpStatus.NOT_FOUND,ex.getMessage()); + } + + @ExceptionHandler(MenuNotExistException.class) + public ResponseEntity handleMenuNotExistException(MenuNotExistException ex) { + logger.error("MenuNotExistException: ", ex); + return createResponse(HttpStatus.NOT_FOUND,"등록된 메뉴가 없습니다."); + } + + @ExceptionHandler(MenuUpdateException.class) + public ResponseEntity handleMenuUpdateException(MenuUpdateException ex) { + logger.error("MenuUpdateException: ", ex); + return createResponse(HttpStatus.BAD_REQUEST, "메뉴를 수정하지 못했습니다"); + } + + @ExceptionHandler(MenuDeleteException.class) + public ResponseEntity handleMenuDeleteException(MenuDeleteException ex) { + logger.error("MenuDeleteException: ", ex); + return createResponse(HttpStatus.BAD_REQUEST,"메뉴를 삭제하지 못했습니다."); + } + + @ExceptionHandler(UserUnmatchException.class) + public ResponseEntity handleUserUnmatchException(UserUnmatchException ex) { + logger.error("UserUnmatchException : ", ex); + return createResponse(HttpStatus.BAD_REQUEST,"해당 메뉴에 접근 권한이 없습니다."); + } } diff --git a/src/main/java/one/kiosk/jwt/JWTFilter.java b/src/main/java/one/kiosk/jwt/JWTFilter.java index 1dda3cb..6c668c4 100644 --- a/src/main/java/one/kiosk/jwt/JWTFilter.java +++ b/src/main/java/one/kiosk/jwt/JWTFilter.java @@ -59,12 +59,14 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse } // 토큰에서 사용자 정보 추출 + Long adminId = jwtUtil.getId(token); String username = jwtUtil.getUsername(token); String role = jwtUtil.getRole(token); String company = jwtUtil.getCompany(token); // Member 객체 생성 Member member = new Member(); + member.setId(adminId); member.setUsername(username); member.setPassword("임시 비밀번호"); // 실제 비밀번호는 필요하지 않음 member.setRole(MemberRole.valueOf(role)); // Enum 변환 diff --git a/src/main/java/one/kiosk/jwt/JWTUtil.java b/src/main/java/one/kiosk/jwt/JWTUtil.java index 1bdd5a2..db6bb91 100644 --- a/src/main/java/one/kiosk/jwt/JWTUtil.java +++ b/src/main/java/one/kiosk/jwt/JWTUtil.java @@ -22,6 +22,9 @@ public JWTUtil(@Value("${spring.jwt.secret}") String secret) { this.secretKey = Keys.hmacShaKeyFor(secret.getBytes()); // HS256 알고리즘에 적합한 SecretKey 생성 } + //JWT 토큰에서 id 추출 + public Long getId(String token) {return extractAllClaims(token).get("id", Long.class);} + // JWT 토큰에서 username 추출 public String getUsername(String token) { return extractAllClaims(token).get("username", String.class); @@ -72,8 +75,9 @@ private Claims extractAllClaims(String token) { } // JWT 토큰 생성 메서드 - public String createJwt(String username, String company, String role) { + public String createJwt(Long id,String username, String company, String role) { return Jwts.builder() + .claim("id",id) .claim("username", username) .claim("role", role) .claim("company", company) diff --git a/src/main/java/one/kiosk/jwt/LoginFilter.java b/src/main/java/one/kiosk/jwt/LoginFilter.java index ba719f5..d947117 100644 --- a/src/main/java/one/kiosk/jwt/LoginFilter.java +++ b/src/main/java/one/kiosk/jwt/LoginFilter.java @@ -44,6 +44,7 @@ protected void successfulAuthentication(HttpServletRequest request, HttpServletR CustomUserDetails customUserDetails = (CustomUserDetails) authentication.getPrincipal(); String username = customUserDetails.getUsername(); String company = customUserDetails.getCompany(); + Long id = customUserDetails.getId(); //role 추출 @@ -53,7 +54,7 @@ protected void successfulAuthentication(HttpServletRequest request, HttpServletR String role = auth.getAuthority(); // JWTUtil에 token 생성 요청 - String token = jwtUtil.createJwt(username, company, role); + String token = jwtUtil.createJwt(id, username, company, role); // JWT를 response에 담아서 응답 (header 부분에) // key : "Authorization" diff --git a/src/main/java/one/kiosk/repository/MenuJpaRepository.java b/src/main/java/one/kiosk/repository/MenuJpaRepository.java new file mode 100644 index 0000000..167fadc --- /dev/null +++ b/src/main/java/one/kiosk/repository/MenuJpaRepository.java @@ -0,0 +1,18 @@ +package one.kiosk.repository; + + +import one.kiosk.dto.MenuReturnDto; +import one.kiosk.entity.MenuEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; +import java.util.Optional; + +public interface MenuJpaRepository extends JpaRepository, MenuJpaRpositoryCustom { + MenuEntity findByMenuId(Long menuId); + + List findAllByAdminId(Long adminId); + +} diff --git a/src/main/java/one/kiosk/repository/MenuJpaRepositoryImpl.java b/src/main/java/one/kiosk/repository/MenuJpaRepositoryImpl.java new file mode 100644 index 0000000..61d5cbc --- /dev/null +++ b/src/main/java/one/kiosk/repository/MenuJpaRepositoryImpl.java @@ -0,0 +1,55 @@ +package one.kiosk.repository; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import one.kiosk.dto.MenuOptionReturnDto; +import one.kiosk.dto.MenuReturnDto; +import one.kiosk.entity.MenuEntity; +import one.kiosk.entity.QImage; +import one.kiosk.entity.QMenuEntity; +import one.kiosk.entity.QMenuOptionEntity; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.stream.Collectors; + +@Repository +@RequiredArgsConstructor +public class MenuJpaRepositoryImpl implements MenuJpaRpositoryCustom{ + private final JPAQueryFactory queryFactory; + + //메뉴 전체조회 리스트 생성, 옵션dto 리스트 따로 생성 후 메뉴 전체조회 리스트 항목 한개당 옵션dto 넣기 + @Override + public List findAllMenuWithOptionsByAdminId(Long adminId) { + QMenuEntity menu = QMenuEntity.menuEntity; + QMenuOptionEntity option = QMenuOptionEntity.menuOptionEntity; + QImage image = QImage.image; + + // 모든 메뉴 조회 + List menus = queryFactory + .selectFrom(menu) + .leftJoin(menu.imageId, image).fetchJoin() // 메뉴와 이미지를 조인 + .where(menu.adminId.eq(adminId)) + .fetch(); + + //모든 옵션 조회후 옵션 dto리스트 생성 + List options = queryFactory + .selectFrom(option) + .fetch() + .stream() + .map(o -> new MenuOptionReturnDto(o.getOptionname(), o.getPrice())) + .collect(Collectors.toList()); + + // 각 메뉴 항목에 옵션 리스트를 넣어 DTO로 변환 + return menus.stream() + .map(m -> new MenuReturnDto( + m.getMenuname(), + m.getPrice(), + m.getCategory(), + m.getImageId() != null ? m.getImageId().getImageUrl() : null, + options // 메뉴 항목 하나당 모든 옵션들 포함 + )) + .collect(Collectors.toList()); + + } +} diff --git a/src/main/java/one/kiosk/repository/MenuJpaRpositoryCustom.java b/src/main/java/one/kiosk/repository/MenuJpaRpositoryCustom.java new file mode 100644 index 0000000..d56cd3e --- /dev/null +++ b/src/main/java/one/kiosk/repository/MenuJpaRpositoryCustom.java @@ -0,0 +1,10 @@ +package one.kiosk.repository; + +import one.kiosk.dto.MenuReturnDto; + +import java.util.List; + +public interface MenuJpaRpositoryCustom { + List findAllMenuWithOptionsByAdminId(Long adminId); + +} diff --git a/src/main/java/one/kiosk/repository/MenuOptionRepository.java b/src/main/java/one/kiosk/repository/MenuOptionRepository.java new file mode 100644 index 0000000..bfa2526 --- /dev/null +++ b/src/main/java/one/kiosk/repository/MenuOptionRepository.java @@ -0,0 +1,7 @@ +package one.kiosk.repository; + +import one.kiosk.entity.MenuOptionEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MenuOptionRepository extends JpaRepository, MenuOptionRepositoryCustom { +} diff --git a/src/main/java/one/kiosk/repository/MenuOptionRepositoryCustom.java b/src/main/java/one/kiosk/repository/MenuOptionRepositoryCustom.java new file mode 100644 index 0000000..45b930a --- /dev/null +++ b/src/main/java/one/kiosk/repository/MenuOptionRepositoryCustom.java @@ -0,0 +1,12 @@ +package one.kiosk.repository; + +import one.kiosk.dto.MenuOptionReturnDto; +import one.kiosk.entity.MenuOptionEntity; + +import java.util.List; + +public interface MenuOptionRepositoryCustom { + + //쿼리문 실행을 위한 커스텀 리포지토리 + List findMenuOptions(); +} diff --git a/src/main/java/one/kiosk/repository/MenuOptionRepositoryImpl.java b/src/main/java/one/kiosk/repository/MenuOptionRepositoryImpl.java new file mode 100644 index 0000000..f604a3d --- /dev/null +++ b/src/main/java/one/kiosk/repository/MenuOptionRepositoryImpl.java @@ -0,0 +1,22 @@ +package one.kiosk.repository; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import one.kiosk.dto.MenuOptionReturnDto; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public class MenuOptionRepositoryImpl implements MenuOptionRepositoryCustom{ + + @PersistenceContext + private EntityManager em; + + //쿼리문 실행하여 리스트에 한꺼번에 담기 + @Override + public List findMenuOptions() { + String jpql = "SELECT new one.kiosk.dto.MenuOptionReturnDto(m.optionname, m.price) FROM MenuOptionEntity m"; + return em.createQuery(jpql, MenuOptionReturnDto.class).getResultList(); + } +} diff --git a/src/main/java/one/kiosk/repository/QuerydslConfig.java b/src/main/java/one/kiosk/repository/QuerydslConfig.java new file mode 100644 index 0000000..413d8a0 --- /dev/null +++ b/src/main/java/one/kiosk/repository/QuerydslConfig.java @@ -0,0 +1,21 @@ +package one.kiosk.repository; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class QuerydslConfig { + + @PersistenceContext + private EntityManager entityManager; + + //JPAQueryFactory 스프링 빈 등록 + @Bean + public JPAQueryFactory jpaQueryFactory() { + return new JPAQueryFactory(entityManager); + } +} + diff --git a/src/main/java/one/kiosk/service/MemberService.java b/src/main/java/one/kiosk/service/MemberService.java index 7839665..01983eb 100644 --- a/src/main/java/one/kiosk/service/MemberService.java +++ b/src/main/java/one/kiosk/service/MemberService.java @@ -46,6 +46,6 @@ public String login(RequestLoginDto loginRequest) { } // 인증 성공 시 사용자 정보 반환 - return jwtUtil.createJwt(findMember.getUsername(), findMember.getCompany(), findMember.getRole().name()); + return jwtUtil.createJwt(findMember.getId(), findMember.getUsername(), findMember.getCompany(), findMember.getRole().name()); } } diff --git a/src/main/java/one/kiosk/service/MenuService.java b/src/main/java/one/kiosk/service/MenuService.java new file mode 100644 index 0000000..80e1c97 --- /dev/null +++ b/src/main/java/one/kiosk/service/MenuService.java @@ -0,0 +1,144 @@ +package one.kiosk.service; + + +import lombok.RequiredArgsConstructor; +import one.kiosk.dto.MenuOptionReturnDto; +import one.kiosk.dto.MenuReturnDto; +import one.kiosk.dto.MenuUpdateDto; +import one.kiosk.dto.MenuUploadDto; +import one.kiosk.entity.Image; +import one.kiosk.entity.MenuEntity; +import one.kiosk.entity.MenuOptionEntity; +import one.kiosk.exception.GlobalExceptionHandler; +import one.kiosk.jwt.JWTUtil; +import one.kiosk.repository.ImageRepository; +import one.kiosk.repository.MenuJpaRepository; +import one.kiosk.repository.MenuOptionRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import java.nio.file.AccessDeniedException; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class MenuService { + + private final MenuJpaRepository menuJpaRepository; + private final JWTUtil jwtUtil; + private static final Logger logger = LoggerFactory.getLogger(MenuService.class); // Logger 생성 + private final ImageRepository imageRepository; + private final MenuOptionRepository menuOptionRepository; + //메뉴 등록 + public MenuEntity upload(MenuUploadDto menuUploadDto, String token) { + + //토큰에서 유저 id 추출 후 메뉴 entity에 저장 + Long adminId = jwtUtil.getId(token); + + menuUploadDto.setAdminId(adminId); + MenuEntity menuEntity = menuJpaRepository.save(menuUploadDto.toMenuEntity()); + //메뉴 등록 진행 중, 오류가 발생하면 throw error + try{ + return menuEntity; + } + catch(Exception e){ + throw new GlobalExceptionHandler.MenuUplaodException("메뉴 등록에 실패하였습니다"); + } + } + + //메뉴 검색. dto변환 필요 + public MenuReturnDto find(Long id,String token) { + Long adminId = jwtUtil.getId(token); + + Optional OpmenuEntity = menuJpaRepository.findById(id); + + if(OpmenuEntity.isPresent()){ + MenuEntity menuEntity = OpmenuEntity.get(); + + if(!menuEntity.getAdminId().equals(adminId)){ + throw new GlobalExceptionHandler.UserUnmatchException("해당 메뉴에 접근 권한이 없습니다."); + } + List menuOptionReturnDtos = menuOptionRepository.findMenuOptions(); + //메뉴 테이블에 저장된 메뉴 아이디를 이용하여 메뉴 url 조회 + String imgUrl = null; + if(menuEntity.getImageId() != null){ + Optional Opimage = imageRepository.findById(menuEntity.getImageId().getId()); + if(Opimage.isPresent()){ + imgUrl = Opimage.get().getImageUrl(); + } + } + + + return MenuReturnDto.toMenuReturnDto(menuEntity,imgUrl,menuOptionReturnDtos); + } + return null; + } + + //메뉴 수정. 성공시 true, 실패시 throw error + public void update(MenuUpdateDto menuUpdateDto, String token) { + Long adminId = jwtUtil.getId(token); + + Optional OpMenuEntity = Optional.ofNullable(menuJpaRepository.findByMenuId(menuUpdateDto.getId())); + + if (OpMenuEntity.isPresent()) { + // optional에서 entity값 추출 + MenuEntity menuEntity = OpMenuEntity.get(); + + //findByMenuId를 통해 찾은 menuEntity의 menuId과 토큰에서 추출한 adminId를 비교. 일치하지 않으면 에러 throw + if(!menuEntity.getAdminId().equals(adminId)) { + throw new GlobalExceptionHandler.UserUnmatchException("해당 메뉴에 접근 권한이 없습니다."); + } + + menuEntity.setMenuname(menuUpdateDto.getMenuname()); + menuEntity.setPrice(menuUpdateDto.getPrice()); + menuEntity.setCategory(menuUpdateDto.getCategory()); + menuEntity.setUpdate(LocalDateTime.now()); + menuEntity.setImageId(menuEntity.getImageId()); + + menuJpaRepository.save(menuEntity); + + } else { + //에러 발생시 throw + throw new GlobalExceptionHandler.MenuUpdateException("메뉴를 수정하지 못했습니다"); + } + } + + //메뉴 삭제. 실패시 throw error + public void delete(Long id, String token) { + Long adminId = jwtUtil.getId(token); + Optional OpMenuEntity = menuJpaRepository.findById(id); + + if(OpMenuEntity.isPresent()){ + MenuEntity menuEntity = OpMenuEntity.get(); + + //findByMenuId를 통해 찾은 menuEntity의 menuId과 토큰에서 추출한 adminId를 비교. 일치하지 않으면 에러 throw + if(!menuEntity.getAdminId().equals(adminId)) { + throw new GlobalExceptionHandler.UserUnmatchException("해당 메뉴에 접근 권한이 없습니다."); + } + menuJpaRepository.delete(menuEntity); + } + else{ + throw new GlobalExceptionHandler.MenuDeleteException("메뉴를 삭제하지 못했습니다."); + } + } + + //전체조회 + public List findAll(String token) { + Long adminId = jwtUtil.getId(token); + + + List menuReturnDtos = menuJpaRepository.findAllMenuWithOptionsByAdminId(adminId); + + if (menuReturnDtos.isEmpty()) { + throw new GlobalExceptionHandler.MenuNotExistException("등록된 메뉴가 없습니다"); + } + return menuReturnDtos; + + } + + + +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 3f84289..b143139 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -29,4 +29,4 @@ spring: max-request-size: 10MB server: - port: 8022 + port: 8022 \ No newline at end of file