您的位置:首页 > 编程语言 > Java开发

struts2之json请求的异常处理方案

2013-09-18 22:46 309 查看
大家都知道,使用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跳转后,在错误页面中取出错误信息。

至此,该方案介绍完毕,有更好方法的童鞋可以赐教!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: