오늘은 전에 만들었던 할 일 카드 프로젝트의 예외처리 등을 손봤다.
아래는 내가 만든 signup 컨트롤러이다. @Valid로 입력값 걸러서 받는데, 무엇에서 오류가 생긴건지 응답을 주지 않기 때문에 클라이언트는 확실히 알 수 없다.
@PostMapping("/signup")
public ResponseEntity<CommonResponseDto> signup(@Valid @RequestBody SignupRequestDto requestDto, BindingResult bindingResult) {
List<FieldError> fieldErrors = bindingResult.getFieldErrors();
if(fieldErrors.size() > 0) {
for (FieldError fieldError : bindingResult.getFieldErrors()) {
log.error(fieldError.getField() + " 필드 : " + fieldError.getDefaultMessage());
}
return ResponseEntity.badRequest().body(new CommonResponseDto("허용된 입력값이 아닙니다.",HttpStatus.BAD_REQUEST.value()));
}
}
그래서 잘못 입력된 필드와 내용을 응답으로 보내기 위해 아래와 같이 Dto를 만들고 List로 묶어줬다.
List<FieldErrorDto> fieldErrorDtoList = fieldErrors.stream().map(FieldErrorDto::new).toList();
public class FieldErrorDto {
private String field;
private String message;
public FieldErrorDto(FieldError fieldError) {
this.field=fieldError.getField();
this.message=fieldError.getDefaultMessage();
}
}
근데 생각해보니 return이 ResponseEntity<CommonResponseDto>
형식으로 되어있어서 어떻게 해야될지 고민했는데, return형식에 구애받지 않는 error로 처리해봐야겠다는 생각을 하게 되었다.
여기서 내가 만든 DtoList를 보낼 수 있는 새로운 exception을 만들어서 거기에 파라미터와 메세지를 전달하면 될 것이라고 생각했다.
일단 내가 원하는 모양새로 오류가 생기는 경우에 대해 FieldErrorException
이라고 throw를 던져봤다.
throw new FieldErrorException(
"허용된 username 또는 password 값이 아닙니다.",
HttpStatus.BAD_REQUEST.value(),
fieldErrorDtoList
);
그 후에 위의 throw를 처리 할 수 있게 FieldErrorException
을 만들어주었다.
@Getter
public class FieldErrorException extends RuntimeException{
private final Integer statusCode;
private final List<FieldErrorDto> fieldErrorDtoList;
public FieldErrorException(String message, Integer statusCode, List<FieldErrorDto> fieldErrorDtoList) {
super(message);
this.statusCode=statusCode;
this.fieldErrorDtoList=fieldErrorDtoList;
}
}
ExceptionHandler에서 FieldErrorException를 잡아주었다.
이 때 List<FieldErrorDto>
를 바로 전달하기보단 필드 에러만 중첩된 구조로 보내고 싶었다.
그래서 FieldErrorResponseDto
를 새로 만들어서 응답에 넣어줬다.
@ExceptionHandler({FieldErrorException.class})
public ResponseEntity<FieldErrorResponseDto> FieldErrorException(FieldErrorException ex) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(
new FieldErrorResponseDto(
ex.getMessage(),
ex.getStatusCode(),
ex.getFieldErrorDtoList()
));
}
FieldErrorResponseDto
@Getter
public class FieldErrorResponseDto {
private String msg;
private Integer statusCode;
private List<FieldErrorDto> fieldError;
public FieldErrorResponseDto(String msg, int statusCode, List<FieldErrorDto> fieldErrorDtoList) {
this.msg=msg;
this.statusCode=statusCode;
this.fieldError=fieldErrorDtoList;
}
}
원하던 결과를 포스트맨을 통해 확인 할 수 있었다.