💡 요청을 통해 들어오는 form 객체 또는 Dto에 대해 값의 유효성 검사(validation)을 진행하여 올바르지 않은 데이터가 서버로 전송되거나, DB에 저장되지 않도록 한다.
💡 Controller 전역에서 발생하는 Custom Error를 잡아줄 Handler를 생성한다.
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ControllerAdvice
public class CustomExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
ResponseEntity<ErrorResponseEntity> handleValidationException(MethodArgumentNotValidException e) {
return ErrorResponseEntity.toResponseEntity(e);
}
}
✅ @ControllerAdvice
✅ @ExceptionHandler(MethodArgumentNotValidException.class)
✅ @ControllerAdvice + @ExceptionHandler
💡 Validation Error 내용을 담을 Response Entity를 생성한다.
@Data
@Builder
public class ErrorResponseEntity {
private String code;
private String message;
public static ResponseEntity<ErrorResponseEntity> toResponseEntity(MethodArgumentNotValidException e) {
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
FieldError fieldError = fieldErrors.get(fieldErrors.size()-1); // 가장 첫 번째 에러 필드
String fieldName = fieldError.getField(); // 필드명
Object rejectedValue = fieldError.getRejectedValue(); // 입력값
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(ErrorResponseEntity.builder()
// 에러 코드 in 에러 코드 명세서
.code(fieldError.getDefaultMessage())
.message(fieldName + " 필드의 입력값[ " + rejectedValue + " ]이 유효하지 않습니다.")
.build());
}
}
Response 결과 예시
{
"code": "{ErrorCode}",
"message": "{fieldName} 필드의 입력값[ null ]이 유효하지 않습니다. "
}
public class TestReqDto {
// message에는 에러 코드 명세서에 선언한 에러 코드를 대입한다.
@NotNull(message = "ERROR-001")
private String title;
}
✅ message 값으로는 " "(문자열)
만 입력 가능하다.
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/test")
public class TestController {
private final TestService testService;
@PostMapping
public ResponseEntity<HttpStatus> test(@Valid @RequestBody TestReqDto dto) {
testService.test(dto);
return ResponseEntity.ok();
}
}
@Valid annotation을 사용해 입력값의 유효성 검사를 진행한다.
만약 title의 값이 없어 null이 들어온다면 MethodArgumentNotValidException를 발생시키고 해당 Error를 위의 코드로 처리하게 된다.
결과값
{
"code": "ERROR-001",
"message": "title 필드의 입력값[ null ]이 유효하지 않습니다. "
}
@Getter
@AllArgsConstructor
public enum Error {
TEST_ERROR("ERROR-001");
private final String message;
}
// @NotNull(message = Error.TEST_ERROR.getMessage())
// -> Attribute value must be constant
private String title;
" "(문자열)
을 입력해야 한다.final String code = "ERROR-001";
@NotNull(message = code)
private String title;
하지만 final
을 사용해 문자열을 담은 변수는 입력 가능하다.