本文算是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":"系統太累了,需要休息!"}