本文算是struts2 异常处理3板斧、spring mvc4:异常处理 后续篇章,普通页面出错后可以跳到统一的错误处理页面,但是ajax就不行了,ajax的本意就是不让当前页面发生跳转,仅局部刷新,从而改善用户体验,基本思路是:把异常转换成json数据返回,这样ajax的回调函数,就能解析出错误原因。
一、如何区分ajax请求与普通请求
打开firefox的调试工具观察一下:
普通的页面请求
jquery发起的ajax请求
对比一下,可以发现jquery发生的ajax请求,Request Headers里多出了x-requested-with,用它就可以判断是否ajax请求。
二、struts2框架
a) 先定义一个ajax通用异常
代码语言:javascript复制 1 package com.cnblogs.yjmyzz.exception;
2
3 public class AjaxException extends Exception {
4
5 private static final long serialVersionUID = -8503861588580421151L;
6
7 public AjaxException(String message) {
8 super(message);
9 }
10
11 }
b) 然后修改异常拦截器
代码语言:javascript复制 1 package com.cnblogs.yjmyzz.interceptor;
2 import javax.servlet.http.HttpServletRequest;
3
4 import org.apache.logging.log4j.*;
5 import org.apache.struts2.ServletActionContext;
6 import org.springframework.util.StringUtils;
7 import com.cnblogs.yjmyzz.exception.AjaxException;
8 import com.opensymphony.xwork2.*;
9 import com.opensymphony.xwork2.interceptor.*;
10
11 public class ExceptionInterceptor extends AbstractInterceptor {
12
13 private static final long serialVersionUID = -6358803554282730952L;
14 Logger logger = LogManager.getLogger();
15
16 @Override
17 public String intercept(ActionInvocation ai) throws Exception {
18 String result = null;
19 try {
20 result = ai.invoke();
21 } catch (Exception e) {
22 logger.error(ai.toString(), e);
23 ai.getStack().push(new ExceptionHolder(e));
24 result = "error";
25
26 HttpServletRequest request = ServletActionContext.getRequest();
27 String xRequestedWith = request.getHeader("X-Requested-With");
28 if (!StringUtils.isEmpty(xRequestedWith)) {
29 // ajax请求
30 // 转换成ajax异常,并放入stack中
31 ai.getStack().push(
32 new ExceptionHolder(new AjaxException(e.getMessage())));
33 result = "ajax-error";
34 }
35 }
36 return result;
37 }
38
39 }
c) 修改struts.xml文件
代码语言:javascript复制 1 <package name="base-default" extends="struts-default">
2 <global-results>
3 <result name="ajax-error">/WEB-INF/common/ajax-error.jsp</result>
4 <result name="error">/WEB-INF/common/error.jsp</result>
5 </global-results>
6 <global-exception-mappings>
7 <exception-mapping exception="com.cnblogs.yjmyzz.exception.AjaxException"
8 result="ajax-error" />
9 <exception-mapping exception="java.lang.Exception"
10 result="error" />
11 </global-exception-mappings>
12 </package>
即:返回ajax-error,异常类型为AjaxException,则交给/WEB-INF/common/ajax-error.jsp处理
d) ajax-error.jsp页面
代码语言:javascript复制1 <%@ page contentType="application/json;charset=UTF-8" language="java"%><%@ taglib prefix="s" uri="/struts-tags"%>{"error":"<s:property value="exception" />"}
即:如果出错,最终返回的是json串,类似:{"error":"com.cnblogs.yjmyzz.exception.AjaxException: / by zero"}
e) 然后调用ajax的地方
代码语言:javascript复制 1 $.ajax({
2 type:"GET",
3 url:"${pageContext.request.contextPath}/rest/orders/x",
4 success: function(data, textStatus, jqXHR){
5 if (data.error!=undefined){
6 alert("错误:" data.error);
7 return false;
8 }
9 //正常处理
10 alert("ajax请求成功!");
11 },
12 error: function(jqXHR, textStatus, errorThrown){
13 alert('error: ' textStatus);
14 }
15 });
如果服务端出异常,则ajax调用完成后,会弹出异常信息,否则按正常流程处理
三、Spring MVC4
a) 先修改Controller基类里的异常处理方法
代码语言: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
17 String xRequestedWith = request.getHeader("X-Requested-With");
18 if (!StringUtils.isEmpty(xRequestedWith)) {
19 // ajax请求
20 resultViewName = "errors/ajax-error";
21
22 }
23
24 return resultViewName;
25 }
大致意思是,如果发现是ajax请求,则有异常,则交给"errors/ajax-error"视图处理
b) ajax-error.jsp页面
代码语言:javascript复制1 <%@ page contentType="application/json;charset=UTF-8" language="java"%><%Exception e = (Exception) request.getAttribute("ex");%>{"error":"<%=e.getClass().getSimpleName()%>","detail":"<%=e.getMessage()%>"}
c) 调用ajax的页面
代码语言:javascript复制 1 $.ajax({
2 type:"GET",
3 url:"${pageContext.request.contextPath}/common-exception",
4 success: function(d, textStatus, jqXHR){
5 if (d.error!=undefined){
6 alert("错误:" d.detail);
7 return false;
8 }
9 //其它正常处理
10 alert("ajax请求成功!");
11 },
12 error: function(jqXHR, textStatus, errorThrown){
13 alert('error: ' textStatus);
14 }
15 });
如果服务端返回异常,ajax得到的反馈内容大概是:{"error":"Exception","detail":"系统太累了,需要休息!"}