반응형

Controller를 작성할 때 예외 상황을 고려하면 처리해야 하는 작업이 엄청나게 늘어날 수 밖에 없습니다. 스프링 MVC에서는 이러한 작업을 다음과 같은 방식으로 처리할 수 있습니다.

 

- @ExceptionHandler와 @ControllerAdvice를 이용한 처리

- @ResponseEntity를 이용하는 예외 메시지 구성

 

@ControllerAdvice

@ControllerAdvice는 나중에 알게되는 AOP(Aspect-Oriented-Programming)를 이용하는 방식입니다. AOP에 대해서는 별도의 파트에서 설명하겠지만, 간단히 언급하자면 핵심적인 로직은 아니지만 프로그램에서 필요한 '공통적인 관심사(cross-concern)는 분리'하자는 개념입니다. Controller를 작성할 때는 메서드의 모든 예외사항을 전부 핸들링 해야 한다면 중복적이고 많은 양의 코드를 작성해야 하지만, AOP방식을 이용하면 공통적인 예외사항에 대해서는 별도로 @ControllerAdvice를 이용해서 분리하는 방식입니다.

 

예제를 위해 프로젝트에 패키지를 생성하고, CommonExceptionAdvice 클래스를 생성하겠습니다.

CommonExceptionAdvice는 @ControllerAdvice 어노테이션을 적용하지만 예외 처리를 목적으로 생성하는 클래스이므로 별도의 로직을 처리하지는 않습니다.

package org.zerock.exception;

import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import lombok.extern.log4j.Log4j;

@ControllerAdvice
@Log4j
public class CommonExceptionAdvice {
	
	@ExceptionHandler(Exception.class)
	public String except(Exception ex, Model model) {
		log.error("Exception.........." + ex.getMessage());
		model.addAttribute("exception", ex);
		log.error(model);
		return "error_page";
	}
}

   CommonExceptionAdvice 클래스에는 @ControllerAdvice라는 어노테이션과 @ExceptionHandler라는 어노테이션을 사용하고 있습니다. @ControllerAdvice는 해당 객체가 스프링의 컨트롤러에서 발생하는 예외를 처리하는 존재임을 명시하는 용도로 사용하고, @ExceptionHandler는 해당 메서드가 () 들어가는 예외 타입을 처리한다는 것을 의미합니다. @ExceptionHandler 어노테이션의 속성으로는 Exception 클래스 타입을 지정할 수 있습니다. 위와 같은 경우 Exception.class를 지정하였으므로 모든 예외에 대한 처리가 except()만을 이용해서 처리할 수 있습니다.

 

  만일 특정한 타입의 예외를 다루고 싶다면 Exception.class 대신에 구체적인 예외의 클래스를 지정해야 합니다. JSP화면에서도 구체적인 메시지를 보고 싶다면 Model을 이용해서 전달하는 것이 좋습니다. org.zerock.exception 패키지는 servlet-context.xml에 인식하지 않기 때문에 <component-scan>을 이용해서 해당패키지의 내용을 조사하도록 해야 합니다.

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

	<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
	
	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven />

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
	<resources mapping="/resources/**" location="/resources/" />

	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>
	
	<beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<beans:property name="defaultEncoding" value="utf-8"></beans:property>
		
		<!--  1024 * 1024 * 10 bytes 10MB -->
		<beans:property name="maxUploadSize" value="104857560"></beans:property>
		<!--  1024 * 1024 * 2 bytes 2MB -->
		<beans:property name="maxUploadSizePerFile" value="2097152"></beans:property>
		
		<beans:property name="uploadTempDir" value="file:/C:/upload/tmp"></beans:property>
		<beans:property name="maxInMemorySize" value="10485756"></beans:property>
	</beans:bean>
	
	<context:component-scan base-package="org.zerock.controller" />
	<context:component-scan base-package="org.zerock.exception" />
	
	
	
	
</beans:beans>

CommonExceptionAdvice의 except()의 리턴값은 문자열이므로 JSP파일의 경로가 됩니다. JSP는 error_page.jsp이므로 /WEB-INF/views 폴더 내에 작성해야 합니다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

	<h4>
		<c:out value="${exception.getMessage()}"></c:out>
	</h4>

	<ul>
		<c:forEach items="${exception.getStackTrace()}" var="stack">
			<li><c:out value="${stack}"></c:out></li>
		</c:forEach>
	</ul>
</body>
</html>

예외의 메시지가 정상적으로 출력되는지 확인해 보려면 고의로 숫자나 날짜 등의 파라미터 값을 변환에 문제 있게 만들어서 호출해 볼 수 있습니다. 예를 들어, '/sample/ex-94?name=aaa&age=11&page=9'와 호출해야 하는 URL에서 고의로 age 값을 숫자로 변환할 수 없게 다른 값을 전달해 보거나 page와 같은 파라미터를 생략하는 등의 작업을 통해서 확인할 수 있습니다. 

 

 

반응형

'2020 > 주저리 주저리 타이핑.. 낙서장.' 카테고리의 다른 글

스프링 MVC 프로젝트의 기본 구성  (0) 2020.05.11
404 에러 페이지  (0) 2020.05.11
파일 업로드 처리  (0) 2020.05.08
Controller의 리턴 타입  (0) 2020.05.06
RedirectAttributes  (0) 2020.05.06
블로그 이미지

꽃꽂이하는개발자

,