本文算是struts2 异常处理3板斧、spring mvc4:异常处理 后续篇章,普通页面出错后可以跳到统一的错误处理页面,但是ajax就不行了,ajax的本意就是不让当前页面发生跳转,仅局部刷新,从而改善用户体验,基本思路是:把异常转换成json数据返回,这样ajax的回调函数,就能解析出错误原因。
一、如何区分ajax请求与普通请求
打开firefox的调试工具观察一下:
普通的页面请求
jquery发起的ajax请求
对比一下,可以发现jquery发生的ajax请求,Request Headers里多出了x-requested-with,用它就可以判断是否ajax请求。
二、struts2框架
a) 先定义一个ajax通用异常
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) 然后修改异常拦截器
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文件
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页面
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的地方
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基类里的异常处理方法
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页面
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的页面
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":"系统太累了,需要休息!"}