@GetMapping("/")
public String root() throws Exception{
throw new Exception("테스트");
}
- 결과 : java.lang.Exception: 테스트
BasicErrorController
- 스프링부트의 기본 응답
- BasicErrorController를 상속받아서 응용 할 수 있다.
- 특정 메소드만 오버라이드
- 특정 핸들러 메소드를 추가
- BasicErrorController의 핸들러 메소드
- BasicErrorController.errorHtml()
- 뷰 응답
- BasicErrorController.error()
- json body 응답
- BasicErrorController.errorHtml()
static html 이나 template 파일을 추가해서 커스텀 페이지를 등록하는 법
• 단일 기본 페이지
• /resources/static/error.html
• /resources/public/error.html
• /resources/template/error.[템플릿확장자]
• http status 별 기본 페이지
• /resources/[static|public|template]/error/{http status 번호}.[html|템플릿확장자]
• /resources/[static|public|template]/error/4xx.[html|템플릿확장자]
• /resources/[static|public|template]/error/5xx.[html|템플릿확장자]
@ExceptionHandler
- 비즈니스 로직이 던진 예외에 반응하는 핸들러 메소드
- 위치 : 특정 컨트롤러 클래스 내부, @ControllerAdvice 컴포넌트 내부
- 특정 예외에 반응한다.
- 예외 처리 범위
- 컨트롤러 안에 작성했을 경우 : 해당 컨트롤러만 처리
- @ControllerAdvice에 작성했을 경우 : 프로젝트 전체 처리
- 입출력 자료형도 핸들러 메소드와 유사하지만 차이점으로 예외를 입력 인자로 다룰 수 있다.
- 입력 인자로 받은 예외만 처리할 수 있다.
@ControllerAdvice
- @ExceptionHandler를 모아서 글로벌하게 적용 할 때 쓰는 애노테이션
- 종류
- @ControllerAdvice : 뷰 에러 처리
- @RestControllerAdvice = @ControllerAdvice + @ResposeBody : JSON API 에러 처리
- 속성
- • value == basePackages
• basePackages: 적용 범위를 문자열을 이용해 특정 패키지로 지정
• basePackageClasses: 적용 범위를 대표 클래스 한 개를 이용해 특정 패키지로 지정
• basePackages 를 type-safe 하게 사용하기 위해 제공하는 옵션
• assignableTypes: 적용 범위를 특정 클래스에 할당할 수 있는 컨트롤러로 지정
• annotations: 적용 범위를 특정 애노테이션을 사용한 컨트롤러로 지정
- • value == basePackages
@ResposeEntityExceptionHandler
- Spring MVC에서 내부적으로 발생하는 예외들을 처리하는 클래스
- API 예외 처리를 담당하는 @ControllerAdvice 클래스에서 상속 받아 사용
- 커스터마이징을 원하는 특정 메소드를 오버라이딩
// BaseErrorController
@Controller // 이 클래스가 컨트롤러로 사용됨을 표시
public class BaseErrorController implements ErrorController { // 오류 처리를 위해 ErrorController 인터페이스를 구현함
@RequestMapping(path = "/error", produces = MediaType.TEXT_HTML_VALUE) // /error 경로에 대한 HTTP 요청 매핑
public ModelAndView errorHtml(HttpServletResponse response) { // HTML 오류 처리를 위한 메서드
HttpStatus httpStatus = HttpStatus.valueOf(response.getStatus()); // 응답에서 HTTP 상태 가져오기
ErrorCode errorCode = httpStatus.is4xxClientError() ? ErrorCode.BAD_REQUEST : ErrorCode.INTERNAL_ERROR; // HTTP 상태에 따라 오류 코드 결정
if (httpStatus == HttpStatus.OK) { // 상태가 OK인 경우
httpStatus = HttpStatus.FORBIDDEN; // 상태를 FORBIDDEN으로 변경
errorCode = ErrorCode.BAD_REQUEST; // 오류 코드를 BAD_REQUEST로 설정
}
return new ModelAndView( // 새로운 ModelAndView 객체 생성
"error", // 뷰 이름
Map.of( // 모델 속성
"statusCode", httpStatus.value(), // HTTP 상태 코드
"errorCode", errorCode, // 오류 코드
"message", errorCode.getMessage(httpStatus.getReasonPhrase()) // 오류 메시지
),
httpStatus // HTTP 상태
);
}
}
@ExceptionHandler
// APIEventController 내의 범위의 핸들러 메서드 GeneralException 처리 -> 발생하면 아래 형식으로 json 조립해서
@ExceptionHandler
public ResponseEntity<APIErrorResponse> general(GeneralException e){
ErrorCode errorCode = e.getErrorCode();
HttpStatus status = errorCode.isClientSideError() ?
HttpStatus.BAD_REQUEST :
HttpStatus.INTERNAL_SERVER_ERROR;
return ResponseEntity
.status(status)
.body(APIErrorResponse.of(
false, errorCode, errorCode.getMessage(e)
));
}
@ControllerAdvice
@ControllerAdvice // 컨트롤러에서 발생하는 예외를 처리하는 어드바이스 클래스
public class BaseExceptionHandler {
@ExceptionHandler // 예외 처리 메서드
public ModelAndView general(GeneralException e) { // GeneralException을 처리하는 메서드
ErrorCode errorCode = e.getErrorCode(); // 예외로부터 오류 코드 가져오기
return new ModelAndView( // 새로운 ModelAndView 객체 반환
"error", // 뷰 이름
Map.of( // 모델 속성
"statusCode", errorCode.getHttpStatus().value(), // HTTP 상태 코드
"errorCode", errorCode, // 오류 코드
"message", errorCode.getMessage() // 오류 메시지
),
errorCode.getHttpStatus() // HTTP 상태
);
}
@ExceptionHandler // 예외 처리 메서드
public ModelAndView exception(Exception e, HttpServletResponse response) { // Exception을 처리하는 메서드
HttpStatus httpStatus = HttpStatus.valueOf(response.getStatus()); // 응답에서 HTTP 상태 가져오기
ErrorCode errorCode = httpStatus.is4xxClientError() ? ErrorCode.BAD_REQUEST : ErrorCode.INTERNAL_ERROR; // HTTP 상태에 따라 오류 코드 결정
if (httpStatus == HttpStatus.OK) { // 상태가 OK인 경우
httpStatus = HttpStatus.FORBIDDEN; // 상태를 FORBIDDEN으로 변경
errorCode = ErrorCode.BAD_REQUEST; // 오류 코드를 BAD_REQUEST로 설정
}
return new ModelAndView( // 새로운 ModelAndView 객체 반환
"error", // 뷰 이름
Map.of( // 모델 속성
"statusCode", httpStatus.value(), // HTTP 상태 코드
"errorCode", errorCode, // 오류 코드
"message", errorCode.getMessage(e) // 예외로부터 오류 메시지 가져오기
),
httpStatus // HTTP 상태
);
}
}
@RestControllerAdvice
@RestControllerAdvice(annotations = {RestController.class, RepositoryRestController.class}) // RestController 및 RepositoryRestController 어노테이션이 지정된 클래스에서 발생하는 예외를 처리하는 어드바이스 클래스
public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler // 예외 처리 메서드
public ResponseEntity<Object> validation(ConstraintViolationException e, WebRequest request) { // ConstraintViolationException을 처리하는 메서드
return handleExceptionInternal(e, ErrorCode.VALIDATION_ERROR, request); // 예외 처리 내부 메서드 호출
}
@ExceptionHandler // 예외 처리 메서드
public ResponseEntity<Object> general(GeneralException e, WebRequest request) { // GeneralException을 처리하는 메서드
return handleExceptionInternal(e, e.getErrorCode(), request); // 예외 처리 내부 메서드 호출
}
@ExceptionHandler // 예외 처리 메서드
public ResponseEntity<Object> exception(Exception e, WebRequest request) { // Exception을 처리하는 메서드
return handleExceptionInternal(e, ErrorCode.INTERNAL_ERROR, request); // 예외 처리 내부 메서드 호출
}
@Override
protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
return handleExceptionInternal(ex, ErrorCode.valueOf(status), headers, status, request); // 예외 처리 내부 메서드 호출
}
private ResponseEntity<Object> handleExceptionInternal(Exception e, ErrorCode errorCode, WebRequest request) { // 예외 처리 내부 메서드
return handleExceptionInternal(e, errorCode, HttpHeaders.EMPTY, errorCode.getHttpStatus(), request); // 예외 처리 내부 메서드 호출
}
private ResponseEntity<Object> handleExceptionInternal(Exception e, ErrorCode errorCode, HttpHeaders headers, HttpStatus status, WebRequest request) { // 예외 처리 내부 메서드
return super.handleExceptionInternal( // 부모 클래스의 예외 처리 내부 메서드 호출
e,
ApiErrorResponse.of(false, errorCode.getCode(), errorCode.getMessage(e)), // API 응답 오류 생성
headers,
status,
request
);
}
}
'개발 > Spring' 카테고리의 다른 글
Test Driven Development(TDD) (1) | 2024.02.18 |
---|---|
Controller Test (0) | 2024.02.18 |
MVC 패턴 - API 설계(2) (0) | 2024.02.17 |
함수형 프로그래밍 (0) | 2024.02.16 |
MVC 패턴(2) - API 설계 (0) | 2024.02.16 |