@ControllerAdvice로 모든 예외를 핸들링
@ControllerAdvice는 모든 예외를 한 곳에서 처리할 수 있게, 컨트롤러에게 조언을 해주는 것이라고 생각하면 됩니다.
controller에서 @Valid라는 어노테이션을 사용하면, 검사 후에 적합하지 않다고 생각하고 예외를 이곳으로 보내주게 됩니다.
핸들링 할 수 있는 예외의 종류들은 아래와 같을 것 같습니다. @NotEmpty, @Email 등도 있긴 합니다.
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* javax.validation.Valid or @Validated 으로 binding error 발생시 발생한다.
* HttpMessageConverter 에서 등록한 HttpMessageConverter binding 못할경우 발생
* 주로 @RequestBody, @RequestPart 어노테이션에서 발생
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
protected ResponseEntity<ErrorResponse> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
log.error("handleMethodArgumentNotValidException", e);
final ErrorResponse response = ErrorResponse.of(ErrorCode.INVALID_INPUT_VALUE, e.getBindingResult());
return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
}
/**
* @ModelAttribut 으로 binding error 발생시 BindException 발생한다.
* ref https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-modelattrib-method-args
*/
@ExceptionHandler(BindException.class)
protected ResponseEntity<ErrorResponse> handleBindException(BindException e) {
log.error("handleBindException", e);
final ErrorResponse response = ErrorResponse.of(ErrorCode.INVALID_INPUT_VALUE, e.getBindingResult());
return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
}
/**
* enum type 일치하지 않아 binding 못할 경우 발생
* 주로 @RequestParam enum으로 binding 못했을 경우 발생
*/
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
protected ResponseEntity<ErrorResponse> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
log.error("handleMethodArgumentTypeMismatchException", e);
final ErrorResponse response = ErrorResponse.of(e);
return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
}
/**
* 지원하지 않은 HTTP method 호출 할 경우 발생
*/
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
protected ResponseEntity<ErrorResponse> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
log.error("handleHttpRequestMethodNotSupportedException", e);
final ErrorResponse response = ErrorResponse.of(ErrorCode.METHOD_NOT_ALLOWED);
return new ResponseEntity<>(response, HttpStatus.METHOD_NOT_ALLOWED);
}
/**
* Authentication 객체가 필요한 권한을 보유하지 않은 경우 발생합
*/
@ExceptionHandler(AccessDeniedException.class)
protected ResponseEntity<ErrorResponse> handleAccessDeniedException(AccessDeniedException e) {
log.error("handleAccessDeniedException", e);
final ErrorResponse response = ErrorResponse.of(ErrorCode.HANDLE_ACCESS_DENIED);
return new ResponseEntity<>(response, HttpStatus.valueOf(ErrorCode.HANDLE_ACCESS_DENIED.getStatus()));
}
@ExceptionHandler(BusinessException.class)
protected ResponseEntity<ErrorResponse> handleBusinessException(final BusinessException e) {
log.error("handleEntityNotFoundException", e);
final ErrorCode errorCode = e.getErrorCode();
final ErrorResponse response = ErrorResponse.of(errorCode);
return new ResponseEntity<>(response, HttpStatus.valueOf(errorCode.getStatus()));
}
@ExceptionHandler(Exception.class)
protected ResponseEntity<ErrorResponse> handleException(Exception e) {
log.error("handleEntityNotFoundException", e);
final ErrorResponse response = ErrorResponse.of(ErrorCode.INTERNAL_SERVER_ERROR);
return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
- handleMethodArgumentNotValidException
- avax.validation.Valid or @Validated 으로 binding error 발생시 발생한다. )
- HttpMessageConverter 에서 등록한 HttpMessageConverter binding 못할경우 발생 주로 @RequestBody, @RequestPart 어노테이션에서 발생
- handleBindException
- @ModelAttribut 으로 binding error 발생시 BindException 발생한다.
- MethodArgumentTypeMismatchException
- enum type 일치하지 않아 binding 못할 경우 발생
- 주로 @RequestParam enum으로 binding 못했을 경우 발생
- handleHttpRequestMethodNotSupportedException :
- 지원하지 않은 HTTP method 호출 할 경우 발생
- handleAccessDeniedException
- Authentication 객체가 필요한 권한을 보유하지 않은 경우 발생합
- Security에서 던지는 예외
- handleException
- 그 밖에 발생하는 모든 예외 처리, Null Point Exception, 등등
- 개발자가 직접 핸들링해서 다른 예외로 던지지 않으면 모두 이곳으로 모인다.
- handleBusinessException
- 비즈니스 요규사항에 따른 Exception
- 아래에서 자세한 설명 진행
추가적인 예외는 @ExceptionHandler 으로 추가해서 적절한 Error Response를 만들어서 핸들링 할 수 있습니다. 비즈니스 로직도 적용할 수 있겠죠.
Error Code 정의
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;
}
}
에러 코드는 enum 타입으로 한 곳에서 관리하는 것이 후에 유지 보수에 더 효과적입니다. 또한 에러 메세지는 각 도메인별로 관리하는 것이 좋을 수 있습니다.
@Sl4j 사용법, 로그에 남기기
@Sl4j는 로깅에 대한 추상 레이어를 제공하는 인터페이스의 모음이다. 이는 나중에 로깅 라이브러리를 변경할 때 코드의 변경없이 가능하다는 것.
application.yml 설정 ( spring boot 2.3.1 )
logging:
file:
name: ${user.dir}/log/test.log # 로깅 파일 위치이다.
max-history: 7 # 로그 파일 삭제 주기이다. 7일 이후 로그는 삭제한다.
max-size: 10MB # 로그 파일 하나당 최대 파일 사이즈이다.
level: # 각 package 별로 로깅 레벨을 지정할 수 있다.
com.project.study : error
com.project.study.controller : debug
Maven or Gradle 에 lombok 라이브러리 추가
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
@SLF4J 사용법
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Controller
@Slf4j
public class TestController {
@GetMapping("/")
public String String(String str){
try {
str.toString();
} catch (NullPointerException e){
log.trace("가장 디테일한 로그");
log.warn("경고");
log.info("정보성 로그");
log.debug("디버깅용 로그");
log.error("에러",e);
}
return "test";
}
}
** 참고
https://cheese10yun.github.io/spring-guide-exception/
Spring Guide - Exception 전략 - Yun Blog | 기술 블로그
Spring Guide - Exception 전략 - Yun Blog | 기술 블로그
cheese10yun.github.io
https://programmer93.tistory.com/64
Spring boot logging - @Slf4j 어노테이션 사용법 - 삽질중인 개발자
개발을 하거나 운영을 하는 상황에서 LOGGING 은 아주 중요하다. Spring boot에서는 로그를 남기는 방법이 많이 있다. 그중 가장 편하게 사용되는 @Slf4j 어노테이션을 알아보자. SLF4J 란? 로깅에 대한
programmer93.tistory.com
'백엔드 > 개발과 설계 원칙' 카테고리의 다른 글
MSA (1) | 2022.09.01 |
---|---|
객체지향 설계 5원칙 (0) | 2022.06.12 |
객체지향이란 (0) | 2022.06.12 |
Impl 분류하는 이유 (0) | 2022.04.10 |
디자인 패턴 - 빌더 패턴 (0) | 2022.03.07 |