Spring MVC에서 Controller 일괄 예외처리하기 (@ControllerAdvice)

항목 개발환경 비고
운영체제 Widnwos10(64)
백엔드프레임워크 Spring MVC 4
개발언어 java1.8
WAS Tomcat9
템플릿엔진 Thymeleaf3
템플릿엔진레이아웃 Tymeleaf-laout-dialect2
DB mysql8
ORM mybatis

들어가기

Spring MVC에서 @ControllerAdvice를 사용해서 controller 에서 발생하는 예외를 일괄 처리하는 방법을 알아보겠다.

이 예제는 Spring boot가 아닌, Spring lagacy project로 만들었으며 템플릿 엔진으로 Thymeleaf를 사용하고 있다.

1.@ControllerAdvice를 등록할 클래스 만들기

아래처럼 클래스를 만든다.

스프링 MVC에서 제공하는 @ControllerAdvice는 호출되는 메소드에서 발생된 Exception을 모두 처리하는 역할을 한다. @ControllerAdvice 애노테이션을 통해서 이 클래스의 객체가 컨트롤러에서 발생하는 Exception을 전문적으로 처리하는 클래스라는 것을 명시한다.

만드는 방식은 다음과 같다.

  • 1.클래스에 @ControllerAdvice 라는 애노테이션 처리
  • 2.각 메소드에 @ExceptionHandler를 이용해서 적절한 타입의 Exception을 처리

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.hanumoka.sample.exception;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

@ControllerAdvice
public class SampleCommonExceptionAdvice {

private static final Logger logger = LoggerFactory.getLogger(SampleCommonExceptionAdvice.class);

/* common메소드는 Exception 타입으로 처리하는 모든 예외를 처리하도록 설정 */
@ExceptionHandler(Exception.class)
public ModelAndView common(Exception e) {

logger.info(e.toString());

ModelAndView mav = new ModelAndView();
mav.setViewName("/samples/errors/error_common");
mav.addObject("exception", e); //예외를 뷰에 던져서 주자.

return mav;
}


}

2.error_common.html 파일을 만들다.

이 파일은 exception 내용을 보여준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
data-layout-decorate="~{samples/layout/sampleLayout}"
>

<!-- 사용자 CSS 추가 -->
<th:block layout:fragment="css">
</th:block>

<!-- 사용자 스크립트 추가 -->
<th:block layout:fragment="script">
</th:block>

<div layout:fragment="content">
<!-- Content Wrapper. Contains page content -->
<div class="content-wrapper">
<!-- Content Header (Page header) -->
<section class="content-header">
<h1>
error_common
<small>Optional description</small>
</h1>
<ol class="breadcrumb">
<li><a href="#"><i class="fa fa-dashboard"></i> Level</a></li>
<li class="active">Here</li>
</ol>
</section>

<!-- Main content -->
<section class="content container-fluid">

<!--------------------------
| Your Page Content Here |
-------------------------->

<h4 th:text="${exception.getMessage()}"></h4>

<ul th:each="est : ${exception.getStackTrace()}">
<li th:text="${est.toString()}"></li>
</ul>

</section>
<!-- /.content -->
</div>
<!-- /.content-wrapper -->
</div>
</html>

부트스트랩과 thymeleaf때문에 좀 지저분한데, exception내용을 보여주는 부분은 아래와 같다. 중요한

1
2
3
4
5
<h4 th:text="${exception.getMessage()}"></h4>

<ul th:each="est : ${exception.getStackTrace()}">
<li th:text="${est.toString()}"></li>
</ul>

3.@ControllerAdvice 동작 확인하기

컨트롤러에 아래처럼 RunTimeException이 발생하게 수정하고 url로 접근해 보자.

1
2
3
4
5
6
7
8
9
10
11
@RequestMapping(value = "/listAll", method = RequestMethod.GET)
public String listAll(Locale locale, Model model) throws Exception {

logger.info("show all list........");

model.addAttribute("list", service.listAll());

double e1 = 1 / 0;

return "/samples/board/list";
}

결과확인