예외 사항을 전부 매번마다 핸들링해야 한다면 중복적이고 많은 양의 코드를 작성해야 하지만, 공통적인 예외사항에 대해서는 별도로 @ControllerAdvice
를 이용해서 분리한다. AOP
를 이용하는 방식이다.
@ControllerAdvice는 뒤에서 배우는 AOP를 이용하는 방식이다. 핵심적인 로직은 아니지만 프로그램에서 필요한 공통적인 관심사
는 분리하자는 개념입니다. Controller를 작성할 때는 메서드의 모든 예외사항을 전부 핸들링해야 한다면 중복적이고 많은 양의 코드를 작성해야 하지만, AOP 방식을 이용하면 공통적인 예외사항에 대해서는 별도로 @ControllerAdvice를 이용해서 분리하는 방식입니다.
발생하는 예외의 타입별로 흐름을 나눠줄 때 사용하는 매핑방식
// 해당 클래스가 스프링의 컨트롤러에서 발생하는 예외를 처리하는 존재임을 명시 @ControllerAdvice @Log4j public class CommonExceptionAdvice { @ExceptionHandler(Exception.class) public String except(Exception e, Model model) { log.error("====================Exception=================="); log.error(e.getMessage()); model.addAttribute("exception", e); return "error_page"; }
여기서 에러를 catch해서 원하는 페이지를 띄어준다.
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <html> <head> <title>error_page</title> </head> <body> <h2 style="background-color: black; color: yellow;">오류발생</h2> <a href="#">백신 프로그램 다운받기</a> <ul style="color: red;"> <c:forEach var="stack" items="${exception.stackTrace}"> <li>${stack}</li> </c:forEach> </ul> </body> </html>
하지만 404같은 문제도 해결해줘야 하는데 404는 에러가 아니기 때문에 여기서 잡을 수 없다. 404를 해결해주기 위해서는 web.xml
에 설정을 추가해줘야 한다.
<servlet> <servlet-name>appServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value> </init-param> <init-param> <param-name>throwExceptionIfNoHandlerFound</param-name> <param-value>true</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
여기서 init-param
throwExceptionIfNoHandlerFound
를 추가해줘야 한다.// 500 메세지는 문법 오류 발생시 @ExceptionHandler를 이용해서 처리가 가능하지만, // 404 메세지는 오류가 아닌 URL, URI를 잘못 호출했을 때 처리해야 한다. // 따라서 서블릿이 web.xml에 간 후 어디로 가야할지 모를때 NoHandlerFoundException을 발생시키도록 // 설정을 해놓고, 실제로 매핑을 못찾을 때 그 예외가 발생되고, 예외발생시 // CommonExceptionAdvice 객체가 잡아준다. 따라서 404 메세지 대신에 원하는 페이지로 // 응답할 수 있게 된다. @ExceptionHandler(NoHandlerFoundException.class) @ResponseStatus(HttpStatus.FOUND) public String handle404(NoHandlerFoundException nhfe) { return "error_404"; }
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>error_404</title> </head> <body> <h2>해당 URL은 존재하지 않습니다.</h2> <a href="./index.jsp">메인으로 돌아가기</a> </body> </html>
스프링 MVC에서 어떤 단계를 거쳐서 실행되는지를 이해해야 문제 발생 시
빠른 대처와 대안을 찾을 수 있다.
웹 프로젝트는 3-tier(티어) 방식으로 구성한다.
Persistance ↔ Business ↔ Presentation
Persistance Tier(영속 계층, 데이터 계층)
- 데이터를 어떤 방식으로 보관하고, 사용하는가에 대한 설계가 들어가는 계층
- 일반적으로 DB를 많이 이용하지만, 상황에 따라서 네트워크 호출 혹은 원격 호출 등의 기술이 접목된다.
Business Tier(비즈니스 계층)
- 순수한 비즈니스 로직을 담고 있는 영역
- 고객(외주업체)이 원하는 요구사항을 반영하는 계층이기 때문에 중요한 영역이다.
- 이 영역의 설계는 고객의 요구 사항과 정확히 일치해야 하며,
~~~Service
와 같은 이름으로 구성한다.
Presentation Tier(화면 계층)
- 데이터를 어떤 방식으로 보관하고, 사용하는가에 대한 설계가 들어가는 계층
- 화면에 보여주는 기술을 사용하는 영역
- JSP/Servlet 혹은 스프링 MVC가 담당하는 영역이며 화면 구성이 이에 속한다.
각 영역은 독립적으로 설계되어 나중에 특정한 기술이 변하더라도 필요한 부분을 전자제품의 부품처럼 쉽게 교환할 수 있게 하자는 방식이다. 각 연결 부위는 인터페이스를 이용해서 설계하는 것이 일반적인 구성 방식이다.
스프링 MVC 영역은 Presentation Tier를 구성하게 되는데, 각 영역은 사실 별도의 설정을 가지는 단위로 볼 수 있습니다. 이전 예제에서는 root-context, servlet-context등의 설정 파일이 해당 영역의 설정을 담당하였습니다. 스프링 Core 영역은 흔히 POJO의 영역입니다. 스프링 의존성 주입을 이용해서 객체 간의 연관구조를 완성해서 사용합니다. Mybatis 영역은 현실적으로는 mybatis-spring을 이용해서 구성하는 영역입니다. SQL에 대한 처리를 담당하는 구조입니다.