SimpleMappingExceptionResolver를 통한 간단한 예외 처리 방법
해당 포스팅에서는 Spring MVC에서 간단하게 예외를 처리하기 위해 사용되는 'SimpleMappingExceptionResolver' 클래스의 사용 방법 및 확장 방법에 대해서 정리하였습니다.
SimpleMappingExceptionResolver의 경우 스프링 MVC 모델에서 주로 사용된다는 점과 Spring 3.2부터 도입된 더 효율적이고 유연한 예외 처리 방식인 @ExceptionHandler @ControllerAdvice가 등장하면서 최근에는 거의 사용되지 않는데요.
잘 사용되지 않는 기능이지만 유지보수 등으로 인해 찾는 경우가 있을 것 같아 간단하게 정리해 보게 되었습니다.
사용 방법
public interface HandlerExceptionResolver {
ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex);
}
(HandlerExceptionResolver interface)
DispatcherServlet은 컨트롤러에서 발생한 예외를 처리하기 위해 ExceptionResolver를 사용하는데요.
SimpleMappingExceptionResolver은 예외를 처리하기 위한 가장 기본 인터페이스인 HandlerExceptionResolver를 구현한 구현체 중 하나로, 예외가 발생했을 때 해당 예외에 매핑된 뷰로 포워딩해 주는 기능을 제공합니다.
SimpleMappingExceptionResolver를 적용하는 방법은 xml 파일을 통해 해당 구현체를 bean으로 등록하거나, 또는 java config를 통해 bean으로 등록하면 되는데요.
<!-- SimpleMappingExceptionResolver -->
<beans:bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 예외 클래스와 해당 예외가 발생했을 때 렌더링할 뷰 페이지를 매핑 -->
<beans:property name="exceptionMappings">
<beans:props>
<beans:prop key="java.lang.NullPointerException">error/null_pointer</beans:prop>
<beans:prop key="java.lang.ArithmeticException">error/arithmetic</beans:prop>
</beans:props>
</beans:property>
<!-- exceptionMappings 속성의 목록에 없는 예외가 발생했을 때 렌더링할 기본 뷰 페이지를 매핑 -->
<beans:property name="defaultErrorView" value="error/default_error" />
<!-- exception의 정보를 담을 객체의 key 값, defaultValue = "exception" -->
<beans:property name="exceptionAttribute" value="exception" />
<!-- 각 뷰 페이지에 대한 statusCode -->
<beans:property name="statusCodes">
<beans:props>
<beans:prop key="error/null_pointer">412</beans:prop>
<beans:prop key="error/arithmetic">413</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
먼저 위 xml 파일을 통한 방식의 세부 내용을 살펴보면 크게 'exceptionMappings', 'defaultErrorView', 'exceptionAttribute', 'statusCodes' 속성이 존재하는데요.
(위 속성 외에도 필요에 따라 적용할 수 있는 다른 속성들도 있습니다.)
exceptionMappings 속성은 예외 클래스와 해당 예외가 발생했을 때 보여줄 뷰 페이지를 매핑합니다.
defaultErrorView 속성의 경우 exceptionMappings 속성 목록에 없는 예외가 발생했을 때 포워딩되는 뷰 페이지를 설정할 수 있습니다.
statusCodes 속성의 경우 각 뷰 페이지가 응답될 때의 statusCode를 설정할 수 있으며, exceptionAttribute 속성을 통해 exception의 정보를 담을 객체의 키 값을 지정할 수 있습니다.
@Bean
public SimpleMappingExceptionResolver createSimpleMappingExceptionResolver() {
SimpleMappingExceptionResolver smer = new SimpleMappingExceptionResolver();
// exceptionMappings
Properties mappings = new Properties();
mappings.setProperty("NullPointerException", "error/null_pointer");
mappings.setProperty("ArithmeticException", "error/arithmetic");
smer.setExceptionMappings(mappings);
// statusCodes
Properties statusCodes = new Properties();
statusCodes.setProperty("error/null_pointer", "555");
statusCodes.setProperty("error/arithmetic", "666");
smer.setStatusCodes(statusCodes);
// defaultErrorView && defaultStatusCode
smer.setDefaultErrorView("error/default_error");
smer.setDefaultStatusCode(200);
// exceptionAttribute
smer.setExceptionAttribute("exception");
// excludedExceptions
smer.setExcludedExceptions(ArrayIndexOutOfBoundsException.class);
return smer;
}
다음으로 java config를 통한 빈 등록 방식이며, 앞서 xml 파일에서 설정했던 속성들을 동일하게 적용할 수 있습니다.
(defaultStatusCode, excludedExceptions 속성 역시 xml에서 형식에 맞춰 동일하게 적용할 수 있습니다.)
<!-- 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>
SimpleMappingExceptionResolver를 통해 반환된 뷰 페이지는 InternalResourceViewResolver의 prefix, suffix를 적용하여 실제 뷰 파일의 경로인 '/WEB-INF/views/error/페이지.jsp'를 찾아 렌더링 하게 됩니다.
SimpleMappingExceptionResolver 문제점 및 확장
SimpleMappingExceptionResolver를 사용하는 경우 Exception이 발생했을 때, 매핑된 예외 페이지로 이동은 하지만 예외에 대한 로그가 찍히지 않는다는 문제점이 있는데요.
(정확하게는 위 이미지에서 보이는 것처럼 DEBUG 레벨의 로그로 예외 내용이 남습니다.)
이러한 부분을 개선하기 위해 아래와 같이 해당 클래스를 확장하여 사용할 수 있습니다.
public class CustomMappingExceptionResolver extends SimpleMappingExceptionResolver {
private static final Logger log = LoggerFactory.getLogger(CustomMappingExceptionResolver.class.getName());
// 실제로 핸들러 실행 중에 발생한 예외를 해결하고, 적절한 경우 특정 오류 페이지를 나타내는 ModelAndView를 반환합니다.
@Override
protected ModelAndView doResolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
log.error("CustomSimpleMappingExceptionResolver: " + ex);
// Call super method to get the ModelAndView
ModelAndView mav = super.doResolveException(request, response, handler, ex);
// Make the full URL available to the view - note ModelAndView uses
// addObject() but Model uses addAttribute(). They work the same.
mav.addObject("url", request.getRequestURL());
return mav;
}
}
위 코드와 같이 예외 처리 기능의 핵심이 되는 doResolverException() 메서드를 오버라이딩하여 기능을 확장할 수 있으며, 예외에 대한 로깅 말고도 포워딩 기능 외 다른 세부적인 처리 로직을 추가하고 싶은 경우 이러한 확장 클래스를 이용할 수 있습니다.
< 참고 자료 >
'Programming > Spring' 카테고리의 다른 글
파일 업로드 시 net::ERR_CONNECTION_RESET 오류 발생 원인 및 해결 방법 (0) | 2025.01.30 |
---|---|
(MyBatis) include refid 용도 및 사용 방법 (3) | 2024.12.14 |
Logback PatternLayout을 통한 로그 마스킹 처리 방법 (1) | 2024.11.02 |
(spring project) log4j2 로그 파일 분리하기 (1) | 2024.08.25 |
MyBatis SQL Injection 발생하는 상황 및 방어 방법 (0) | 2024.04.10 |