BindingResult
BindingResult를 통해 서버 사이드에서 검증할 때 MVC 패턴에서는 타임리프를 이용해 쉽게 error 메시지 출력이 가능했다.
그러다 프로젝트 중 요구사항이 변경되어 MVC가 아닌 Rest API 방식으로 검증 오류 메시지 출력이 필요해졌다.
MVC에서의 BindingResult
1
2
3
4
5
6
7
8
9
@PostMapping("edit")
public String update(@Validated @ModelAttribute Member member, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return "member/edit";
}
//////
return "redirect:/";
}
다음과 같이 error가 발생되면 @ModelAttribute가 붙어있는 Member 객체에 bindingResult가 함께 model에 담겨 랜더링이 가능했다.
요구사항 변경에 따른 문제
기존의 경우 수정 버튼 눌렀을 시 새로운 페이지를 랜더링해서 오류 메시지를 출력했다.
하지만 요구사항이 변경되면서 회원정보 수정 버튼을 눌렀을 때 alert 창에 메시지가 출력되게 바꿔야했다.
처음에는 bindingResult 객체 그 자체를 응답바디에 담아서 보내려고 했는데 이렇게 하면 원하는 메시지를 뽑아내기 힘들었다.
ex) BindingResult 객체를 응답 바디에 담을 시
1
2
3
4
5
6
7
8
{
"timestamp": "2024-05-23T04:10:03.285+00:00",
"status": 500,
"error": "Internal Server Error",
"trace": //생략
"message": "Type definition error: [simple type, class org.springframework.validation.DefaultMessageCodesResolver]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.springframework.validation.DefaultMessageCodesResolver and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: org.springframework.validation.BeanPropertyBindingResult[\"messageCodesResolver\"])",
"path": "/study/update"
}
이런 문제를 해결하기 위해 서버에서 BindingResult 객체의 error 메시지를 뽑아냈다.
1
List<String> errorMessages = bindingResult.getFieldErrors().stream().map(FieldError::getDefaultMessage).toList();
스트림을 통해 List로 errorMessage를 뽑아냈다.
1
결과 -> ["제목을 입력해주세요."]
리스트를 response 바디에 바로 담으면 Json의 key-value로 파싱이 되질 않아 객체를 만들어 처리해줬다.
Rest API 방식
1
2
3
4
5
6
7
8
@Data
public class ErrorMessage {
private List<String> message;
public ErrorMessage(List<String> message) {
this.message = message;
}
}
Controller
1
2
3
4
5
6
7
8
9
10
@PostMapping("edit")
public ResponseEntity<ErrorMessage> update(@Validated @ModelAttribute Member member, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
ErrorMessage errorMessages = new ErrorMessage( bindingResult.getFieldErrors().stream().map(FieldError::getDefaultMessage).toList());
return new ResponseEntity<>(errorMessages, HttpStatus.BAD_REQUEST);
}
//////
return new ResponseEntity<>(HttpStatus.OK);
}
1
결과 -> {"message":["제목을 입력해주세요."]}
다음과 같이 Json으로 잘 파싱된 것을 확인 할 수 있다.
This post is licensed under CC BY 4.0 by the author.