허원철의 개발 블로그

Spring Boot - Exception Handler 본문

web

Spring Boot - Exception Handler

허원철 2017. 1. 3. 19:41
이번 글은 spring에서 exception 처리를 하기 위한 글입니다.
 

 
was가 tomcat인 spring 개발을 하다보면, 볼 수 있는 에러페이지 입니다.(가장 보기 싫은 페이지죠...) 요즘은 스크립트에서 비동기 처리를 많이 하기 때문에 적다곤 해도 간간히 보입니다만, 그래도 에러에 대한 여러 처리를 하고 싶을 때가 있습니다.
 

why..?
 
- 간혹 기본 에러페이지가 아닌 Rest 형식이나 커스텀 뷰로 표현해야되는 경우가 생깁니다.
 
 
where..?
 
1. 에러가 발생하거나 일부러 에러는 내야하는 경우, 커스텀을 하고 싶다!(code변경이라던지, message 변경이라던지.. 등등)
 
2. 동일 Exception에 대해서 동일한 에러는 표현하고 싶다!
 
3. 더 간단하게 혹은 더 상세하게 보여주고 싶다!
 
 
How..?
 
1. 기본
 
 - 기본적인 Exception의 경우 입니다.
 
1
2
3
4
5
6
7
8
9
10
11
@RestController
public class BasicController {
 
    // ... 중략
    @GetMapping("/")
    public String basicError() {
        throw new IllegalStateException("Basic Error");
    }

    // ... 중략
}
cs
 
결과
Code : 500
Message : Basic Error
 
※ 어떤 Exception이든 Code 는 500 입니다.
 
 
2. 에러가 발생하거나 일부러 에러는 내야하는 경우, 커스텀을 하고 싶다!(code변경이라던지, message 변경이라던지.. 등등)
 
 - 커스텀 Exception 를 구현합니다.
 
1
2
3
4
5
6
7
8
9
10
@RestController
public class BasicController {
 
    // ... 중략
    @GetMapping("/extension")
    public String extensionError() {
        throw new ExtensionException("extension error");
    }    
    // ... 중략
}
cs
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@SuppressWarnings("serial")
@ResponseStatus(value=HttpStatus.NOT_FOUND)
public class ExtensionException extends RuntimeException {
    
    String message;
    
    public ExtensionException(String message) {
        this.message = message;
    }
    
    @Override
    public String getMessage() {
        return message;
    }
}
cs
 
결과
Code : 404(Not Found)
Message : extension error
 
@ResponseStatus 어노테이션를 간단하게 알아보겠습니다.
- value : 상태코드(HttpStatus)
- code : 상태코드(HttpStatus)
- reason : message(String)
 
※ 동일한 code 이지만 다른 message를 반환하고 싶다고 생각하여 message 만 따로 받아서 처리할 수 있도록 했습니다.
 
 
3 . 동일 Exception에 대해서 동일한 에러는 표현하고 싶다!
 
 - @ControllerAdvice 를 이용하는데, 인터셉터라고 생각하면 됩니다.
 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@RestController
public class BasicController {
 
    // ... 중략
    @GetMapping("/extension2")
    public String extension2Error() throws Exception {
        throw new NotContextException();
    }
 
    @GetMapping("/extension3")
    public String extension3Error() throws Exception {
        throw new IllegalArgumentException();
    }    
    // ... 중략
}
cs
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@ControllerAdvice
public class GlobalControllerExceptionHandler {
 
    Logger logger = Logger.getLogger(GlobalControllerExceptionHandler.class);
 
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(NotContextException.class)
    public ModelAndView handleNotContent() {
        logger.info("NotContextException 입니다.");
        // 커스텀 뷰 표현..
        // error 같은 경우, 필요한 값이 있기 때문에 이하 생략... 
        return new ModelAndView("error");
    }
 
    @ResponseStatus(HttpStatus.CONFLICT)
    @ExceptionHandler(IllegalArgumentException.class)
    public void handleConflict() {
        logger.info("handleConflict");
    }
    // ... 
}
cs
 
최종적으로 Exception을 반환하게 되면 @ControllerAdvice에서 @ExceptionHandler에 Exception이 있을 경우 해당 메소드를 실행합니다.
 
 
4 . 더 간단하게 혹은 더 상세하게 보여주고 싶다!
 
1
2
3
4
5
6
7
8
9
@RestController
public class BasicController {
 
    // ... 중략
    @GetMapping("/extension4")
    public String extension4Error() throws Exception {
        throw new RestClientException("restful error");
    }    // ... 중략
}
cs

Error 만의 Vo 를 만들어 줍니다.

1
2
3
4
5
6
7
8
9
10
public class ErrorInfo {
    
    public final String url;
    public final String ex;
 
    public ErrorInfo(String url, Exception ex) {
        this.url = url;
        this.ex = ex.getLocalizedMessage();
    }
}
cs
 

1
2
3
4
5
6
7
8
9
10
11
12
13
@ControllerAdvice
public class GlobalControllerExceptionHandler {
 
    Logger logger = Logger.getLogger(GlobalControllerExceptionHandler.class);
 
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(RestClientException.class)
    @ResponseBody
    public ErrorInfo handleBadRequest(HttpServletRequest req, Exception ex) {
        return new ErrorInfo(req.getRequestURL().toString(), ex);
    }
    // ... 중략
}
cs

 
그리고 표현하고 싶은 데이터를 반환해줍니다. 
 

※ 3,4 번에 대한 Exception은 무작위로 고른 Exception이므로 의미부여를 안하셔도 됩니다.



참고

https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc


github 주소


'web' 카테고리의 다른 글

Spring Boot - RabbitMQ  (395) 2017.01.10
메시지 큐(Message Queue) 훑어보기  (441) 2017.01.08
책 '서블릿 컨테이너의 이해' 후기  (419) 2016.12.29
Spring Boot - Resource 개선하기  (414) 2016.12.25
HTTP1.1 Header  (404) 2016.12.17
Comments