오늘은 @NotNull 어노테이션을 사용하여 Exception이 발생하였을때 예외처리를 커스텀하는 방법을 알아보도록 하자 !
@AllArgsConstructor
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
@Getter
@Builder
public static class RegisterDto {
private Long id;
@NotNull(message = "이메일이 입력되지 않았습니다.")
private String email;
@NotNull(message = "비밀번호가 입력되지 않았습니다.")
private String password;
@NotNull(message = "이름이 입력되지 않았습니다.")
private String name;
@NotNull(message = "닉네임이 입력되지 않았습니다.")
private String nickName;
.
.
.
Dto 클래스에서 필수적으로 받아야 하는 값들을 @NotNull을 이용해 예외처리를 하였다.
@PostMapping("auth")
public CustomResponseEntity<UserDto.RegisterDto> register(
@Valid @RequestBody final UserDto.RegisterDto request
){
...
}
또한 해당 Dto를 요청하는 파라미터 값에 꼭 @Valid를 붙여야한다. 해당 어노테이션을 붙이지 않는다면 @NotNull을 사용해도 작동되지 않는다.
왜 @NotNull을 커스텀 예외처리 해줘야 할까? 🤔
사실 예외처리를 커스텀하는 이유가 거의 동일하다고 생각한다. 로그를 조금 더 자세하고 간단하게 찍힐 수 있게끔 구성하고, 해당 Exception이 발생하였을때 클라이언트에게 Response 값을 원하는대로 보내준다던지 많은 이점을 챙겨간다고 생각한다. 해당 경우도 마찬가지로 @NotNull을 사용하여 선언해둔 값들이 null 일때 좀 더 편하고, 직관적으로 값을 구성해서 로그와 클라이언트에게 정보를 제공할 수 있다.
@ResponseBody
@ExceptionHandler(
MethodArgumentNotValidException.class
)
public CustomResponseEntity<Object> handleBadRequest(
MethodArgumentNotValidException e, HttpServletRequest request
) {
log.error("url {}, message: {}",
request.getRequestURI(), e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
return CustomResponseEntity.builder()
.code(-1)
.message(e.getBindingResult().getAllErrors().get(0).getDefaultMessage())
.build();
}
Exception을 Handler 하는 클래스가 있다면, 해당 클래스에서 위와 같이 구성하면 된다.
MethodArgumentNotValidException.class가 @NotNull의 Exception 클래스이며 해당 클래스를 핸들링 하여 아래와 같이 return 해준다. Response 값은 자신이 개발해놓은 값에 맞게 커스텀화 하면 되며, 해당 로그에서
e.getBindingResult().getAllErrors().get(0).getDefaultMessage()
이 부분을 통해 엄청 긴 로그를 어떤 값이 null인지만 쉽게 찍을 수 있다.
Request 값들을 편하게 null 체크해주는 @NotNull 어노테이션을 커스텀 예외처리 하는 방법을 알아보았다. 서비스 코드 내에서 null 체크를 하지 않고, 예외처리까지 쉽게 하는 방법이기에 null이 발생하지 않고 클라이언트에게도 쉽게 Exception 값을 전달 해줄 수 있기에 잘 활용하면 좋은 예외처리가 될거라 생각한다 👍