@ModelAttribute란?
Spring MVC에서 HTTP 요청 데이터를 컨트롤러 메서드의 파라미터나 모델에 바인딩하기 위해 사용되는 어노테이션이다.
이번프로젝트에서 ModelAttribute를 사용한 이유는 아래 코드와 같이 전체 조회 시에 서치 옵션에 따라서 조회의 결과가 달라지는 경우 아래와 같이 어마어마한 양의 RequestParam을 볼 수 있다. 이는 코드의 가독성을 떨어트릴 뿐만 아니라 실제로 코드 작성 시 실수를 할 가능성이 너무 많아진다.
@PreAuthorize("hasAnyRole('CUSTOMER')")
@GetMapping("/orders")
public ResponseEntity<CommonResponse<Page<OrderResponse>>> getAllOrdersCustomer(
Pageable pageable,
@AuthenticationPrincipal UserDetailsImpl userDetails,
@RequestParam(required = false) String storeName,
@RequestParam(required = false) UUID categoryId,
@RequestParam(value = "orderType", required = false) OrderType orderType,
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate,
@RequestParam(value = "orderStatus", required = false) OrderStatus orderStatus,
@RequestParam(value = "sortOption", required = false, defaultValue = "CREATED_AT_ASC") SortOption sortOption
@Valid @ModelAttribute OrderSearchCustomerRequest orderSearchCustomerRequest
) {
return CommonResponse.success(SuccessCode.SUCCESS,
orderService.getOrdersCustomer(
pageable,
userDetails.getUser(),
storeName,
categoryId,
orderType,
startDate,
endDate,
orderStatus,
sortOption
orderSearchCustomerRequest
));
}
따라서 @ModelAttribute를 사용하여 Dto를 생성하여 정리하면 이렇게나 깔끔해진다. 아래의 DTO를 본다면 궁금증이 생길 수 있다. 그러면 RequestParam에서 사용하던 옵션을 사용을 안해도 되는 건가?
정답은 Yes다
이유는 맨 위에 작성한 ModelAttribute의 목적에 있다.
"컨트롤러 메서드의 파라미터나 모델에 바인딩하기 위해 사용되는 어노테이션"
즉 요청 파라미터의 이름과 객체의 필드 이름이 일치한다면 자동으로 매핑이 되기 때문에 요청이 없는 필드는 null이나 기본값으로 설정된다.
@PreAuthorize("hasAnyRole('CUSTOMER')")
@GetMapping("/orders")
public ResponseEntity<CommonResponse<Page<OrderResponse>>> getAllOrdersCustomer(
Pageable pageable,
@AuthenticationPrincipal UserDetailsImpl userDetails,
@Valid @ModelAttribute OrderSearchCustomerRequest orderSearchCustomerRequest
) {
return CommonResponse.success(SuccessCode.SUCCESS,
orderService.getOrdersCustomer(
pageable,
userDetails.getUser(),
orderSearchCustomerRequest
));
}
만약 내가 null 말고 defaultValue 값이 필요하다면 아래의 예시처럼 생성자를 통해 기본값을 설정할 수 있다.
public record OrderSearchCustomerRequest(
@Size(max = 50, message = "매장명은 50자 이내로 작성해 주세요")
String storeName,
UUID categoryId,
OrderType orderType,
LocalDate startDate,
LocalDate endDate,
OrderStatus orderStatus,
SortOption sortOption
) {
public OrderSearchCustomerRequest(
String storeName,
UUID categoryId,
OrderType orderType,
LocalDate startDate,
LocalDate endDate,
OrderStatus orderStatus,
SortOption sortOption
) {
this.storeName = storeName;
this.categoryId = categoryId;
this.orderType = orderType;
this.startDate = startDate;
this.endDate = endDate;
this.orderStatus = orderStatus;
this.sortOption = sortOption != null ? sortOption : SortOption.CREATED_AT_ASC;
}
}
'심화 캠프 정리' 카테고리의 다른 글
RestTemplate vs FeignClient (1) | 2024.11.20 |
---|---|
PageableArgumentResolver (0) | 2024.11.20 |
동적쿼리 BooleanExpression (1) | 2024.11.20 |
동적쿼리 OrderSpecifier (0) | 2024.11.20 |
PreAuthorize (3) | 2024.11.19 |