大家都知道,使用struts2的异常处理机制,只要几行配置,就可以在发生异常时,跳转到我们指定的页面,并显示出相应的异常信息,具体的使用操作过程如下:
1)struts.xml
<struts> <include file="struts-default.xml"></include> <constant name="struts.devMode" value="true" /><!-- 实现国际化资源文件和struts配置文件自动重新加载,不需要重启服务器 --> <constant name="struts.ui.theme" value="simple" /> <constant name="struts.action.extension" value="," /><!-- 不要后缀 --> <constant name="struts.enable.SlashesInActionNames" value="true" /><!-- 使用"/"的方式 --> <package name="hatch" namespace="" extends="json-default"><!-- json支持 --> ... <!-- 定义全局视图 --> <global-results> <result name="login" type="redirectAction">login</result> <result name="404">/WEB-INF/view/404.jsp</result> <result name="500">/WEB-INF/view/500.jsp</result> </global-results> <!-- 定义全局异常--> <global-exception-mappings> <exception-mapping result="500" exception="java.lang.Exception"/><!-- 出现异常时,将页面转到500这个错误页面 --> </global-exception-mappings> ... </struts>
2)500.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>程序异常</title> <%@include file="/WEB-INF/view/common/common.jspf" %> <style type="text/css"> *{margin:0;padding:0;} .errTitle{min-width:300px;width:90%;height:50px;line-height:50px;border:1px solid #999999;border-radius:5px;background:#0169B2;text-align:center;word-spacing:10px;font-family:'黑体';font-size:24px;margin:10px 70px;padding: 4px 4px 4px 6px;position:relative;} .showErrWrap{font-size:10px;position:absolute;right:10px;bottom:-5px;} .showErrWrap a:link,.showErrWrap a:visited{text-decoration:none;color:black;} .showErrWrap a:hover{text-decoration:underline;color:yellow;} .showErrWrap span{margin:0 4px;color:black;} .errStack{min-width:300px;width:90%;font-family:"Courier New", Courier, monospace;border:0 none;margin:10px 70px;overflow:auto;padding:4px;} </style> <script type="text/javascript"> $(function(){ $('#showErrBtn').toggle(function(){ $('#showErrBtn').text('关闭详情'); $('.errStack').slideDown('normal'); },function(){ $('.errStack').slideUp('normal'); $('#showErrBtn').text('查看详情'); }); }); if (window.parent != window) { window.parent.location.href = window.location.href; } </script> </head> <body> <div class="errTitle">程 序 出 现 异 常!<span class="showErrWrap"><a href="javascript:void(0);" id="showErrBtn">查看详情</a><span>|</span><a href="javascript:void(0);" onclick="javascript:history.go(-1);">返回上一页</a></span></div> <div class="errStack" style="display:none;"><pre> <s:property value="exceptionStack"/><!-- 异常信息 --> </pre> </div> </body> </html>
假设在UserAction.java中有一个跳转到列表页面的方法,如下:
/* 用户列表视图 */ public String list() { int i = 10/0; return "list"; }
这样,在出现异常时,就能到这个页面了,效果大约是下面的样子:
但现在我很多请求处理,使用的都是ajax提交请求并获取数据的方式,这种情况下,默认的异常处理就力不从心了。跑个题儿先,稍微介绍下struts2中ajax请求的配置方式,以下以用户列表为例:
1)添加jar包支持:struts2-json-plugin-2.3.4.jar
2)在自己的struts.xml中,package继承json-default
3)返回类型为json
4)Action中添加设置返回的数据的值
如下是配置:
<struts> <constant name="struts.devMode" value="true" /><!-- 实现国际化资源文件和struts配置文件自动重新加载,不需要重启服务器 --> <constant name="struts.ui.theme" value="simple" /> <constant name="struts.action.extension" value="," /><!-- 不要后缀 --> <constant name="struts.enable.SlashesInActionNames" value="true" /><!-- 使用"/"的方式 --> <package name="hatch" namespace="" extends="json-default"> <!-- json支持 --> ... <action name="user/*" class="userAction" method="{1}"> <result name="list">/WEB-INF/view/sys/user/list.jsp</result> <result name="saveOrUpdate">/WEB-INF/view/sys/user/saveOrUpdate.jsp</result> <result name="assginRole">/WEB-INF/view/sys/user/assginRole.jsp</result> <result type="json"> <param name="root">dataMap</param> <param name="excludeProperties">rows\[\d+\]\.department.parent,rows\[\d+\]\.department.users,rows\[\d+\]\.department.children,rows\[\d+\]\.roles</param> </result><!-- ajax请求的返回视图 --> </action>如下是页面:
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <%@include file="/WEB-INF/view/common/common.jspf"%> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>用户列表</title> <script type="text/javascript"> $(function(){ //用户列表初始化 $('#dg').datagrid({ striped : true, rownumbers : true, singleSelect : false, pagination : true, pageSize : 10, fitColumn : true, dataType : 'json', animate : true, loadMsg : '请稍候...', url:'${ctx }/sys/user/doList', columns:[[ {field:'ck',checkbox:true,align:'center'}, {title:'序号',field:'id',align:'center'}, {title:'登录名',field:'username',align:'center'}, {title:'名称',field:'name',align:'center'}, {title:'性别',field:'gender',align:'center',formatter:function(v){ return v==1?'男':'女' }}, {title:'手机',field:'phoneNumber',align:'center'}, {title:'email',field:'email',align:'center'}, {title:'所属部门',field:'department',align:'center',formatter:function(v){if(v)return v['name'];}}, {title:'操作',field:'Operation',align:'center',formatter: operationFormate} ]], });//easyui的列表请求,返回数据为json //添加操作列 function operationFormate(value,node){ var str='<a style="color:green;text-decoration:none;margin-right:4px;" href="javascript:void(0);" onclick="update('+node.id+')">修改</a>' +'<a style="color:red;text-decoration:none;margin-right:4px;" href="javascript:void(0);" onclick="del('+node.id+')">删除</a>' +'<a style="color:green;text-decoration:none;margin-right:4px;" href="javascript:void(0);" onclick="assignrole('+node.id+')">角色分配</a>' +'<a style="color:red;text-decoration:none;" href="javascript:void(0);" onclick="resetPwd('+node.id+')">密码重置</a>'; return str; } //查询用户 $('#queryBtn').click(function(){ var queryParams = $('#dg').datagrid('options').queryParams; var name = $.trim($('#queryForm').find('input[name=name]').val()); var gender = $.trim($('#queryForm').find('select[name=gender]').val()); queryParams.name = name; queryParams.gender = gender; $('#dg').datagrid('options').queryParams=queryParams; $('#dg').datagrid('reload'); }); //添加用户 $('#addBtn').click(function(){ window.location.href="${ctx}/sys/user/save"; }); //删除用户 $('#delBtn').click(function(){ var ss = new Array(); var rows = $('#dg').datagrid('getSelections'); for(var i=0; i<rows.length; i++){ var row = rows[i]; ss.push(row.id); } del(ss.join(',')); }); }); //修改用户 function update(id){ window.location.href="${ctx}/sys/user/update?id="+id; } //删除用户 function del(ids){ $.messager.confirm('确认框', '确认要删除吗?此操作是不可恢复的', function(r){ if (r){ var url = '${ctx }/sys/user/del'; $.post(url, { ids:ids }, function(data){ if(data.result==0){ $('#dg').datagrid('reload'); }else{ $.messager.alert('error','失败'); } alert(data.result); },'json'); } }); } //分配角色 function assignrole(id){ window.location.href="${ctx}/sys/user/assginRole?id="+id; } //密码重置 function resetPwd(id){ var url = '${ctx }/sys/user/doResetPwd1'; $.post(url, { id:id }, function(data){ if(data.result==0){ $.messager.alert('信息提示','修改成功,密码重置为111111!','info'); }else{ var msg = data.msg; $.messager.alert('错误提示','操作失败!','error'); window.location = "${ctx}/jsonHandlerAction"; } },'json'); } </script> </head> <body> <div class="ptitle">系统管理>>用户列表</div> <div class="content-wrap"> <div class="pcontent"> <div class="easyui-panel toolbar"> <a href="javascript:void(0);" class="easyui-linkbutton" iconCls="icon-add" plain="true" id="addBtn">新建</a> <a href="javascript:void(0);" class="easyui-linkbutton" iconCls="icon-remove" plain="true" id="delBtn">删除</a> <s:form action="/user/doList" namespace="/" method="post" id="queryForm"> 名称:<s:textfield name="name"/> 性别:<s:select list="#{null:'全部',1:'男',2:'女'}" name="gender"/> <a href="javascript:void(0);" class="easyui-linkbutton" iconCls="icon-search" id="queryBtn">Search</a> </s:form> </div> <!-- 列表 --> <table id="dg" title=""></table> </div> </div> </body>如下是Action
/* 用户 列表数据 */ public String doList(){ HttpServletRequest re = ServletActionContext.getRequest(); dataMap = new HashMap<String, Object>(); Map<String, Object> cond = MapBeanUtil.transBean2Map(user); Page<User> p = new Page<User>(); cond.put("page", Integer.parseInt(re.getParameter("page"))); cond.put("rows", Integer.parseInt(re.getParameter("rows"))); p = userService.findUserForPage(cond); dataMap.put("total", p.getTotal()); dataMap.put("rows", p.getRows()); return SUCCESS; }效果如下:
以上是json开发的简单介绍,更详细的可以下载相关文档。
返回正题,假如正在我在Action中出现异常,可怕的事情:框架将错误页面的html代码以html的形式返回来了,以下是用firefox看到的结果:
分析思考:
struts2的异常处理,是基于拦截器的,出现目前的错误,就是因为拦截器的异常处理,没有考虑到ajax异步请求,那么是哪个拦截器处理异常呢?打开struts核心包struts2-core-2.3.4.jar中的struts-default.xml中,查看下面的信息:
<interceptors> <interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/> <interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/> <interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/> <interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/> <interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/> <interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" /> <interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" /> <interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" /> <interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/> <interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/> 。。。发现异常是这个类com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor来处理的,因此,一个最简单的办法,就是将该类覆写,加上json请求的支持。
/* * Copyright 2002-2006,2009 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.opensymphony.xwork2.interceptor; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.apache.struts2.ServletActionContext; import org.apache.struts2.StrutsStatics; import com.hatch.common.JsonHandlerException; import com.opensymphony.xwork2.Action; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.config.entities.ExceptionMappingConfig; import com.opensymphony.xwork2.util.ValueStack; import com.opensymphony.xwork2.util.logging.Logger; import com.opensymphony.xwork2.util.logging.LoggerFactory; /** * <!-- START SNIPPET: description --> * * This interceptor forms the core functionality of the exception handling * feature. Exception handling allows you to map an exception to a result code, * just as if the action returned a result code instead of throwing an * unexpected exception. When an exception is encountered, it is wrapped with an * {@link ExceptionHolder} and pushed on the stack, providing easy access to the * exception from within your result. * * <b>Note:</b> While you can configure exception mapping in your configuration * file at any point, the configuration will not have any effect if this * interceptor is not in the interceptor stack for your actions. It is * recommended that you make this interceptor the first interceptor on the * stack, ensuring that it has full access to catch any exception, even those * caused by other interceptors. * * <!-- END SNIPPET: description --> * * <p/> * <u>Interceptor parameters:</u> * * <!-- START SNIPPET: parameters --> * * <ul> * * <li>logEnabled (optional) - Should exceptions also be logged? (boolean * true|false)</li> * * <li>logLevel (optional) - what log level should we use ( * <code>trace, debug, info, warn, error, fatal</code>)? - defaut is * <code>debug</code></li> * * <li>logCategory (optional) - If provided we would use this category (eg. * <code>com.mycompany.app</code>). Default is to use * <code>com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor</code>. * </li> * * </ul> * * The parameters above enables us to log all thrown exceptions with stacktace * in our own logfile, and present a friendly webpage (with no stacktrace) to * the end user. * * <!-- END SNIPPET: parameters --> * * <p/> * <u>Extending the interceptor:</u> * * <p/> * * <!-- START SNIPPET: extending --> * * If you want to add custom handling for publishing the Exception, you may * override * {@link #publishException(com.opensymphony.xwork2.ActionInvocation, ExceptionHolder)} * . The default implementation pushes the given ExceptionHolder on value stack. * A custom implementation could add additional logging etc. * * <!-- END SNIPPET: extending --> * * <p/> * <u>Example code:</u> * * <pre> * <!-- START SNIPPET: example --> * <xwork> * <package name="default" extends="xwork-default"> * <global-results> * <result name="error" type="freemarker">error.ftl</result> * </global-results> * * <global-exception-mappings> * <exception-mapping exception="java.lang.Exception" result="error"/> * </global-exception-mappings> * * <action name="test"> * <interceptor-ref name="exception"/> * <interceptor-ref name="basicStack"/> * <exception-mapping exception="com.acme.CustomException" result="custom_error"/> * <result name="custom_error">custom_error.ftl</result> * <result name="success" type="freemarker">test.ftl</result> * </action> * </package> * </xwork> * <!-- END SNIPPET: example --> * </pre> * * <p/> * This second example will also log the exceptions using our own category * <code>com.mycompany.app.unhandled<code> at WARN level. * * <pre> * <!-- START SNIPPET: example2 --> * <xwork> * <package name="something" extends="xwork-default"> * <interceptors> * <interceptor-stack name="exceptionmappingStack"> * <interceptor-ref name="exception"> * <param name="logEnabled">true</param> * <param name="logCategory">com.mycompany.app.unhandled</param> * <param name="logLevel">WARN</param> * </interceptor-ref> * <interceptor-ref name="i18n"/> * <interceptor-ref name="staticParams"/> * <interceptor-ref name="params"/> * <interceptor-ref name="validation"> * <param name="excludeMethods">input,back,cancel,browse</param> * </interceptor-ref> * </interceptor-stack> * </interceptors> * * <default-interceptor-ref name="exceptionmappingStack"/> * * <global-results> * <result name="unhandledException">/unhandled-exception.jsp</result> * </global-results> * * <global-exception-mappings> * <exception-mapping exception="java.lang.Exception" result="unhandledException"/> * </global-exception-mappings> * * <action name="exceptionDemo" class="org.apache.struts2.showcase.exceptionmapping.ExceptionMappingAction"> * <exception-mapping exception="org.apache.struts2.showcase.exceptionmapping.ExceptionMappingException" * result="damm"/> * <result name="input">index.jsp</result> * <result name="success">success.jsp</result> * <result name="damm">damm.jsp</result> * </action> * * </package> * </xwork> * <!-- END SNIPPET: example2 --> * </pre> * * @author Matthew E. Porter (matthew dot porter at metissian dot com) * @author Claus Ibsen */ public class ExceptionMappingInterceptor1 extends AbstractInterceptor { protected static final Logger LOG = LoggerFactory .getLogger(ExceptionMappingInterceptor.class); protected Logger categoryLogger; protected boolean logEnabled = false; protected String logCategory; protected String logLevel; public boolean isLogEnabled() { return logEnabled; } public void setLogEnabled(boolean logEnabled) { this.logEnabled = logEnabled; } public String getLogCategory() { return logCategory; } public void setLogCategory(String logCatgory) { this.logCategory = logCatgory; } public String getLogLevel() { return logLevel; } public void setLogLevel(String logLevel) { this.logLevel = logLevel; } @Override public String intercept(ActionInvocation invocation) throws Exception { String result; try { result = invocation.invoke(); } catch (Exception e) { ActionContext actionContext = invocation.getInvocationContext(); HttpServletRequest request = (HttpServletRequest) actionContext .get(StrutsStatics.HTTP_REQUEST); if (isAjaxRequest(request)) {//如果是ajax请求方式 ValueStack stack = invocation.getStack(); List<ExceptionMappingConfig> exceptionMappings = invocation .getProxy().getConfig().getExceptionMappings(); JsonHandlerException je = new JsonHandlerException(e); String mappedResult = this.findResultFromExceptions( exceptionMappings, je); result = mappedResult; Map<String, Object> dataMap = new HashMap<String, Object>(); stack.set("dataMap", dataMap); dataMap.put("result", "500"); StringBuffer msg = new StringBuffer(e.toString()+"\n"); StackTraceElement[] trace = e.getStackTrace(); for (int i=0; i < trace.length; i++) msg.append("\tat " + trace[i]+"\n"); ServletActionContext.getRequest().getSession().setAttribute("errMsg", msg); }else{// 默认处理方式 if (isLogEnabled()) { handleLogging(e); } List<ExceptionMappingConfig> exceptionMappings = invocation.getProxy().getConfig().getExceptionMappings(); String mappedResult = this.findResultFromExceptions(exceptionMappings, e); if (mappedResult != null) { result = mappedResult; publishException(invocation, new ExceptionHolder(e)); } else { throw e; } invocation.getStack(); invocation.getInvocationContext().get(Action.ERROR); // invocation.getStack().findString("exceptionStack"); invocation.getInvocationContext().get(Action.ERROR); } } return result; } private boolean isAjaxRequest(HttpServletRequest request) { String header = request.getHeader("X-Requested-With"); if (header != null && "XMLHttpRequest".equals(header)) return true; else return false; } /** * Handles the logging of the exception. * * @param e * the exception to log. */ protected void handleLogging(Exception e) { if (logCategory != null) { if (categoryLogger == null) { // init category logger categoryLogger = LoggerFactory.getLogger(logCategory); } doLog(categoryLogger, e); } else { doLog(LOG, e); } } /** * Performs the actual logging. * * @param logger * the provided logger to use. * @param e * the exception to log. */ protected void doLog(Logger logger, Exception e) { if (logLevel == null) { logger.debug(e.getMessage(), e); return; } if ("trace".equalsIgnoreCase(logLevel)) { logger.trace(e.getMessage(), e); } else if ("debug".equalsIgnoreCase(logLevel)) { logger.debug(e.getMessage(), e); } else if ("info".equalsIgnoreCase(logLevel)) { logger.info(e.getMessage(), e); } else if ("warn".equalsIgnoreCase(logLevel)) { logger.warn(e.getMessage(), e); } else if ("error".equalsIgnoreCase(logLevel)) { logger.error(e.getMessage(), e); } else if ("fatal".equalsIgnoreCase(logLevel)) { logger.fatal(e.getMessage(), e); } else { throw new IllegalArgumentException("LogLevel [" + logLevel + "] is not supported"); } } protected String findResultFromExceptions( List<ExceptionMappingConfig> exceptionMappings, Throwable t) { String result = null; // Check for specific exception mappings. if (exceptionMappings != null) { int deepest = Integer.MAX_VALUE; for (Object exceptionMapping : exceptionMappings) { ExceptionMappingConfig exceptionMappingConfig = (ExceptionMappingConfig) exceptionMapping; int depth = getDepth(exceptionMappingConfig .getExceptionClassName(), t); if (depth >= 0 && depth < deepest) { deepest = depth; result = exceptionMappingConfig.getResult(); } } } return result; } /** * Return the depth to the superclass matching. 0 means ex matches exactly. * Returns -1 if there's no match. Otherwise, returns depth. Lowest depth * wins. * * @param exceptionMapping * the mapping classname * @param t * the cause * @return the depth, if not found -1 is returned. */ public int getDepth(String exceptionMapping, Throwable t) { return getDepth(exceptionMapping, t.getClass(), 0); } private int getDepth(String exceptionMapping, Class exceptionClass, int depth) { if (exceptionClass.getName().contains(exceptionMapping)) { // Found it! return depth; } // If we've gone as far as we can go and haven't found it... if (exceptionClass.equals(Throwable.class)) { return -1; } return getDepth(exceptionMapping, exceptionClass.getSuperclass(), depth + 1); } /** * Default implementation to handle ExceptionHolder publishing. Pushes given * ExceptionHolder on the stack. Subclasses may override this to customize * publishing. * * @param invocation * The invocation to publish Exception for. * @param exceptionHolder * The exceptionHolder wrapping the Exception to publish. */ protected void publishException(ActionInvocation invocation, ExceptionHolder exceptionHolder) { invocation.getStack().push(exceptionHolder); } }这里说明下,如果是出现异常,而且是ajax请求的话,就找JsonHandlerException这个异常所对应的视图:
<!-- 定义全局视图 --> <global-results> <result name="login" type="redirectAction">login</result> <result name="404">/WEB-INF/view/404.jsp</result> <result name="500">/WEB-INF/view/500.jsp</result> <result name="json_500" type="json"><param name="root">dataMap</param></result> <result type="json"><param name="root">dataMap</param></result><!-- ajax请求的返回视图 --> </global-results> <!-- 定义全局异常--> <global-exception-mappings> <exception-mapping result="500" exception="java.lang.Exception"/> <exception-mapping result="json_500" exception="com.hatch.common.JsonHandlerException"/> </global-exception-mappings> ...
下面是自定义Json异常类
package com.hatch.common; public class JsonHandlerException extends Exception { /** * */ private static final long serialVersionUID = -4788951533205831941L; public JsonHandlerException() { super(); } public JsonHandlerException(String message) { super(message); } public JsonHandlerException(String message, Throwable cause) { super(message, cause); } public JsonHandlerException(Throwable cause) { super(cause); } }这样在页面一端,就可以正确的获取异常数据了。
对于普通的$.post请求,这个异常数据很容易可以人性化的提示给用户,这里用的easyui,可以在数据表格加载时,验证下有没有返回数据:
$('#dg').datagrid({ striped : true, rownumbers : true, singleSelect : false, pagination : true, pageSize : 10, fitColumn : true, dataType : 'json', animate : true, loadMsg : '请稍候...', url:'${ctx }/sys/user/doList', loadFilter:function(data){ if(!data.rows||!data.total){ if(data.msg){ $.messager.alert('错误提示','操作失败!错误原因:<hr/>'+data.msg,'error'); }else{ $.messager.alert('错误提示','操作失败!','error'); } return {total:0,rows:[]}; } }, columns:[[ {field:'ck',checkbox:true,align:'center'}, {title:'序号',field:'id',align:'center'}, {title:'登录名',field:'username',align:'center'}, {title:'名称',field:'name',align:'center'}, {title:'性别',field:'gender',align:'center',formatter:function(v){ return v==1?'男':'女' }}, {title:'手机',field:'phoneNumber',align:'center'}, {title:'email',field:'email',align:'center'}, {title:'所属部门',field:'department',align:'center',formatter:function(v){if(v)return v['name'];}}, {title:'操作',field:'Operation',align:'center',formatter: operationFormate} ]], });
当然,如果想做一致的处理,像默认的拦截器那样定位到一个错误页面,可以在这里加跳转信息:
loadFilter:function(data){ if(!data.rows||!data.total){ if(data.msg){ $.messager.alert('错误提示','操作失败!错误原因:<hr/>'+data.msg,'error'); }else{ $.messager.alert('错误提示','操作失败!','error'); } window.location = '${ctx}/jsonHandlerAction' return {total:0,rows:[]}; } },这样,又能跳转到我们默认的错误页面了:
这个错误信息,用了一个很笨的方法传递到错误页面,即在拦截器捕获到这个ajax操作的异常时 ,将这个异常信息加入到会话中,然后在js跳转后,在错误页面中取出错误信息。
至此,该方案介绍完毕,有更好方法的童鞋可以赐教!