We can use multiple HandlerExceptionResolver at a time by using HandlerExceptionResolverComposite.
Following method of HandlerExceptionResolverComposite can be used to specify multiple HandlerExceptionResolvers:
public void setExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers)
In resolveException(...) method, this resolver loops through the provided list of resolvers. The first one to return a ModelAndView instance wins. Otherwise null is returned. Here's the snippet:
public class HandlerExceptionResolverComposite implements HandlerExceptionResolver, Ordered {
private List<HandlerExceptionResolver> resolvers;
....................
public void setExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
this.resolvers = exceptionResolvers;
}
..................
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
if (resolvers != null) {
for (HandlerExceptionResolver handlerExceptionResolver : resolvers) {
ModelAndView mav = handlerExceptionResolver.resolveException(request, response, handler, ex);
if (mav != null) {
return mav;
}
}
}
return null;
}
}
Note that, if any of the the provided HandlerExceptionResolver, implements Ordered interface, then the order returned from Ordered#getOrder is not used to sort the provided resolvers. The resolvers are iterated in list's insertion order. So what is the use of Ordered#getOrder()? It is actually used in the DispatcherServlet to iterate through the default and registered exception resolvers. (in the next tutorial we will look into that with an example).
In following example we are going to set two HandlerExceptionResolvers with HandlerExceptionResolverComposite, one from our last tutorial example which is a custom resolver and other will be SimpleMappingExceptionResolver.
Example
Registering HandlerExceptionResolvers in JavaConfig class
@EnableWebMvc
@ComponentScan("com.logicbig.example")
public class AppConfig {
@Bean
HandlerExceptionResolver exceptionResolverComposite () {
//the custom resolver from last example
HandlerExceptionToViewResolver r = new HandlerExceptionToViewResolver();
SimpleMappingExceptionResolver s = new SimpleMappingExceptionResolver();
s.setDefaultErrorView("default-error-page");
Properties p = new Properties();
p.setProperty(IllegalAccessException.class.getName(), "simple-test-error-view");
s.setExceptionMappings(p);
HandlerExceptionResolverComposite c = new HandlerExceptionResolverComposite();
c.setExceptionResolvers(Arrays.asList(r, s));
return c;
}
.......
}
The Controller
@Controller
public class ExampleController {
//should be handled by our custom resolver because of @ErrorView
@ErrorView(value = "test-error-view", status = HttpStatus.GONE)
@RequestMapping("/test1")
public String handleRequest () throws Exception {
throw new Exception("test exception 1");
}
//should be handled by handleException() because of @ExceptionHandler.
//Default resolvers are processed before application registered ones
@RequestMapping("/test2")
public String handleRequest2 () throws Exception {
throw new OperationNotSupportedException("test exception 2");
}
//should be handled by SimpleMappingExceptionResolver's default view
@RequestMapping("/test3")
public String handleRequest3 () throws Exception {
throw new Exception("test exception 3");
}
//should be handled by SimpleMappingExceptionResolver:
//IllegalAccessException is mapped to 'test-error-view'
@RequestMapping("/test4")
public String handleRequest4 () throws Exception {
throw new IllegalAccessException("test exception 4");
}
//should be handled by our custom resolver even though IllegalAccessException
//is mapped in SimpleMappingExceptionResolver. Reasons is: in iteration order
// our custom resolver is first to process
@ErrorView(value = "test-error-view", status = HttpStatus.FORBIDDEN)
@RequestMapping("/test5")
public String handleRequest5 () throws Exception {
throw new IllegalAccessException("test exception 5");
}
@ExceptionHandler
@ResponseBody
public String handleException (OperationNotSupportedException e) {
return "exception :" + e.toString();
}
}
JSP pages
src/main/webapp/WEB-INF/views/test-error-view.jsp
<%@ page language="java"
contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<html>
<body>
<h3>Test Error View</h3>
<p>Request Uri: <b>${requestUri}</b></p>
<p>Exception: <b>${exception['class'].name}</b></p>
<p>Message: <b>${exception.message}</b></p>
<p>Response status: <b>${statusValue} (${statusStr})</b></p>
</body>
</html>
src/main/webapp/WEB-INF/views/simple-test-error-view.jsp
<%@ page language="java"
contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<html>
<body>
<h3>Simple Test Error View</h3>
<p>Exception: <b>${exception['class'].name}</b></p>
<p>Message: <b>${exception.message}</b></p>
</body>
</html>
src/main/webapp/WEB-INF/views/default-error-page.jsp
<%@ page language="java"
contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<html>
<body>
<h3>This is the default exception page</h3>
<p>Exception: <b>${exception['class'].name}</b></p>
<p>Message: <b>${exception.message}</b></p>
</body>
</html>
Run embedded tomcat
mvn tomcat7:run-war
output
/test1
/test2
/test3
/test4
/test5
Example ProjectDependencies and Technologies Used: - spring-webmvc 4.3.5.RELEASE: Spring Web MVC.
- javax.servlet-api 3.0.1 Java Servlet API
- JDK 1.8
- Maven 3.3.9
|