예외처리
*22년 4월 한 달간 한국이러닝협회의 '실전 개발자를 위한 Spring Framework'를 수강하고 정리한 내용입니다
1. Spring에서의 예외처리
- 사용 이유: 서버에서 발생된 예외가 최종 사용자에게 전달되는 것 방지
- DAO와 Service에서 발생된 예외는 Controller로 모여짐
- System 예외는 Business 예외로 다시 던지는(re-throwing) 방식 사용
- @ExeptionHandler와 @ControllerAdvice를 사용하여 예외 처리
2. Spring 예외처리 특징
1) 컨트롤러 기반
- 부가기능을 제공하는 Advice 클래스 작성
- XML 설정 파일에 <aop:config>를 이용해서 aspect를 설정(즉, Advice와 Pointcut을 설정)
2) 글로벌 Exception 핸들러
- 예외처리는 cross-cutting concern, 어플리케이션 전체에 Pointcut이 적용되어야 함
- @ControllerAdvice 어노테이션을 포함한 클래스는 전역 예외처리 컨트롤러가 됨
- 컨트롤러에서 캐치한 예외는 JSP같은 View나 JSON으로 응답 가능
3. MyBatis에서의 예외처리
- JDBC 관련 코드는 대부분 SQLException 발생: 대부분의 SQLException은 복구가 불가능함
- Spring-MyBatis는 SQLException을 DataAccessException(RuntimeException)으로 re-throwing 함
- DataAccessException으로부터 SQLException을 추출하여 getErrorCode() 메소드로 에러코드 확인 가능
4. 글로벌 예외처리-@ControllerAdvice
1) @ControllerAdvice 특징
- Spring 3.2 이상에서 사용 가능
- @Controller나 @RestController에서 발생하는 예외 catch
- 스프링 4.0 이상에서는, 특정한 컨트롤러만 지정해서 catch하는 것도 가능
2) @ControllerAdvice 사용을 위한 설정
-> servlet-context.xml에서 ControllerAdvice를 include
<context:component-scan base-package="kr.co.acomp.hello" use-default-filters="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
<context:include-filter type="annotation"
expression="org.springframework.web.bind.annotation.ControllerAdvice" />
</context:component-scan>
3) 글로벌 예외처리 예제
@ControllerAdvice //모든 컨트롤러에 대응된다.
public class GlobalExceptionHandler {
@ExceptionHandler(SQLException.class)
public String handleSQLException(Exception ex) {
ModelAndView mav = new ModelAndView("exception");
mav.addObject("name", ex.getClass().getSimpleName());
mav.addObject("message", e.getMessage());
return mav;
}
//JSON 형태로 응답 수행
@ExceptionHandler(UserNotFoundException.class)
@ResponseBody
public ExceptionJSONInfo handleUserNotFoundException(
HttpServletRequest request. Exception ex) {
ExceptionJSONInfo response = new ExceptionJSONInfo();
response.setUrl(request.getRequestURL().toString());
response.setMessage(ex.getMessage());
return response;
}
}
4) @RestController 예외처리
@ControllerAdvice(annotation=RestController.class) //RestController에 대응된다
public class RestControllerExceptionHandler {
// JSON 형태로 응답 수행
@ExceptionHandler(UserNotFoundException.class)
@ResponseBody
public ErrorDetail handleUserNotFoundException(
HttpServletRequest request, Exception ex) {
ErrorDetail error = new ErrorDetail();
error.setStatus(HttpStatus.BAD_REQUEST.value());
error.setMessage(exception.getLocalizedMessage());
error.setUrl(request.getRequestURL().append("/emperror/").toString();
return error;
}
}