3.3 Catch Error

yeonseong Jo·2023년 6월 19일
0

SEB_BE_45

목록 보기
34/47
post-thumbnail

이전 dto를 통해 유효성 검증을 진행했었는데,
이번엔 유효성 검증이 실패 했을 경우
처리하는 방법에 대해 배웠다.

물론 기본적인 예외 처리는
Spring에서 알아서 해준다.
하지만, 사용자나 클라이언트에
자세하게 error response를 보여주기 위한
예외 처리하는 방법이 있다.


ExceptionHandler

@RestController
@RequestMapping("~")
public class Controller{
	@PostMapping
    ...
    
    @ExceptionHandler 
    public ResponseEntity handleException(MethodArgumentNotValidException e) {
    	// 유효성 검증 예외 처리
        final List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        // 각 필드별 유효성 검증 예외 리스트
        return new ResponseEntity<>(fieldErrors, HttpStatus.BAD_REQUEST);
    }
}

springframework가 제공하는
기본적인 Exception들을 사용하여
(물론 유효성 검증 관련도 있다.)

Controller안에서
method를 작성하는 방법이다.

ErrorResponse class

하지만, FieldError는 유효성 검증에 실패한 error message 뿐만 아니라
해당 데이터의 구조까지 보여주기 때문에,
위험할 수 있다.

@Getter
@AllArgsConstructor
public class ErrorResponse {
    // (1)
    private List<FieldError> fieldErrors;

    @Getter
    @AllArgsConstructor
    public static class FieldError {
    	// 오류 필드
        private String field;
        // 받은 값
        private Object rejectedValue;
        // 오류 이유
        private String reason;
    }
}

그래서 따로 ErrorResponse라는 클래스를 생성하여
사용자나 클라이언트에 보여주고자 하는 error 내용만
걸러 보여주게 한다.

단점

구현 코드를 보자마자 생각이 났는데,
이 방식은
ExceptionHandler는 controller에 작성되기 때문에
모든 controller에 각각 따로 작성해야 한다는 것이다.
에러 내용이 같더라도!!


Exception with RestControllerAdvice

그래서 사용하는게
RestControllerAdvice이다.
예외 처리를 할 클래스에서 이 annotation을 사용하면,
한 클래스에서 공통으로 사용할 예외 처리를 작성하여
Controller에 상관없이 다 사용할 수 있다.

(이 RestControllerAdivce에 있는 Advice는
AOP에서 사용하는 Advice와 같은 개념이다.
공통의 관심사(예외 처리사항)을 관리)

advice class

@RestControllerAdivce
public class ExceptionAdvice{
	@ExceptionHandler
    public ErrorResponse notValidException(
    	MethodArgumentNotValidException e
    ) {
    	final List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        final ErrorResponse response = ErrorResponse.of(e.getBindingResult());
        
        return response;
    }
}

advice는 간단하게 작성해 주고,

ErrorResponse class

@Getter
public class ErrorResponse{
	private List<FieldError> fieldErrors;
    
    private ErrorResponse(List<FieldError> fieldErrors){
    	this.fieldErrors = fieldErrors;
    }
    
    public static ErrorResponse of(BindingResult br){
    	return new ErrorResponse(FieldError.of(br));
    }
    @Getter
    public static class FieldError{
    	private String field,
        private Object rejectedValue;
        private String reason;
        
        private FieldError(String field, ...){
        	// 생성자
        }
        public static List<FieldError> of(BindingResult br){
        	final List<org.springframework.validation.FieldError> fieldErrors = bindingResult.getFieldErrors();
            return fieldErrors.stream()
            		.map(error -> new FieldError(
                    	error.getField(),
                        error.getRejectedValue() == null? "" : error.getRejectedValue().toString(),
                        error.getDefaultMessage()))
                    .collect(Collectors.toList());
        }
    }
}

ErrorResponse클래스에서
exception을 파라미터로 받아 원하는 정보만 보여주도록
exception을 ErrorResponse로 바꾸는 기능을 만들어

각 클래스별로 역할을 명확하게 하여 유지보수를 조금은 더 향상 시킬 수 있다.


ustom Exception 처리

spring에서 제공하는 MethodArgumentNotValidException 등의
Exception외에도 다른 exception이나, custom한 exception
또한 당연하게도 사용 가능하다.

@RestControllerAdvice
public class ExceptionAdvice{
	...
    @ExceptionHandler
    @ResponseStatus(HttpStatus.원하는_코드) 
    // return type이 ResponseEntity일 때 생략 가능
    public ErrorResponse(혹은 ResponseEntity) handleCustomException(CustomException e){
    	ErrorResponse response = ErrorResponse.of(e);
    	return response;
    }
}
@Getter
public class ErrorResponse{
	private int statusCode;
    private String message;
    
    private ErrorResponse(int statusCode, String message){
    	this.statusCode = statusCode;
        this.message = message;
    }
    public ErroResponse of(CustomException e){
    	return new ErrorResponse(원하는_status_code, e.getMessage());
    }
}
profile
뒤(back)끝(end)있는 개발자

0개의 댓글