-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[feat][#5] 상품 및 카테고리 관련 API 구현 #7
base: develop
Are you sure you want to change the base?
Conversation
279d030
to
6010918
Compare
6010918
to
c478131
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
확인하였습니다.
작성하신 로직이 제가 이해한 것이 맞다면 큰 이견은 없습니다만 예외처리를 위한 구간은 많은 것 같아요. 서비스 중요 로직이 아니라면 null 값이 아예 안들어오게 만드는 경우가 가장 좋지 않을까 싶어요.
src/main/java/com/flab/ecommerce/domain/category/controller/CategoryController.java
Show resolved
Hide resolved
src/main/java/com/flab/ecommerce/domain/category/dto/CategoryResponseDTO.java
Show resolved
Hide resolved
src/main/java/com/flab/ecommerce/domain/category/controller/CategoryController.java
Show resolved
Hide resolved
if (requestDTO.getName() != null && !requestDTO.getName().equals(category.getName())) { | ||
if(categoryRepository.existsByNameAndIdNot(requestDTO.getName(), id)) { | ||
throw new CategoryAlreadyExistsException(); | ||
} | ||
category.updateName(requestDTO.getName()); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
빈 string 에 대한 검사가 불가능 한 것 같아요. 위 CategoryUpdateRequestDTO
에도 @NotBlank
가 안걸려 있어서요.
String 의 null 값과 빈값을 동시 검출할 수 있는 StringUtils 에 isNotBlank
를 쓰시는건 어떨까요?
https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html#isNotBlank(java.lang.CharSequence)
if (requestDTO.getName() != null && !requestDTO.getName().isEmpty()) { | ||
this.name = requestDTO.getName(); | ||
} | ||
if (requestDTO.getDescription() != null && !requestDTO.getDescription().isEmpty()) { | ||
this.description = requestDTO.getDescription(); | ||
} | ||
if (requestDTO.getPrice() != null) { | ||
this.price = requestDTO.getPrice(); | ||
} | ||
if (requestDTO.getStockQuantity() > 0) { | ||
this.stockQuantity = requestDTO.getStockQuantity(); | ||
} | ||
if (requestDTO.getImageUrl() != null && !requestDTO.getImageUrl().isEmpty()) { | ||
this.imageUrl = requestDTO.getImageUrl(); | ||
} | ||
if (newCategory != null) { | ||
this.category = newCategory; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
product 에서 바꾸고 싶지 않은 필드값은 ProductUpdateRequestDTO
의 필드에 null 값을 주입해서 주기 위한, 일종의 편의성을 위한 로직인걸까요?
@Transactional | ||
public ProductDetailResponseDTO updateProduct(long id, ProductUpdateRequestDTO requestDTO) { | ||
Product product = productRepository.findById(id) | ||
.orElseThrow(() -> new ProductNotFoundException(id)); | ||
|
||
Category category = requestDTO.getCategoryId() == null | ||
? product.getCategory() | ||
: categoryRepository.findById(requestDTO.getCategoryId()) | ||
.orElseThrow(CategoryNotFoundException::new); | ||
|
||
product.update(requestDTO, category); | ||
return new ProductDetailResponseDTO(product); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
생각보다 탈출구가 많은 로직인 것 같아요. requestDTO 에 category 가 null 값일때를 가정하신 이유도 있나요? category를 변경하고 싶지 않을 때 requestDTO 에 null 값을 넣는다고 가정하신건가요?
@ExceptionHandler(MethodArgumentNotValidException.class) | ||
public ResponseEntity<ErrorResponse> handleValidationException(MethodArgumentNotValidException ex) { | ||
String errorMessage = ex.getBindingResult().getFieldErrors().stream() | ||
.map(error -> error.getField() + ": " + error.getDefaultMessage()) | ||
.collect(Collectors.joining(", ")); | ||
|
||
return ResponseEntity.status(ex.getStatus()) | ||
.body(new ErrorResponse(ex.getStatus().value(), ex.getMessage(), ex.getErrorCode())); | ||
return ResponseEntity.status(HttpStatus.BAD_REQUEST) | ||
.body(new ErrorResponse(HttpStatus.BAD_REQUEST.value(), errorMessage, "VALIDATION_FAILED")); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍👍👍
@Getter | ||
public class ApiResponse<T> { | ||
private final int status; | ||
private final String message; | ||
private final T data; | ||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") | ||
private final LocalDateTime timestamp; | ||
|
||
public ApiResponse(int status, String message, T data) { | ||
this.status = status; | ||
this.message = message; | ||
this.data = data; | ||
this.timestamp = LocalDateTime.now(); | ||
} | ||
|
||
public static <T> ApiResponse<T> success(T data) { | ||
return new ApiResponse<>(200, "Success", data); | ||
} | ||
|
||
public static <T> ApiResponse<T> created(T data) { | ||
return new ApiResponse<>(201, "Created", data); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍👍👍👍👍👍
|
관련 이슈
resolve : #5
작업 내용
사용자 + 관리자 공통 API (상품)
GET /products
→ 상품 목록 조회GET /products/{id}
→ 상품 상세 조회관리자 전용 API (상품)
POST /products
→ 상품 등록PUT /products/{id}
→ 상품 수정DELETE /products/{id}
→ 상품 삭제사용자 + 관리자 공통 API (카테고리)
GET /�categories/active
→ 활성화된 카테고리 목록 조회관리자 전용 API (카테고리)
GET /�categories
→ 모든 카테고리 목록 조회GET /{id}/�sub-categories
→ 세부 카테고리 조회POST /�categories
→ 카테고리 등록PATCH /�categories/{id}
→ 카테고리 수정PATCH /categories/{id}/activate
→ 카테고리 활성화PATCH /categories/{id}/deactivate
→ 카테고리 비활성화테스트 방법
1. 로그인 성공 화면
2. 관리자 API에 접근했을 경우
3. 일반 사용자 API 접근했을 경우
참고 사항
기존 문제
개선 포인트