참고!
0. Controller
/messages URI로 POST요청을 하면, @Valid 어노테이션이 설정되어 있기 때문에 MesseageParam에 설정된 검증 항목(?)들을 검사한다.
만약 검증을 통과하지 못하면..! (더 큰 값을 보낸다거나 필수값을 보내지 않는 등..) Exception이 발생한다..
@RestController
public class MessageController {
@PostMapping(value = "/messages", produces = "application/json")
public ResponseEntity<?> sendSMS(@Valid @RequestBody MessageParam param) {
return new ResponseEntity<>(HttpStatus.OK);
}
}
1. GlobalExceptionHandler작성
이 클래스에 @RestContollerAdvice어노테이션을 설정함으로써 컨트롤러에서 발생하는 Exception들을 처리할 수 있다..!
RestControllerAdvice는 ControllerAdvice + ResponseBody
@ControllerAdvice는 기본적으로 모든 컨트롤러(@Controller)를 감지해 처리하고, basePackage()와 같은 선택자를 이용해 특정 컨트롤러에만 작동하도록 할 수도 있다.
우선 위의 컨트롤러에 적어둔대로 @Valid 유효성 검사를 통과하지 못했을 때 발생하는 MethodArgumentNotValidException을
@ExceptionHandler에 등록(?)하고 해당 Exception이 발생하면 ControllerAdvice가 감지한다..
+) ResponseBody로 리턴할 ErrorResponse 객체를 만들어 표준화하면 좋은데, 그 방법은 맨 위의 링크를 참고하면 된다.
@RestControllerAdvice // 컨트롤러에서 발생한 Exception들을 모두 이 곳에서 처리할 수 있도록
@Slf4j
public class GlobalExceptionHandler {
/* @Valid 로 유효성 검사했을 때 발생한 에러 */
@ExceptionHandler(MethodArgumentNotValidException.class)
protected ResponseEntity<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
log.error("MethodArgumentNotValidException", e);
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}
2. 테스트!
call_back이라는 field는 현재 @NotBlank로 설정되어있어서 Null과 빈문자열("") 그리고 공백(" ")을 허용하지 않는다.
call_back에 아무런 문자열도 입력하지 않고 요청했을 때 저렇게 아주 친절하게 알려준다...
+) 직접 만든 제약 (Custom Constraint)에 대한 ExceptionHandling
MethodArgumentNotValidException은 BindingResult를 이용해 어떤 항목들이 유효성 검사를 통과하지 못했는지 알 수 있고,
ConstraintViolationException은 ConstraintViolations를 이용해 알 수 있다..!
/* Custom Constraint 관련 에러 */
@ExceptionHandler(ConstraintViolationException.class)
protected ResponseEntity<?> handleConstraintViolationException(ConstraintViolationException e) {
log.error("ConstraintViolationException", e);
final ErrorResponse response =
ErrorResponse.of(ErrorCode.INVALID_INPUT_VALUE, e.getConstraintViolations().iterator());
return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
}
ErrorResponse 👇
/* 생략 ... */
public static ErrorResponse of(final ErrorCode code, final Iterator<ConstraintViolation<?>> violationIterator) {
return new ErrorResponse(code, FieldError.of(violationIterator));
}
/* 생략 ... */
private static List<FieldError> of(final Iterator<ConstraintViolation<?>> violationIterator) {
List<FieldError> fieldErrors = new ArrayList<>();
while (violationIterator.hasNext()) {
final ConstraintViolation<?> constraintViolation = violationIterator.next();
fieldErrors.add(new FieldError(
getFieldName(constraintViolation.getPropertyPath().toString()),
constraintViolation.getInvalidValue() == null? "" : constraintViolation.getInvalidValue().toString(),
constraintViolation.getMessage()
));
}
return fieldErrors;
}
/* 생략 ... */
'STUDY > Spring' 카테고리의 다른 글
Spring Boot | Spring Security @PreAuthorize사용하기 (0) | 2021.03.26 |
---|---|
Spring Boot | REST API 파일 업로드 / 다운로드 (1) | 2021.03.23 |
Spring Boot | 유효성 검사 직접 만들기! (Custom Constraint) (0) | 2021.03.17 |
Spring Boot | spring-boot-starter-validation (2) | 2021.03.16 |
Spring Boot | Spring Security 한 유저에게 여러 Authority(ROLE) 부여하기 (UserDetails) (0) | 2021.03.15 |