스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 - (30) Bean Validation - HTTP 메시지 컨버터
인프런 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술편을 학습하고 정리한 내용 입니다.
@Valid, @Validated는 HttpMessageConverter(@RequestBody)에도 적용할 수 있다.
참고
@ModelAttribute는 HTTP 요청 파라미터(URL 쿼리 스트링, POST Form)를 다룰 때 사용한다.@RequestBody는 HTTP Body의 데이터를 객체로 변환할 때 사용한다. 주로 API JSON 요청을 다룰 때 사용한다.
ValidationItemApiController 생성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Slf4j
@RestController
@RequestMapping("/validation/api/items")
public class ValidationItemApiController {
@PostMapping("/add")
public Object addForm(@RequestBody @Validated ItemSaveForm form, BindingResult bindingResult) {
log.info("API 컨트롤러 호출");
if (bindingResult.hasErrors()) {
log.info("검증 오류 발생 errors={}", bindingResult);
return bindingResult.getAllErrors();
}
log.info("성공 로직 실행");
return form;
}
}
자 이렇게 만들었고 간단하게 흐름을 보도록 로그를 남겼다.
그리고 먼저 성공할 데이터를 포스트맨으로 넘겨 봤다.

자 잘 된다. 이제 실패 데이터를 넣어보자.

가격에 문자를 넣어서 실패를 유도했다.
보이는가? 400 에러가 났는데, 컨트롤러에 로그가 남지도 않고 그냥 컨트롤러 오지도 않고 실패 돼버렸다.
API의 경우 3가지 경우를 나누어 생각해야 한다.
- 성공 요청 : 성공
- 실패 요청 : JSON을 객체로 생성하는 것 자체를 실패함
- 검증 오류 요청 : JSON을 객체로 생성하는 것은 성공했고, 검증에서 실패함.
자 그럼 이번엔 검증 오류에 걸려보도록 요청해보자.
1
2
3
4
5
{
"itemName" : "hello",
"price" : 1000,
"quantity" : 10000
}
다음과 같이 수량 최대 수 9999에 걸리도록 10000을 요청했다.

자 이번엔 컨트롤러를 탔고, 다양한 오류가 나왔다. (bindingResult.getAllErrors() 로 그냥 다 출력함.)
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
[
{
"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 vs @RequestBody
HTTP 요청 파라미터를 처리하는 @ModelAttribute는 각각의 필드 단위로 세밀하게 적용된다. 그래서 특정 필드에 타입이 맞지 않는 오류가 발생해도 나머지 필드는 정상 처리할 수 있다.
HttpMessageConverter는 @ModelAttribute와 다르게 각각의 필드 단위로 적용되는 것이 아니라, 전체 객체 단위로 적용된다.
따라서 메시지 컨버터의 작동이 성공해서 ItemSaveForm 객체를 만들어야 @Valid @Validated가 적용된다.
@ModelAttribute는 필드 단위로 정교하게 바인딩이 적용된다. 특정 필드가 바인딩 되지 않아도 나머지 필드는 정상 바인딩 되고, Validator를 통한 검증도 적용할 수 있다.@RequestBody는 HttpMessageConverter 단계에서 JSON데이터를 객체로 변경하지 못하면 이후 단계 자체가 진행되지 않고 예외가 발생한다. 컨트롤러가 호출되지도 않고, Validator도 적용할 수 없다.
참고로 @RequestBody단계에서 바인딩 에러로 발생한 예외 문구는 커스텀텀이 가능하다.
댓글남기기