From c013ffb165009137959b132de36654c0aaa3c1a8 Mon Sep 17 00:00:00 2001 From: junho <2171168@hansung.ac.kr> Date: Sun, 7 Sep 2025 14:13:26 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=EB=82=B4=EA=B0=80=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=ED=95=9C=20=EC=83=81=ED=92=88=20=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ProductController.java | 22 +++++++++++----- .../products/converter/ProductConverter.java | 16 +++++++++--- .../response/ProductRegisterHistoryDto.java | 25 +++++++++++++++++++ .../repository/ProductRepository.java | 4 +++ .../products/service/ProductService.java | 15 ++++++++--- .../config/CurrentUserArgumentResolver.java | 19 ++++++-------- 6 files changed, 75 insertions(+), 26 deletions(-) create mode 100644 src/main/java/com/DecodEat/domain/products/dto/response/ProductRegisterHistoryDto.java diff --git a/src/main/java/com/DecodEat/domain/products/controller/ProductController.java b/src/main/java/com/DecodEat/domain/products/controller/ProductController.java index fc0f8d2..1b68670 100644 --- a/src/main/java/com/DecodEat/domain/products/controller/ProductController.java +++ b/src/main/java/com/DecodEat/domain/products/controller/ProductController.java @@ -1,10 +1,7 @@ package com.DecodEat.domain.products.controller; -import com.DecodEat.domain.products.dto.response.ProductDetailDto; +import com.DecodEat.domain.products.dto.response.*; import com.DecodEat.domain.products.dto.request.ProductRegisterRequestDto; -import com.DecodEat.domain.products.dto.response.ProductRegisterResponseDto; -import com.DecodEat.domain.products.dto.response.ProductResponseDTO; -import com.DecodEat.domain.products.dto.response.ProductSearchResponseDto; import com.DecodEat.domain.products.entity.RawMaterial.RawMaterialCategory; import com.DecodEat.domain.products.service.ProductService; import com.DecodEat.domain.users.entity.User; @@ -44,7 +41,8 @@ public ApiResponse getProduct(@PathVariable Long id) { @Operation( summary = "제품 등록", description = "상품 이미지, 제품명, 회사명으로 상품을 등록합니다") - @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) //이 엔드포인트가 multipart/form-data 타입의 요청 본문을 소비(consume)한다는 것을 명확하게 선언 + @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + //이 엔드포인트가 multipart/form-data 타입의 요청 본문을 소비(consume)한다는 것을 명확하게 선언 public ApiResponse registerProduct( @CurrentUser User user, @RequestParam("name") String name, @@ -90,8 +88,20 @@ public ApiResponse> sea @RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "20") int size) { - Pageable pageable = PageRequest.of(page-1, size, Sort.by("productName").ascending()); // 0-based + Pageable pageable = PageRequest.of(page - 1, size, Sort.by("productName").ascending()); // 0-based return ApiResponse.onSuccess(productService.searchProducts(productName, categories, pageable)); } + @GetMapping("/register-history") + @Operation(summary = "나의 분석 요청 기록", description = "내가 등록한 상품의 분석 결과 목록입니다.") + public ApiResponse> getRegisterHistory(@CurrentUser User user, + @RequestParam(defaultValue = "1") int page, + @RequestParam(defaultValue = "20") int size) { + + Pageable pageable = PageRequest.of(page - 1, size, Sort.by("createdAt").descending()); // 0-based + + return ApiResponse.onSuccess(productService.getRegisterHistory(user, pageable)); + } + + } diff --git a/src/main/java/com/DecodEat/domain/products/converter/ProductConverter.java b/src/main/java/com/DecodEat/domain/products/converter/ProductConverter.java index a19683d..e729b75 100644 --- a/src/main/java/com/DecodEat/domain/products/converter/ProductConverter.java +++ b/src/main/java/com/DecodEat/domain/products/converter/ProductConverter.java @@ -1,9 +1,7 @@ package com.DecodEat.domain.products.converter; -import com.DecodEat.domain.products.dto.response.ProductDetailDto; -import com.DecodEat.domain.products.dto.response.ProductRegisterResponseDto; -import com.DecodEat.domain.products.dto.response.ProductResponseDTO; -import com.DecodEat.domain.products.dto.response.ProductSearchResponseDto; +import com.DecodEat.domain.products.dto.request.ProductRegisterRequestDto; +import com.DecodEat.domain.products.dto.response.*; import com.DecodEat.domain.products.entity.Product; import com.DecodEat.domain.products.entity.ProductNutrition; import com.DecodEat.domain.products.entity.RawMaterial.RawMaterialCategory; @@ -94,6 +92,16 @@ public static ProductSearchResponseDto.ProductPrevDto toProductPrevDto(Product p .build(); } + public static ProductRegisterHistoryDto toProductRegisterHistoryDto(Product product){ + return ProductRegisterHistoryDto.builder() + .productId(product.getProductId()) + .registerDate(product.getCreatedAt()) + .productImage(product.getProductImage()) + .decodeStatus(product.getDecodeStatus()) + .build(); + } + + // Slice → ProductListResultDTO 변환 public static ProductResponseDTO.ProductListResultDTO toProductListResultDTO(Slice slice) { List productList = slice.getContent().stream() diff --git a/src/main/java/com/DecodEat/domain/products/dto/response/ProductRegisterHistoryDto.java b/src/main/java/com/DecodEat/domain/products/dto/response/ProductRegisterHistoryDto.java new file mode 100644 index 0000000..83b0db2 --- /dev/null +++ b/src/main/java/com/DecodEat/domain/products/dto/response/ProductRegisterHistoryDto.java @@ -0,0 +1,25 @@ +package com.DecodEat.domain.products.dto.response; + +import com.DecodEat.domain.products.entity.DecodeStatus; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Getter; + +import java.time.LocalDateTime; + +@Getter +@Builder +public class ProductRegisterHistoryDto { + + @Schema(description = "상품 ID", example = "1") + private Long productId; + + @Schema(description = "상품 등록일", example = "2025-09-05") + private LocalDateTime registerDate; + + @Schema(description = "상품 이미지", example = "https://example.com/image.jpg") + private String productImage; + + @Schema(description = "뷴석 상태", example = "COMPLETED") + private DecodeStatus decodeStatus; +} diff --git a/src/main/java/com/DecodEat/domain/products/repository/ProductRepository.java b/src/main/java/com/DecodEat/domain/products/repository/ProductRepository.java index ee011bc..7916869 100644 --- a/src/main/java/com/DecodEat/domain/products/repository/ProductRepository.java +++ b/src/main/java/com/DecodEat/domain/products/repository/ProductRepository.java @@ -2,6 +2,8 @@ import com.DecodEat.domain.products.entity.DecodeStatus; import com.DecodEat.domain.products.entity.Product; +import com.DecodEat.domain.users.entity.User; +import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; import org.springframework.data.jpa.repository.JpaRepository; @@ -22,4 +24,6 @@ Slice findCompletedProductsByCursor(@Param("cursorId") Long cursorId, Pageable pageable); void deleteByDecodeStatusIn(List statuses); + + Page findByUserId(Long userId, Pageable pageable); } diff --git a/src/main/java/com/DecodEat/domain/products/service/ProductService.java b/src/main/java/com/DecodEat/domain/products/service/ProductService.java index c9f542d..9f89f3b 100644 --- a/src/main/java/com/DecodEat/domain/products/service/ProductService.java +++ b/src/main/java/com/DecodEat/domain/products/service/ProductService.java @@ -2,10 +2,7 @@ import com.DecodEat.domain.products.converter.ProductConverter; import com.DecodEat.domain.products.dto.request.ProductRegisterRequestDto; -import com.DecodEat.domain.products.dto.response.ProductDetailDto; -import com.DecodEat.domain.products.dto.response.ProductRegisterResponseDto; -import com.DecodEat.domain.products.dto.response.ProductResponseDTO; -import com.DecodEat.domain.products.dto.response.ProductSearchResponseDto; +import com.DecodEat.domain.products.dto.response.*; import com.DecodEat.domain.products.entity.DecodeStatus; import com.DecodEat.domain.products.entity.Product; import com.DecodEat.domain.products.entity.ProductInfoImage; @@ -145,4 +142,14 @@ public PageResponseDto searchProducts(S return new PageResponseDto<>(result); } + + public PageResponseDto getRegisterHistory(User user, Pageable pageable){ + + Long userId = user.getId(); + + Page pagedProducts = productRepository.findByUserId(userId, pageable); + Page result = pagedProducts.map(ProductConverter::toProductRegisterHistoryDto); + + return new PageResponseDto<>(result); + } } \ No newline at end of file diff --git a/src/main/java/com/DecodEat/global/config/CurrentUserArgumentResolver.java b/src/main/java/com/DecodEat/global/config/CurrentUserArgumentResolver.java index 059fe2c..b0f1ff7 100644 --- a/src/main/java/com/DecodEat/global/config/CurrentUserArgumentResolver.java +++ b/src/main/java/com/DecodEat/global/config/CurrentUserArgumentResolver.java @@ -21,24 +21,19 @@ public class CurrentUserArgumentResolver implements HandlerMethodArgumentResolve @Override public boolean supportsParameter(org.springframework.core.MethodParameter parameter) { return parameter.getParameterAnnotation(CurrentUser.class) != null - && parameter.getParameterType().equals(com.DecodEat.domain.users.entity.User.class); + && parameter.getParameterType().equals(com.DecodEat.domain.users.entity.User.class); } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { - try { - Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - if (principal instanceof org.springframework.security.core.userdetails.User) { - org.springframework.security.core.userdetails.User springUser = (org.springframework.security.core.userdetails.User) principal; - Long userId = Long.valueOf(springUser.getUsername()); - return userService.findById(userId); // userId로 User 엔티티를 찾아 반환 - } - } catch (Exception e) { - // 예외 처리, 인증되지 않은 사용자의 경우 null 또는 예외를 던질 수 있습니다. - throw new GeneralException(ErrorStatus._UNAUTHORIZED); + Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + + if (principal instanceof org.springframework.security.core.userdetails.User springUser) { + Long userId = Long.valueOf(springUser.getUsername()); + return userService.findById(userId); // userId로 User 엔티티를 찾아 반환 } - return null; + throw new GeneralException(ErrorStatus._UNAUTHORIZED); } } From 36efbca821e953a41f3d7698e1fc41c2f5ef67c4 Mon Sep 17 00:00:00 2001 From: junho <2171168@hansung.ac.kr> Date: Sun, 7 Sep 2025 14:15:29 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=EB=93=B1=EB=A1=9D=EC=9D=BC=20?= =?UTF-8?q?=ED=8F=AC=EB=A7=A4=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../products/dto/response/ProductRegisterHistoryDto.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/DecodEat/domain/products/dto/response/ProductRegisterHistoryDto.java b/src/main/java/com/DecodEat/domain/products/dto/response/ProductRegisterHistoryDto.java index 83b0db2..b82bc9d 100644 --- a/src/main/java/com/DecodEat/domain/products/dto/response/ProductRegisterHistoryDto.java +++ b/src/main/java/com/DecodEat/domain/products/dto/response/ProductRegisterHistoryDto.java @@ -1,6 +1,7 @@ package com.DecodEat.domain.products.dto.response; import com.DecodEat.domain.products.entity.DecodeStatus; +import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; import lombok.Getter; @@ -15,11 +16,12 @@ public class ProductRegisterHistoryDto { private Long productId; @Schema(description = "상품 등록일", example = "2025-09-05") + @JsonFormat(pattern = "yyyy-MM-dd") private LocalDateTime registerDate; @Schema(description = "상품 이미지", example = "https://example.com/image.jpg") private String productImage; - @Schema(description = "뷴석 상태", example = "COMPLETED") + @Schema(description = "분석 상태", example = "COMPLETED") private DecodeStatus decodeStatus; }