前面学习过struts2的异常处理,今天来看下spring mvc4的异常处理:
一、Servlet配置文件修改1
2 class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
3
4
5
6 errors/error
7
8
9
增加上面这一节,大意是:只要有异常就跳到/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
2
3 Exception e = (Exception) request.getAttribute("ex");
4 %>
5
6
7
师傅,有妖怪:error8
9
10
11 错误:
12
13
14 错误描述:
15
16
17
18 详细信息:
19
20
21
22 e.printStackTrace(new java.io.PrintWriter(out));
23 %>
24
25
26
上面的内容只是示意,大家可以根据需要自行美化
另:前文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配置文件中注册:
spring mvc的拦截器提供了4个处理方法:
preHandle在Controller被调用前,先执行,可以在这里执行一些安全检查(上面示意了如何对IP做限制)
postHandle在Controller调用后执行,这时,可以修改ModelAndView,比如转到其它view之类
afterCompletion在Controller调用全部完成后执行,如果ex变量不为空,表示有异常了,这里可以记录异常日志
afterConcurrentHandlingStarted这个没怎么研究过,暂时不做评价
值得一提的是:spring-mvc中的拦截器,虽然可以在afterCompletion中记录异常日志,但如果按前面的baseController配合@ExceptionHandler做了处理,这里的ex就变成了null,因为异常在前面已经得到了处理,所以这二种方法不推荐混用,另外afterCompletion方法中,如果要根据不同的异常类型转到不同处理页面,并不方便。