티스토리 뷰

본 글은 다크모드에 최적화되어 있습니다.

 

 

스프링에서는 form을 통해 전달받은 값에 대하여 값을 검증하는 기능과 API JSON 요청을 통해 전달받은 값에 대하여 검증을 수행할 수 있다.

 

설명에 들어가기 앞서 결론은 다음과 같다.

  • form으로 전송한 값을 @ModelAttribute를 통해 받으면 특정 필드가 바인딩에 실패해도 검증을 수행한다.
  • API JSON 통신으로 전송한 값을 @RequestBody를 통해 받으면 필드 바인딩에 실패하면 검증 자체를 수행하지 않는다.

본 글은 @ModelAttribute와 @RequestBody 애너테이션 설명 글이 아니므로 간단하게만 설명하낟.

@ModelAttirbute : Http 요청으로 전송한 값을 Controller에서 필드로 받을 필요 없이 객체로 바로 바인딩 한다.

@RequestBody : JSON API로 요청한 값을 객체로 바인딩 한다.

 


@ModelAttribute

@ModelAttribute 애너테이션 설명에 사용되는 ItemSaveForm 클래스와 컨트롤러는 다음과 같다.

컨트롤러가 호출되면 saveItem 객체를 log로 남기고 바인딩 실패 유무에 따라 클라이언트에 보여 줄 view가 달라진다.

ItemSaveForm의 필드에 사용된 Bean Validation에 대해서는 설명하지 않는다. (궁금하면 구글링하길 바란다)

@Data
public class ItemSaveForm {

    @NotBlank
    private String itemName;

    @NotNull
    @Range(min = 10000, max = 1000000)
    private Integer price;

    @NotNull
    @Max(9999)
    private Integer quantity;
}

@Slf4j
@Controller
@RequestMapping("/validation/v4/items")
@RequiredArgsConstructor
public class ValidationItemControllerV4 {

    private final ItemRepository itemRepository;

    @PostMapping("/add")
    public String addItem(@Validated @ModelAttribute("item") ItemSaveForm saveItem, BindingResult bindingResult, RedirectAttributes redirectAttributes) {

        log.info("item={}", saveItem);

        if(saveItem.getPrice() != null && saveItem.getQuantity() != null) {
            int result = saveItem.getQuantity() * saveItem.getPrice();
            if(result < 10000)
                bindingResult.reject("totalPrice", null, null);
        }

        if(bindingResult.hasErrors()){
            log.info("검증 실패");
            return "/validation/v4/addForm";
        }

        log.info("검증 성공");
        Item item = new Item(saveItem.getItemName(), saveItem.getPrice(), saveItem.getQuantity());
        Item savedItem = itemRepository.save(item);
        redirectAttributes.addAttribute("itemId", savedItem.getId());
        redirectAttributes.addAttribute("status", true);
        return "redirect:/validation/v4/items/{itemId}";
    }
}

 

  • 검증 성공

특별히 설명할 부분이 없으므로 다음으로 넘어가자

 

  • 검증 실패1

ItemSaveForm의 price 필드의 최소 가격이 10,000으로 설정되어 있다. 따라서 1,000을 저장하려고 하면 검증 실패가 된다.

 

  • 검증 실패2

ItemSaveForm의 price 필드를 보면 타입이 Integer이다. 따라서 문자 A를 저장하려고 하면 검증에 실패한다.

올바르지 않는 타입의 값을 넣어도 log에 item 객체가 찍힌다.

 

@ModelAttribute의 경우에는 올바르지 않는 입력값을 넣어 전송해도 Controller가 정상적으로 호출된다!!

 


@RequestBody

@RequestBody 애너테이션을 설명하기 위해 사용된 ItemSaveForm 클래스와 Controller는 다음과 같다.

컨트롤러가 호출되면 클라이언트에 view를 보여주는 것이 아니라 값을 전달한다.

@Data
public class ItemSaveForm {

    @NotBlank
    private String itemName;

    @NotNull
    @Range(min = 10000, max = 1000000)
    private Integer price;

    @NotNull
    @Max(9999)
    private Integer quantity;
}
@Slf4j
@RestController
@RequestMapping("/validation/api/items")
public class ValidationApiController {

    @PostMapping("/add")
    public Object addItem(@RequestBody @Validated ItemSaveForm form, BindingResult bindingResult) {
        log.info("itemSave={}", form);

        if(bindingResult.hasErrors()) {
            log.info("검증 실패");
            return bindingResult.getAllErrors();
        }

        log.info("검증 성공");
        return form;
    }
}

 

  • 검증 성공

딱히 설명할 것이 없으므로 다음으로 넘어간다.

 

  • 검증 실패1

ItemSaveForm의 price 필드의 최소 가격이 10,000으로 설정되어 있다. 따라서 1,000을 저장하려고 하면 검증 실패가 된다.

 

  • 검증 실패2

검증 실패1과 출력 결과가 다르다. log 자체가 찍히지도 않았다.  price 필드는 Integer 타입이기 때문에 문자를 저장할 수 없다. 이 경우는 ItemSaveForm 객체 자체를 생성하지 못한 경우이다. 그렇기에 Controller 자체가 호출되지 못하고 예외가 발생한 경우이다.

 

@RequestBody는 올바르지 않은 값을 전송하면 객체를 생성하지 못하기 때문에 Controller 자체가 호출되지 않는다!!


 

이렇게 @ModelAttribute와 @RequestBody에서 검증 처리 방법을 알아보았다.

Http 요청 파라미터를 처리하는 @ModelAttribute는 각각의 필드 단위로 세밀하게 처리한다.

JSON 데이터를 처리하는 @RequestBody는 HttpMessageConverter를 이용하는데, 각각의 필드 단위로 처리하는 것이 아니라 전체 객체 단위로 처리한다.

 


결론

@ModelAttribute는 모든 필드에 세밀하게 적용되므로, 특정 필드가 바인딩 되지 않아도 나머지 필드는 정상적으로 바인딩 된다. 따라서 Validator를 통한 검증도 가능하다.

@RequestBody는 하나의 필드라도 바인딩에 실패하면 JSON 데이터를 객체로 변경하지 못하므로 객체 생성에 실패한다. 따라서 Controller도 호출되지 않고 Validator도 사용할 수 없다.


 

Total
Today
Yesterday
최근에 올라온 글
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30