Skip to content

Commit

Permalink
orderForm 유효성 검사 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
daadaadaah committed Jun 7, 2023
1 parent 7676d9e commit abbf282
Show file tree
Hide file tree
Showing 12 changed files with 210 additions and 248 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ repositories {
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'mysql:mysql-connector-java:8.0.22'
implementation 'org.flywaydb:flyway-core'
implementation 'org.flywaydb:flyway-mysql'
Expand Down
34 changes: 20 additions & 14 deletions src/main/java/com/hcommerce/heecommerce/order/OrderController.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
package com.hcommerce.heecommerce.order;

import com.hcommerce.heecommerce.common.dto.ResponseDto;
import jakarta.validation.Valid;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class OrderController {

@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.addValidators(new OrderFormValidator());
}

private final OrderService orderService;

@Autowired
Expand All @@ -30,29 +38,27 @@ public ResponseDto completeOrderReceipt(@PathVariable("orderUuid") UUID orderUui
return ResponseDto.builder()
.code(HttpStatus.OK.name())
.message("주문 접수 완료가 처리되었습니다.")
.data(null)
.build();
}

@PostMapping("/orders")
public ResponseEntity placeOrder(@RequestBody OrderForm orderForm) {
@ResponseStatus(HttpStatus.CREATED)
public ResponseDto placeOrder(@Valid @RequestBody OrderForm orderForm) {
/**
* 예상 예외 상황
* - 로그인 유저의 요청이 아닌 경우 UNAUTHORIZED 예외
* - OrderForm 유효성 검사에 어긋난 경우 -> 유효성 공부 후 결정하기
* - OrderForm 유효성 검사에 어긋난 경우 : 최대 주문 수량보다 많이 주문한 경우에 대한 DB 처리 필요
* - userId 가 DB에 없는 경우 NOT FOUND 예외
* - dealProductUuid 가 DB에 없는 경우 NOT FOUND 예외
* - ProductUuid 가 DB에 없는 경우 NOT FOUND 예외
* - 결제 실패로 주문이 불가능한 경우 예외 -> 이 경우는 HTTP 상태코드 몇번으로 해야하는
* - 재고 부족으로 주문이 불가능한 경우 409 error 예외
* - 결제 실패로 주문이 불가능한 경우 예외 -> 결제 API 검토 후 생각해보기(참고 : https://stackoverflow.com/questions/60112667/what-http-code-response-to-use-when-payment-fails)
* - 재고 부족으로 주문이 불가능한 경우 409 error 예외 : 재고가 0이어서 불가능한 경우가 있을 수 있고, 재고는 2개인데, 주문량이 3개여서 주문이 불가능한 경우도 있을 수 있는데, 이 경우는 어떻게 처리할 것인가?
*/

// 주문 데이터를 Local Cache로 사용할 수 있도록 클라이언트에게 내려주는 것도 괜찮을 것 같음
// TODO : ResponseDto 확정되면 수정하기
ResponseDto responseDto = ResponseDto.builder()
.code(HttpStatus.CREATED.name())
.message("주문 접수가 완료되었습니다.")
.build();

return new ResponseEntity(responseDto, HttpStatus.CREATED);
return ResponseDto.builder()
.code(HttpStatus.CREATED.name())
.message("주문 접수가 완료되었습니다.")
.data(null)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.hcommerce.heecommerce.common.dto.ResponseDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
Expand All @@ -29,9 +30,19 @@ public ResponseDto orderOverStockExceptionExceptionHandler(OrderOverStockExcepti
.build();
}

@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler
public ResponseDto methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
return ResponseDto.builder()
.code(HttpStatus.BAD_REQUEST.name())
.message(e.getBindingResult().getAllErrors().get(0).getDefaultMessage())
.build();
}

@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler
public ResponseDto fallbackExceptionHandler(Exception e) {
log.error("[{}] message = {} ", e.getClass(), e.getMessage());
return ResponseDto.builder()
.code(HttpStatus.INTERNAL_SERVER_ERROR.name())
.message("내부 서버 오류가 발생했습니다.")
Expand Down
49 changes: 36 additions & 13 deletions src/main/java/com/hcommerce/heecommerce/order/OrderForm.java
Original file line number Diff line number Diff line change
@@ -1,29 +1,52 @@
package com.hcommerce.heecommerce.order;

import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import java.beans.ConstructorProperties;
import java.util.UUID;
import lombok.Builder;
import lombok.Getter;
import org.hibernate.validator.constraints.Range;

@Getter
public class OrderForm {

private OrdererInfo ordererInfo;
private RecipientInfo recipientInfo;
private PaymentInfo paymentInfo;
@Range(min = 1, message = "주문자 ID를 확인해주세요.")
private final int userId;

@Valid
@NotNull(message = "수령자 정보는 필수입니다.")
private RecipientInfoForm recipientInfoForm;

@NotNull(message = "딜 상품 UUID를 입력해주세요.")
private final UUID dealProductUuid;

@Min(value = 1, message = "주문 수량은 1개 이상이어야 합니다.")
private final int orderQuantity;

@NotNull(message = "결제 유형을 입력해주세요.")
private final PaymentType paymentType;

@Builder
@ConstructorProperties({
"ordererInfo",
"recipientInfo",
"paymentInfo"}
)
"userId",
"recipientInfoForm",
"dealProductUuid",
"orderQuantity",
"paymentType"
})
public OrderForm(
OrdererInfo ordererInfo,
RecipientInfo recipientInfo,
PaymentInfo paymentInfo
int userId,
RecipientInfoForm recipientInfoForm,
UUID dealProductUuid,
int orderQuantity,
PaymentType paymentType
) {
this.ordererInfo = ordererInfo;
this.recipientInfo = recipientInfo;
this.paymentInfo = paymentInfo;
this.userId = userId;
this.recipientInfoForm = recipientInfoForm;
this.dealProductUuid = dealProductUuid;
this.orderQuantity = orderQuantity;
this.paymentType = paymentType;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.hcommerce.heecommerce.order;

import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;

@Component
public class OrderFormValidator implements Validator {

@Override
public boolean supports(Class<?> clazz) {
return OrderForm.class.equals(clazz);
}

@Override
public void validate(Object target, Errors errors) {
OrderForm orderForm = (OrderForm) target;

int MAX_ORDER_QUANTITY_PER_ORDER = 10; // TODO: 딜 상품마다 최대 주문량을 다른 값을 갖도록 상황을 가정했으므로, DB에서 가져올 예정
// (참고: https://github.com/f-lab-edu/home-delivery/blob/b78ba80d38dd6e1e59554ebea59343a52d770e1d/src/main/java/com/flab/delivery/controller/validator/OrderValidator.java#L1)

if (orderForm.getOrderQuantity() > MAX_ORDER_QUANTITY_PER_ORDER) {
errors.rejectValue("orderQuantity", "orderQuantity.invalid", "최대 주문 수량은 " + MAX_ORDER_QUANTITY_PER_ORDER + "개 입니다.");
}
}
}
20 changes: 0 additions & 20 deletions src/main/java/com/hcommerce/heecommerce/order/OrdererInfo.java

This file was deleted.

61 changes: 0 additions & 61 deletions src/main/java/com/hcommerce/heecommerce/order/PaymentInfo.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
package com.hcommerce.heecommerce.order;

import jakarta.validation.constraints.NotNull;
import java.beans.ConstructorProperties;
import lombok.Builder;
import lombok.Getter;

@Getter
class RecipientInfo {
class RecipientInfoForm {

@NotNull(message = "수령인 이름을 입력해주세요.")
private final String recipientName;

@NotNull(message = "수령인 전화번호를 입력해주세요.")
private final String recipientPhoneNumber;

@NotNull(message = "수령 주소를 입력해주세요.")
private final String recipientAddress;

private final String recipientDetailAddress;

private final String shippingRequest;

@Builder
Expand All @@ -18,9 +27,9 @@ class RecipientInfo {
"recipientPhoneNumber",
"recipientAddress",
"recipientDetailAddress",
"shippingRequest"}
)
public RecipientInfo(
"shippingRequest"
})
public RecipientInfoForm(
String recipientName,
String recipientPhoneNumber,
String recipientAddress,
Expand Down
Loading

0 comments on commit abbf282

Please sign in to comment.