Spring MVC – Catch the exceptions thrown by view page

Here’s the scenario, the controller returns a ModelAndView, and an exception is thrown while rendering the JSP view page, reason behind is one of message code is not found.


org.apache.jasper.JasperException: org.springframework.context.NoSuchMessageException: 
	No message found under code 'Diff.userform.password' for locale 'en_US'.
	
	org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:549)
	org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:470)
	org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
	org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:722)

An exception is thrown and render an HTTP 500 error page directly.

1. Problem

Declared an exception handler globally, but still unable to catch the NoSuchMessageException?


@ControllerAdvice
public class GlobalExceptionHandler {

	private final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
	
	@ExceptionHandler(value = Exception.class)
	public ModelAndView defaultErrorHandler(HttpServletRequest req, 
               Exception e) throws Exception {
		
		logger.error("[URL] : {}", req.getRequestURL(), e);
		
		ModelAndView mav = new ModelAndView();
		mav.addObject("exception", e);
		mav.addObject("url", req.getRequestURL());
		mav.setViewName("error"");
		return mav;
	}
	
}

2. Solution

No, you can’t catch the exception which is thrown by the view page. The @ExceptionHandler is used to catch the exceptions thrown by the Controller class only.

The best you can do is defined an error page in web.xml

web.xml

	<!-- This will catch Http 500 error -->
	<error-page>
	    <error-code>500</error-code>
	    <location>/WEB-INF/views/jsp/error.jsp</location>
	</error-page>
	
	<!-- This will catch any exception -->
	<error-page>
	    <location>/WEB-INF/views/jsp/error.jsp</location>
	</error-page>
Note
Tell me if you have a better solution :)

3. Servlet Filter

Alternatively, you can create a filter and intercepts the entire requests on your web application. If any exceptions are thrown, log it or do whatever you want.


package com.mkyong.form.web;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.mkyong.form.service.UserService;

public class ErrorHandleFilter implements Filter {

	private final Logger logger = LoggerFactory.getLogger(ErrorHandleFilter.class);
	
	//Your custom bean to handle error
	ErrorHandlerSpecialForce errHandle;
	
	@Override
	public void destroy() {
		// ...
	}

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		//Get bean from Spring container
		errHandle = (ErrorHandlerSpecialForce) WebApplicationContextUtils
		  .getRequiredWebApplicationContext(filterConfig.getServletContext())
                  .getBean("errorHandlerSpecialForce");
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain)
			throws IOException, ServletException {

		try {
                        // your code, do whatever
			errHandle.handle(request, response); 
			
			chain.doFilter(request, response);
			
		} catch (Exception ex) {
		
			logger.error("Error : {}", ex); //log it
			request.setAttribute("errorMessage", ex);
			request.getRequestDispatcher("/WEB-INF/views/jsp/error.jsp")
				.forward(request, response);
			
		}

	}

}

To register above filter, declares it in web.xml

web.xml

	<!-- must register this, else WebApplicationContext not found -->
	<listener>
		<listener-class>
                     org.springframework.web.context.ContextLoaderListener
                </listener-class>
	</listener>
	
	<filter>
		<filter-name>errorHandlerFilter</filter-name>
		<filter-class>com.mkyong.form.web.ErrorHandleFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>errorHandlerFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

Or declares it in an initializer class.


package com.mkyong.form.config.servlet3;
 
import javax.servlet.Filter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import com.mkyong.form.web.ErrorHandleFilter;
 
public class MyWebInitializer extends
	AbstractAnnotationConfigDispatcherServletInitializer {
 
	//...
 
	@Override
	protected Filter[] getServletFilters() {
		return new Filter[]{new ErrorHandleFilter()};
	}
}

References

  1. Exception Handling in Spring MVC
  2. How to register a servlet filter in Spring MVC

About the Author

author image
mkyong
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter. If you like my tutorials, consider make a donation to these charities.

Comments

avatar
1 Comment threads
0 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
1 Comment authors
graduategamers Recent comment authors
newest oldest most voted
graduategamers
Guest
graduategamers

The way your website helps me, I cant even explain. On top there with StackOverflow.