@Validated의 정의

검증기를 실행하라는 Annotation
WebDataBinder 에 등록한 검증기를 찾아서 실행합니다.

검증기 선정 방법

여러 검증기 중 어떤 검증기를 적용하게 될 지는 supports()에서 지정한 클래스를 통해 정해집니다.

사용 예시

검증기(변동 없음)

@Component
public class ItemValidator implements Validator {
    @Override    
    public boolean supports(Class<?> clazz) {
        return Item.class.isAssignableFrom(clazz);
    }
 
	@Override
	public void validate(Object target, Errors errors) {
		...
	}
}

호출 클래스 상위

@InitBinder
public void init(WebDataBinder dataBinder) {
    dataBinder.addValidators(itemValidator);
}

Bean Validation을 이용하면 생략 가능합니다.

호출 메서드

@PostMapping("/add")
public String addItem(
	@Validated @ModelAttribute Item item, 
	BindingResult bindingResult, 
	...) {
 
	// 아래 부분 제외해도 검증 가능
	// itemValidator.validate(item, bindingResult);
	...
}

@RequestBody를 이용한 반환

@RequestBody를 사용하여 객체 자체를 return할 때도 검증 기능을 사용할 수 있습니다.

@PostMapping("/add")
public Object addItem(
	@RequestBody @Validated ItemSaveForm form, 
	BindingResult bindingResult) { 
 
	// 오류 발생 시
	if (bindingResult.hasErrors()) {  
		log.info("검증 오류 발생 errors={}", bindingResult); 
		return bindingResult.getAllErrors();
	}
 
	// 성공 시
    return form;
}

실패 응답 예시 (9999개 제한인 제품 수량에 10000을 입력한 경우)

[  
	{
		"codes": [
		    "Max.itemSaveForm.quantity",
		    "Max.quantity",
		    "Max.java.lang.Integer",
		    "Max"
		],
		"arguments": [
			{
				"codes": [
			        "itemSaveForm.quantity",
					"quantity"
				],        
				"arguments": null,
			    "defaultMessage": "quantity",
			    "code": "quantity"
			},
			9999
		],  
		"defaultMessage": "9999 이하여야 합니다", 
		"objectName": "itemSaveForm", 
		"field": "quantity",  
		"rejectedValue": 10000, 
		"bindingFailure": false,  
		"code": "Max"
	}
]

이렇게 에러 내용 전체를 출력하기 보단 필요한 내용만 뽑아서 출력하는게 도움됩니다.

@ModelAttribute@RequestBody에서 작동의 차이

  • @ModelAttribute 는 특정 필드가 바인딩 되지 않아도 나머지 필드 는 정상 바인딩 되고, Validator를 사용한 검증도 적용할 수 있습니다.
  • @RequestBody 는 HttpMessageConverter 단계에서 JSON 데이터를 객체로 변경하지 못하면 이후 단계 자 체가 진행되지 않고 예외가 발생합니다. 컨트롤러도 호출되지 않고, Validator도 적용할 수 없습니다.