부트 개념과 활용-20.ExceptionHandler
스프링 웹 MVC 9부: ExceptionHandler
스프링 @MVC 예외 처리 방법
- @ControllerAdvice
- @ExceptionHandler
스프링 부트가 제공하는 기본 예외 처리기
BasicErrorController HTML과 JSON 응답 지원 커스터마이징 방법 ErrorController 구현
커스텀 에러 페이지
상태 코드 값에 따라 에러 페이지 보여주기 src/main/resources/static|template/error/ 404.html 5xx.html ErrorViewResolver 구현
이미 자주 봤던, 에러 핸들러가 처리해 준 결과. (브라우저 요청 -> 에러 페이지)
하지만 이렇게 요청을 하면 제이슨으로 응답이 온다. (머신 클라이언트 요청 -> json)
정확하게는 BasicErrorController 안에 다 들어있다.
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
...
// text / html 요청인 경우 - 에러페이지 반환
@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
HttpStatus status = getStatus(request);
Map<String, Object> model = Collections
.unmodifiableMap(getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
}
...
// json으로 반환
@RequestMapping
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
HttpStatus status = getStatus(request);
if (status == HttpStatus.NO_CONTENT) {
return new ResponseEntity<>(status);
}
Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
return new ResponseEntity<>(body, status);
}
예제 코드 실습
public class SampleException extends RuntimeException {
}
public class AppError {
private String message;
private String reason;
...
... get, setter
@Controller
public class SampleController {
@GetMapping("/hello")
public String hello(){
throw new SampleException();
}
// 이 컨트롤러(SampleController) 안에서 발생하는 SampleException 이라는 예외가 발생하면 이 핸들러를 사용하겠다.(ExceptionHandler)
@ExceptionHandler(SampleException.class)
public @ResponseBody AppError sampleError(SampleException e) {
AppError appError = new AppError();
appError.setMessage("error.app.key");
appError.setReason("reason is what?..");
return appError;
}
}
익셉션 클래스를 전역적으로 사용하고 싶다면?
클래스를 따로 만든 다음(익셉션 핸들러들을 모아놓은) 그 위에 @ControllerAdvice 를 붙이고
그 안에 익셉션 핸들러들을 정리하면, 여러 컨트롤러들에서 발생하는 샘플 익셉션을 처리하는 핸들러를 모두 동작하게 된다.
public class BasicErrorController extends AbstractErrorController (위에서 보았던.)
AbstractErrorController 타입의 클래스를 만들어 등록하고 빈으로 만들어 등록하면 커스터마이징이 가능하다.
BasicErrorController를 상속받아 구현해도 같다.
상속받아서 커스텀하는게 레퍼런스에서 권장하는 방법이다.
응답의 상태값에 따라 다른 웹페이지를 보여주고 싶다면?
resource - static - error
error 디렉토리 만들고
404.html (html 이름이 상태값과 같아야 한다.)
아니면
5xx.html (500번대 발생하는 에러)
사용자가 설정한 이런 커스텀에 다 걸리지 않으면
베이직 에러 컨트롤러가 띄우는 에러 화면.(제일 위의 에러 화면)
많은 커스터마이징을 하고 싶으면..
에러 뷰 리졸버(ErrorViewResolver) 구현.
좀 더 동적인 컨텐츠 뷰로 좀 더 다양하게 커스텀 가능, 에러정보들 넣어서 꾸미는 것 등…