struts2之json請求的異常處理方案
大家都知道,使用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跳轉後,在錯誤頁面中取出錯誤資訊。
至此,該方案介紹完畢,有更好方法的童鞋可以賜教!