티스토리 뷰
Exception 처리 방법
1. @ExceptionHandler + @RestControllerAdvice
- 전역 Exception 처리를 지원한다
- ResponseEntity를 사용하여 예외를 처리할 수 있다
- 같은 메소드에 여러 Exception을 매핑하여 사용이 가능하다
@ControllerAdvice
@RestController
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<?> processValidationError(MethodArgumentNotValidException exception) {
BindingResult bindingResult = exception.getBindingResult();
StringBuilder builder = new StringBuilder();
for (FieldError fieldError : bindingResult.getFieldErrors()) {
builder.append("{");
builder.append("error field: "+fieldError.getField());
builder.append(" message: "+fieldError.getDefaultMessage());
builder.append(" value: "+fieldError.getRejectedValue());
builder.append("}, ");
}
String errors = builder.toString();
BaseResponse baseResponse = new BaseResponse(400, errors, "0001", "요청값이 잘못되었습니다.");
return ResponseEntity.ok().body(baseResponse);
}
}
- MethodArgumentNotValidException : @valid를 통한 dto 필드 검증시 발생하는 예외를 처리해주는 클래스
- BaseResponse : 개발자가 정의한 ErrorResponse 객체
- ResponseEntity를 사용하여 리턴
2. ResponseStatusException (Spring 5 이상)
- 전역 Exception 처리를 지원한다
- HttpStatus를 제공하고 이유&원인을 제공하는 인스턴스를 만들어 사용이 가능하다
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;
public class ForbiddenException extends ResponseStatusException {
public ForbiddenException(String message) {
super(HttpStatus.FORBIDDEN,message);
}
}
public class PasswordMismatchException extends ForbiddenException {
public PasswordMismatchException(){super("Password is wrong");}
}
- @ExceptionHadler를 사용할 필요 없이 바로 예외를 던질 수 있다
깔끔한 Exception 처리 전략
1. ErrorCode 정의
비즈니스단의 예외를 처리하는 경우에는 ErrorCode를 Enum으로 정의하고 BuisnessException을 사용하여 @ExceptionHandler에서 통일성 있게 처리하는 것이 바람직하다.
public enum ErrorCode {
// Common
INVALID_INPUT_VALUE(400, "C001", " Invalid Input Value"),
METHOD_NOT_ALLOWED(405, "C002", " Invalid Input Value"),
....
HANDLE_ACCESS_DENIED(403, "C006", "Access is Denied"),
// Member
EMAIL_DUPLICATION(400, "M001", "Email is Duplication"),
LOGIN_INPUT_INVALID(400, "M002", "Login input is invalid"),
;
private final String code;
private final String message;
private int status;
ErrorCode(final int status, final String code, final String message) {
this.status = status;
this.message = message;
this.code = code;
}
}
@Getter
public class BusinessLogicException extends BusinessException {
private ErrorCodeType errorCodeType;
public BusinessLogicException(ErrorCodeType errorCodeType) {
super(errorCodeType.getMessage());
this.errorCodeType = errorCodeType;
}
}
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BuisnisLogicException.class)
public ResponseEntity handleNotFoundException(BuisnisLogicException e) {
ErrorCodeType errorCodeType = e.getErrorCodeType();
String message = errorCodeType.getMessage();
Integer status = errorCodeType.getStatus();
String code = errorCodeType.getCode();
BaseResponse baseResponse = new BaseResponse(status, "errors", code, message);
return ResponseEntity.ok().body(baseResponse);
}
}
- ErrorType 으로 비즈니스단의 에러코드를 정의
- 정의한 에러코드를 BusinessLogicException 클래스에 적용하여 사용
- ExceptionHandler로 BsinessLoginException을 실행시키고 적절한 ErrorResponse 객체를 생성하여 반환
2. 통일된 ErrorResponse 객체 사용
통일된 ErrorResponse를 사용하므로써 클라이언트에서 예외처리를 항상 동일한 로직으로 처리할 수 있도록한다
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class BaseResponse {
private Integer status = 200;
private String errors = "";
private String errorCode = "";
private String errorMessage = "";
}
'BackEnd > SpringBoot' 카테고리의 다른 글
[Spring] - Spring & DispatcherServlet (0) | 2021.01.18 |
---|---|
[Spring] - 프록시 패턴과 스프링 AOP (0) | 2020.11.16 |
[Spring] - SpringBoot에서 Redis Cache 사용하기 (0) | 2020.10.15 |
[Spring Security] - SpringSecurity+Jwt 로그인 과정 (0) | 2020.10.10 |
[Spring] - Filter,Interceptor,AOP의 개념 및 차이 (0) | 2020.10.09 |