Programming/Spring

Spring MVC, SimpleMappingExceptionResolver를 통한 간단한 예외 처리 방법

Jan92 2025. 1. 25. 01:13
반응형

SimpleMappingExceptionResolver를 통한 간단한 예외 처리 방법

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에서 형식에 맞춰 동일하게 적용할 수 있습니다.)

 

 

InternalResourceViewResolver

<!-- 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 문제점 및 확장

processHandlerException() method

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() 메서드를 오버라이딩하여 기능을 확장할 수 있으며, 예외에 대한 로깅 말고도 포워딩 기능 외 다른 세부적인 처리 로직을 추가하고 싶은 경우 이러한 확장 클래스를 이용할 수 있습니다.

 

 

 

 

< 참고 자료 >

https://yjksw.github.io/spring-exception-handling/

반응형