-
[스프링MVC - 2편] 검증 (4)스프링&스프링부트 2025. 3. 2. 16:03
Form 전송 객체 분리
실무에서는 groups를 잘 사용하지 않는데 등록시 폼에서 전달하는 데이터가 Item 도메인 객체와 딱 맞지 않기 때문이다
그래서 보통 Item을 직접 전달받는 것이 아니라, 복잡한 폼의 데이터를 컨트롤러까지 전달할 별도의 객체를 만들어서 전달한다
- 폼 데이터 전달에 Item 도메인 객체 사용
- HTML Form -> Item -> Controller -> Item -> Repository
- 장점: Item 도메인 객체를 컨트롤러, 리포지토리 까지 직접 전달해서 중간에 Item을 만드는 과정이 없어서 간단하다
- 단점: 간단한 경우에만 적용할 수 있다 수정시 검증이 중복될 수 있고, groups를 사용해야 한다
- 폼 데이터 전달을 위한 별도의 객체 사용
- HTML Form -> ItemSaveForm -> Controller -> Item 생성 -> Repository
- 장점: 전송하는 폼 데이터가 복잡해도 거기에 맞춘 별도의 폼 객체를 사용해서 데이터를 전달 받을 수 있다
- 단점: 폼 데이터를 기반으로 컨트롤러에서 Item 객체를 생성하는 변환 과정이 추가된다
ITEM
@Data public class Item { private Long id; private String itemName; private Integer price; private Integer quantity; }
ItemSaveForm - ITEM 저장용 폼
@Data public class ItemSaveForm { @NotBlank private String itemName; @NotNull @Range(min = 1000, max = 1000000) private Integer price; @NotNull @Max(value = 9999) private Integer quantity; }
**ItemUpdateForm - ITEM 수정용 폼**
@Data public class ItemUpdateForm { @NotNull private Long id; @NotBlank private String itemName; @NotNull @Range(min = 1000, max = 1000000) private Integer price; // 수정에서는 수량은 자유롭게 변경할 수 있다. private Integer quantity; }
ValidationItemControllerV4 수정
@Slf4j @Controller @RequestMapping("/validation/v4/items") @RequiredArgsConstructor public class ValidationItemControllerV4 { ... @PostMapping("/add") public String addItem(@Validated @ModelAttribute("item") ItemSaveForm form, BindingResult bindingResult, RedirectAttributes redirectAttributes) { if (form.getPrice() != null && form.getQuantity() != null) { int resultPrice = form.getPrice() * form.getQuantity(); if (resultPrice < 10000) { bindingResult.reject("totalPriceMin", new Object[]{10000, resultPrice}, null); } } if (bindingResult.hasErrors()) { log.info("errors={}", bindingResult); return "validation/v4/addForm"; } // 성공 로직 Item item = new Item(); item.setItemName(form.getItemName()); item.setPrice(form.getPrice()); item.setQuantity(form.getQuantity()); Item savedItem = itemRepository.save(item); redirectAttributes.addAttribute("itemId", savedItem.getId()); redirectAttributes.addAttribute("status", true); return "redirect:/validation/v4/items/{itemId}"; } ... @PostMapping("/{itemId}/edit") public String edit(@PathVariable Long itemId, @Validated @ModelAttribute("item") ItemUpdateForm form, BindingResult bindingResult) { if (form.getPrice() != null && form.getQuantity() != null) { int resultPrice = form.getPrice() * form.getQuantity(); if (resultPrice < 10000) { bindingResult.reject("totalPriceMin", new Object[]{10000, resultPrice}, null); } } if (bindingResult.hasErrors()) { log.info("errors={}", bindingResult); return "validation/v4/editForm"; } Item itemParam = new Item(); itemParam.setItemName(form.getItemName()); itemParam.setPrice(form.getPrice()); itemParam.setQuantity(form.getQuantity()); itemRepository.update(itemId, itemParam); return "redirect:/validation/v4/items/{itemId}"; } ... }
Bean Validation - HTTP 메시지 컨버터
- @ModelAttribute는 HTTP 요청 파라미터(URL 쿼리 스트링, POST Form)를 다룰 때 사용한다
- @RequestBody는 HTTP Body의 데이터를 객체로 변환할 때 사용한다. 주로 API JSON 요청을 다룰 때 사용한다
ValidationItemApiController 생성
@Slf4j @RestController @RequestMapping("/validation/api/items") public class ValidationItemApiController { @PostMapping("/add") public Object addItem(@RequestBody @Validated ItemSaveForm form, BindingResult bindingResult) { log.info("API 컨트롤러 호출"); if (bindingResult.hasErrors()) { log.info("검증 오류 발생 errors={}", bindingResult); return bindingResult.getAllErrors(); } log.info("성공 로직 실행"); return form; } }
API의 경우 3가지 경우를 나누어 생각
- 성공 요청: 성공
- 실패 요청: JSON을 객체로 생성하는 것 자체가 실패함
- 검증 오류 요청: JSON을 객체로 생성하는 것은 성공했고, 검증에서 실패함
@ModelAttribute vs @RequestBody
- @ModelAttribute는 필드 단위로 정교하게 바인딩이 적용된다 특정 필드가 바인딩 되지 않아도 나머지 필드는 정상 바인딩 되고, Validator를 사용한 검증도 적용할 수 있다
- @RequestBody는 HttpMessageConverter 단계에서 JSON 데이터를 객체로 변경하지 못하면 이후 단계 자체가 진행되지 않고 예외가 발생한다 컨트롤러도 호출되지 않고 Validator도 적용할 수 없다
728x90'스프링&스프링부트' 카테고리의 다른 글
[스프링MVC - 2편] 로그인 처리1 - 쿠키, 세션 (0) 2025.03.04 [스프링MVC - 2편] 검증 (3) (1) 2025.03.02 [스프링MVC - 2편] 검증 (2) (0) 2025.02.09 [스프링MVC - 2편] 검증 (1) (0) 2025.02.08 [스프링MVC - 2편] 메시지, 국제화 (0) 2025.02.04 - 폼 데이터 전달에 Item 도메인 객체 사용