In some badly coded applications, when an unknown exception occurs the application server usually displays the evil exception stack trace to the user in the webpage itself. In this case, users have nothing to do with this stack trace and complain that your application is not user-friendly. Moreover, it can also prove a potential security risk, as you are exposing the internal method call hierarchy to users. Though a web application’s web.xml
can be configured to display friendly JSP pages in case an HTTP error or class exception occur, Spring MVC supports a more robust approach to managing views for class exceptions.
1. Spring HandlerExceptionResolver and SimpleMappingExceptionResolver
In a Spring MVC application, you can register one or more exception resolver beans in the web application context to resolve uncaught exceptions. These beans have to implement the HandlerExceptionResolver
interface for DispatcherServlet
to auto-detect them. Spring MVC comes with such a simple exception resolver i.e. SimpleMappingExceptionResolver
to map each category of exceptions to a view in a configurable way.
Let’s say we have an exception class i.e. AuthException
. And we want that every time this exception is thrown from anywhere into the application, we want to show a pre-determined view page /WEB-INF/views/error/authExceptionView.jsp
. So the configuration would be:
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="com.howtodoinjava.demo.exception.AuthException">
error/authExceptionView
</prop>
</props>
</property>
<property name="defaultErrorView" value="error/genericView"/>
</bean>
The complete context configuration is :
applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context/
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.howtodoinjava.demo" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages" />
</bean>
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="com.howtodoinjava.demo.exception.AuthException">
error/authExceptionView
</prop>
</props>
</property>
<property name="defaultErrorView" value="error/genericView"/>
</bean>
</beans>
Notice the “defaultErrorView” property in the last. If spring context detects any exception thrown from an application that is not listed in “exceptionMappings” properties list, then it will render the view /WEB-INF/views/error/genericView.jsp
.
2. Demo
For testing purposes, let’s create AuthException.java
.
AuthException.java
public class AuthException extends RuntimeException {
private Date date;
private String message;
//Setters and Getters
}
And throw this exception from any controller.
EmployeeController.java
@Controller
@RequestMapping("/employee-module")
public class EmployeeController
{
@RequestMapping(value="/getAllEmployees", method = RequestMethod.GET)
public String welcome(Model model)
{
throw new AuthException(new Date(), "Something bad happened dude !! Run Away :-(");
}
}
And create two jsp files in path /WEB-INF/views/error/
authExceptionView.jsp
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title>Authentication Exception</title>
</head>
<body>
<h2>Exception occured at: </h2><fmt:formatDate value="${exception.date}" pattern="yyyy-MM-dd" />
<h2>Exception Message : </h2>${exception.message}
</body>
</html>
genericView.jsp
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<html>
<head>
<title>Generic Exception</title>
</head>
<body>
<h2>Some generic error message</h2>
</body>
</html>
And now hit the URL: http://localhost:8080/springmvcexample/employee-module/getAllEmployees

Now throw any other exception from the controller such as NullPointerException
as below.
@Controller
@RequestMapping("/employee-module")
public class EmployeeController
{
@RequestMapping(value="/getAllEmployees", method = RequestMethod.GET)
public String welcome(Model model)
{
throw new NullPointerException();
}
}
And hit again the URL: http://localhost:8080/springmvcexample/employee-module/getAllEmployees

Clearly, the application is now able to find correct views in case of exceptions. No more error stack traces in the front view.
Happy Learning !!
Comments