ConstraintValidator를 사용해보기
ConstraintValidator를 사용해보기
- 우아한 테크코스를 진행하던 도중
CostraintValidator를 사용해보라는 피드백을 받았다. - Yun님의 블로그에서 일단 최대한 따라해보자 생각하고 적용시켰다.
- 잘 따라한 것 같은데 아무리 디버깅을 해도
@ExceptionHandler(MethodArgumentNotValidException.class)에 에러가 잡히지 않았다.
왜 MethodArgumentNotValidException이 ExceptionHandler에 잡히지 않을까?
- 일단 블로그의 글과 다른 부분이 딱 하나 있었다.
- 블로그 글은
Post요청을 받고@RequestBody를 사용했는데 나는Get요청으로 단순히DTO만으로 받는다. - 혹시 데이터를 바인딩하는데 차이가 있을까?
Post 요청과 Get 요청을 받을 때 데이터 바인딩하는 방식에 차이가 있었다
- Post 요청 처리
WebDataBinder를 이용하는데@RequestBody와@Valid를 통해 내가 정의한 유효성 검사를 진행할 때 데이터 바인딩이 안 된다면MethodArgumentNotValidException이 발생한다.RequestResponseBodyMethodProcessor클래스의resolveArgument()메서드를 보면 잘 나와있다- 그리고 기본적으로 Spring은 이 예외에 대해서 400을 응답 코드로 준다
- Get 요청
- 아무것도 적지 않고 객체 타입으로 인자를 받으면
@ModelAttribute가 자동으로 붙는다. - 인자 타입의 오브젝트를 새로 만든다. 때문에 기본 생성자가 필요하다.
@Valid를 통해 유효성 검사를 진행하면BindException이 일어나지만 던지지 않는다- 이 오류는
Controller의BindingResult를 통해 잡을 수 있다.
- 아무것도 적지 않고 객체 타입으로 인자를 받으면
나의 경우에는 전역
ExceptionHandler에서 처리하고 싶은 욕심으로 커스텀 예외에BindingResult를 담고 커스텀 예외를throw시키는 방법으로 처리했다.
// Controller
@GetMapping()
public ResponseEntity<PathResponse> findShortestPath(@Valid PathRequest pathRequest, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
throw new SameStationException(bindingResult);
}
PathResponse pathResponse = pathService.findShortestPath(pathRequest, new DijkstraStrategy());
return ResponseEntity
.ok()
.body(pathResponse);
}
// ControllerAdvice
@ExceptionHandler(SameStationException.class)
public ResponseEntity<ErrorResponse> handleConflict(SameStationException e) {
return ResponseEntity.badRequest()
.body(ErrorResponse.of(ErrorCode.INVALID_INPUT_VALUE, e.getBindingResult()));
}
추후 피드백을 더 받아보고 수정해야겠다 ㅎㅎ