스프링에서의 예외처리
1. try-catch
컨트롤 메서드 내에서 try-catch로 처리
2. ExceptionHandler메서드가 처리
- 컨트롤러에서 처리
- @ControllAdvice클래스에서 모든 처리
3. 예외 종류별로 뷰지정- SimpleMappingExceptionResolver
4. 응답 상태 코드 별로 뷰 지정 - <error-page>
@ExceptionHandler
- 컨트롤러와 비슷한 형태이다.
- 에러가 발생하면 해당에러에 맞는 처리를 하는 파트이다.
- 기본적으로 @Exception핸들러는 같은컨트롤러클래스에서만 감지를 함
- @ExeceptionHandler(처리할예외종류), 예외가 여러개변 배열로 넣기
- jsp에서 isErrorPage="true"로 해주면 model로 안넘겨도 exception속성들을 사용할 수 있다.
하지만 상태코드가 500으로 강제로 바뀐다.
@ResponseStatus
- 응답 메시지의 상태 코드를 변경할 때 사용(에러페이진데 200이 나오면안된다.-> 변경을 해주어야 한다.)
- 사용자 정의 예외클래스 구현시에 사용
@ControllerAdvice
- 기본적으로 @Exception핸들러는 같은클래스에서만 감지를 함
- @ControllAdvice를 사용하면 전역을 감지함
- @ControllAdvice("com.sad.sda") 처럼 패키지명을 넣으면 해당패키지 내에서 감지함
- @ControllerAdvice는 예외처리말고도 다른 용도로도 사용함
SimpleMappingExceptionResolver
- 따로 예외처리 컨트롤러 만들 필요 없이 예외종류별 뷰 매핑을 할 수 있다.
- sevlet-context.xml에 등록
- 예외종류별이다
<error-page>
- jsp의 경우 web.xml에서 에러코드에 따른 페이지들을 설정해 줄 수 있다.
- 이때의 jsp파일은 resouces패키지안에 위치(views가 아님)
- SimpleMappingExceptionResolver는 예외종류별, <error-page>는 에러코드별이다.
ExceptionResolver( default전략)
- 요청 -> DispatcherServlet -> Controller
- 여기서 DispatcherServlet의 handlerExceptionResolver가 아래의 3개의 ExceptionResolver를 가지고 있고 순차대로 처리(체크)가 진행된다.
- ExceptionHandlerExceptionResolver (해당하는 @ExceptionHandler가 있는지 -> 설정된 대로 요청(오류 페이지 요청등))
- ResponseStatusExceptionResolver (@ResponseStatus, 응답코드가 바꿈, 해당코드에 해당하는 처리(오류 페이지 요청 등))
- DefaultHandlerExceptionResolver(위의 것들에서 처리가 안되면 스프링에 정의된 예외의 상태코드대로 처리)
- 위 순서대로 예외를 처리할 수 있는지 체크 한다.
실전예제
json형태로 데이터를 리턴할 때
- @ControllerAdvice 대신 @RestControllerAdvice를 사용한다. (@Controller대신 @RestController쓰는맥락, Rest는 데이터를 ResponseEntity로 감싸서 반환한다.)
- 파일구조
- ExceptionManage : 전역에서 발생하는 에러를 감지하고 에러 발생시 에러코드,Status를 담고 ErrorDTO에 에러코드와 메세지를 담는다.
@RestControllerAdvice
public class ExceptionManager {
@ExceptionHandler(AppException.class)
public ResponseEntity<?> appExceptionHandler(AppException e){
return ResponseEntity.status(e.getErrorCode().getHttpStatus())
.body(new ErrorDTO(e.getErrorCode(), e.getMessage()));
}
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<?> runtimeExceptionHandler(RuntimeException e){
return ResponseEntity.status(HttpStatus.CONFLICT)
.body(e.getMessage());
}
}
- AppException: 내가 커스텀한 에러를 처리하기 위해 만든 예외, 아래 예시에선 에러의 상위클래스중 하나인 RuntimeException을 상속받아 구현했다.
@AllArgsConstructor
@Getter
public class AppException extends RuntimeException{
private ErrorCode errorCode;
private String message;
}
- ErrorCode: enum이다.
@AllArgsConstructor
@Getter
public enum ErrorCode {
MEMBER_DUPLICATED(HttpStatus.CONFLICT,""), //409
NOT_SUPPORTED_SOCIAL_PLATFORM(HttpStatus.CONFLICT,""),
NOT_A_MEMBER(HttpStatus.NOT_FOUND,""), //404 ,일단 404로 처리했긴한데.. 흠
SOCIAL_LOGIN_FAIL(HttpStatus.CONFLICT,"");
//""안은 메세지
private HttpStatus httpStatus;
private String message;
}
- ErrorDTO: 데이터반환을 위한 DTO
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ErrorDTO {
private ErrorCode errorCode;
private String massege;
}
- 에러 발생시키기
if(optionalUser.isPresent()){
throw new AppException(ErrorCode.MEMBER_DUPLICATED,nickname+" 는 이미 존재하는 닉네임입니다.");
}
JSP, 타임리프등을 뷰로 사용할 때
- Exception컨트롤러에서 @ExceptionHandler를 이용해서 해당에러가 발생하면 에러페이지 error.jsp로 이동하도록 설정하면 됨
- @ExceptionHandler는 기본적으로 같은 클래스 내에서만 작동한다. (감지영역)
- 에러코드도 변경해야 한다.
- 컨트롤러마다 ExceptionHandler가 필요하다.
-> Global한 catcher로 변환
-> 새로 클래스를 만들고 @ControllerAdvice어노테이션이용(모든클래스에서 적용됨)
jsp의 경우 web.xml에서 에러코드에 따른 페이지들을 설정해 줄 수 있다. 이때의 jsp파일은 resouces패키지안에 위치(views가 아님)
'I leaned > 스프링,스프링부트' 카테고리의 다른 글
데이터의 변환과 검증 (0) | 2023.05.30 |
---|---|
DispatcherServlet (0) | 2023.05.26 |
세션(Session) (0) | 2023.05.24 |
쿠키(Cookie) (0) | 2023.05.24 |
redirect와 forward (0) | 2023.05.23 |