前面学习过struts2的异常处理,今天来看下spring mvc4的异常处理:
一、Servlet配置文件修改
1 <bean id="exceptionResolver" 2 class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> 3 <property name="defaultErrorView" value="errors/error" /> 4 <property name="exceptionMappings"> 5 <props> 6 <prop key="java.lang.Throwable">errors/error</prop> 7 </props> 8 </property> 9 </bean>
增加上面这一节,大意是:只要有异常就跳到/WEB-INF/views/errors/error.jsp这个页面,当然如果要实现个性化的错误处理,比如:业务错误跳到页面A,SQL错误跳到页面B...,直接在props节点下,根据不同的异常类型,自行扩充 (注:404之类的错误,仍然参考struts2异常处理中的做法,在web.xml中配置解决)
二、创建一个BaseController基类,里面放一个以下方法:
1 @ExceptionHandler 2 public String exp(HttpServletRequest request, Exception ex) { 3 String resultViewName = "errors/error"; 4 5 // 记录日志 6 logger.error(ex.getMessage(), ex); 7 8 // 根据不同错误转向不同页面 9 if (ex instanceof BusinessException) { 10 resultViewName = "errors/biz-error"; 11 } else { 12 // 异常转换 13 ex = new Exception("系统太累了,需要休息!"); 14 } 15 request.setAttribute("ex", ex); 16 return resultViewName; 17 }
记录异常日志、根据不同的异常类型转到不同的处理页面、友好异常转换(如果需要的话),都在上面的方法中处理了
三、所有Controller都继承自BaseController
这个,就不解释了
四、error.jsp页面
1 <%@ page contentType="text/html;charset=UTF-8" language="java"%> 2 <% 3 Exception e = (Exception) request.getAttribute("ex"); 4 %> 5 <html> 6 <head> 7 <title>师傅,有妖怪:error</title> 8 </head> 9 <body> 10 <H2> 11 错误:<%=e.getClass().getSimpleName()%></H2> 12 <hr /> 13 <P> 14 <strong>错误描述:</strong><%=e.getMessage()%> 15 </P> 16 17 <P> 18 <strong>详细信息:</strong> 19 </P> 20 <pre> 21 <% 22 e.printStackTrace(new java.io.PrintWriter(out)); 23 %> 24 </pre> 25 </body> 26 </html>
上面的内容只是示意,大家可以根据需要自行美化
另:前文struts2的异常处理中,采用的是拦截器思想,spring mvc中也有拦截器,而且拦截的点更灵活:
1 package com.cnblogs.yjmyzz.interceptor; 2 3 import javax.servlet.http.HttpServletRequest; 4 import javax.servlet.http.HttpServletResponse; 5 6 import org.apache.logging.log4j.LogManager; 7 import org.apache.logging.log4j.Logger; 8 import org.springframework.web.servlet.ModelAndView; 9 import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; 10 11 public class ExcpetionInterceptor extends HandlerInterceptorAdapter { 12 13 protected Logger logger = LogManager.getLogger(); 14 15 @Override 16 public boolean preHandle(HttpServletRequest request, 17 HttpServletResponse response, Object handler) throws Exception { 18 System.out.println("ExcpetionInterceptor.preHandle"); 19 // 演示:限制仅允许从本机访问 20 if (request.getLocalAddr().equals("127.0.0.1") 21 || request.getLocalAddr().equals("0.0.0.0")) { 22 return true; 23 } 24 logger.error("非法入侵:" + request.getLocalAddr()); 25 return false; 26 } 27 28 @Override 29 public void postHandle(HttpServletRequest request, 30 HttpServletResponse response, Object handler, 31 ModelAndView modelAndView) throws Exception { 32 System.out.println("ExcpetionInterceptor.postHandle"); 33 } 34 35 @Override 36 public void afterCompletion(HttpServletRequest request, 37 HttpServletResponse response, Object handler, Exception ex) 38 throws Exception { 39 System.out.println("ExcpetionInterceptor.afterCompletion"); 40 if (ex != null) { 41 logger.error(handler); 42 logger.error(ex.getMessage(), ex); 43 } 44 } 45 46 @Override 47 public void afterConcurrentHandlingStarted(HttpServletRequest request, 48 HttpServletResponse response, Object handler) throws Exception { 49 System.out 50 .println("ExcpetionInterceptor.afterConcurrentHandlingStarted"); 51 } 52 53 }
拦截器创建后,依然要在servlet配置文件中注册:
<mvc:interceptors> <bean class="com.cnblogs.yjmyzz.interceptor.ExcpetionInterceptor"></bean> </mvc:interceptors>
spring mvc的拦截器提供了4个处理方法:
preHandle在Controller被调用前,先执行,可以在这里执行一些安全检查(上面示意了如何对IP做限制)
postHandle在Controller调用后执行,这时,可以修改ModelAndView,比如转到其它view之类
afterCompletion在Controller调用全部完成后执行,如果ex变量不为空,表示有异常了,这里可以记录异常日志
afterConcurrentHandlingStarted这个没怎么研究过,暂时不做评价
值得一提的是:spring-mvc中的拦截器,虽然可以在afterCompletion中记录异常日志,但如果按前面的baseController配合@ExceptionHandler做了处理,这里的ex就变成了null,因为异常在前面已经得到了处理,所以这二种方法不推荐混用,另外afterCompletion方法中,如果要根据不同的异常类型转到不同处理页面,并不方便。
附:ajax的统一异常处理,请移步 Struts2、Spring MVC4 框架下的ajax统一异常处理