前面学习过struts2的异常处理,今天来看下spring mvc4的异常处理:
一、Servlet配置文件修改
代码语言:javascript复制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基类,里面放一个以下方法:
代码语言:javascript复制 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页面
代码语言:javascript复制 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中也有拦截器,而且拦截的点更灵活:
代码语言:javascript复制 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配置文件中注册:
代码语言:javascript复制 <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统一异常处理