Struts2 攔截器處理普通Http請求和Ajax請求時攔截配置
阿新 • • 發佈:2019-01-05
近期發現以前的系統中存在一個如下的Bug Case:
在Session過期時,執行頁面的ajax請求時,無法正常跳轉到session過期提示頁面,系統直接hold在那裡不動,只有點選左側選單時,系統才能跳轉到session過期提示頁面。
經過調研,發現是攔截器的處理問題,攔截器只攔截了Http請求,而沒有攔截Ajax請求,才導致出現上述Bug。
下面是解決辦法:
首先,優化攔截器:
[java]
/**
* 攔截器
* @author lyh
* @version 2013-11-1
* @see LoginFilter
* @since
*/
public class LoginFilter implements Interceptor
{
/**
* 序列號
*/
private static final long serialVersionUID = -4979037503367919375L;
/**
* 日誌
*/
private static final Logger LOG = Logger.getLogger(LoginFilter.class);
/**
* ajax session超時返回值
*/
private static String AJAX_TIME_OUT = null;
/**
* ajax 請求無許可權返回值
*/
private static String AJAX_NO_LIMIT = null;
/**
* ajax 請求異常返回值 (在每個ajax請求中處理)
*/
//private static String AJAX_EXCEPTION = null;
/**
* 放行url
*/
private static List<String> awayUrls = null;
static
{
AJAX_TIME_OUT = "ajaxSessionTimeOut";
AJAX_NO_LIMIT = "ajaxNoLimit";
//AJAX_EXCEPTION = "ajaxException";
awayUrls = new LinkedList<String>();
//awayUrls.add("/login!userLogin.action");
//awayUrls.add("/custom!toLogin.action");
awayUrls.add("/equipment!upLoad.action");
}
@Override
public String intercept(ActionInvocation invocation)
throws Exception
{
//獲取request域中資訊
HttpServletRequest req = ServletActionContext.getRequest();
//獲得當前請求url
String url = req.getServletPath();
//獲得請求型別
String type = req.getHeader("X-Requested-With");
//Object object = (Object)invocation.getAction();
//如果當前url在放行url集合內 則直接放行
if (!awayUrls.contains(url))
{
UserInfoBean userinfo = (UserInfoBean)req.getSession().getAttribute(
CommonConstant.AUTH_SESSION_USER_KEY);
if (userinfo == null)
{
LOG.debug("使用者登入會話已過期!");
//ajax請求 session過期時 返回字串
if ("XMLHttpRequest".equalsIgnoreCase(type))
{
PrintWriter printWriter = ServletActionContext.getResponse().getWriter();
printWriter.print(AJAX_TIME_OUT);
printWriter.flush();
printWriter.close();
return null;
}
//普通http請求 直接返回頁面
else
{
return "sessionTimeOut";
}
}
else
{
//鑑權結果
boolean authFlag = false;
try
{
//執行鑑權
authFlag = userManager_Service.isUrlInUserLimit(userinfo.getU_phone_num(),
url);
}
catch (Exception e)
{
LOG.error(" 鑑權出現異常!異常資訊:" + e.toString() + ":" + e.getMessage());
}
//鑑權通過則放行 否則攔截
if (authFlag)
{
return invocation.invoke();
}
//鑑權不通過
else
{
//ajax請求 session過期時 返回字串
if ("XMLHttpRequest".equalsIgnoreCase(type))
{
PrintWriter printWriter = ServletActionContext.getResponse().getWriter();
printWriter.print(AJAX_NO_LIMIT);
printWriter.flush();
printWriter.close();
return null;
}
//其他Http請求 直接返回頁面
else
{
return "noLimit";
}
}
}
}
else
{
return invocation.invoke();
}
}
@Override
public void destroy()
{
//do yourself
}
@Override
public void init()
{
//do yourself
}
}
上述攔截器考慮了Ajax和Http兩種情況,Http請求被攔截時,直接跳轉到指定的全域性頁面,而Ajax請求被攔截時則採用Js方式提示使用者。
[html]
<package name="self-default" extends="json-default">
<interceptors>
<interceptor name="loginFilter" class="xx.xx.LoginFilter" />
<interceptor-stack name="mydefault">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="tokenSession">
<param name="includeMethods">add*,update*,modify*,upload*</param>
</interceptor-ref>
<interceptor-ref name="loginFilter" />
</interceptor-stack>
</interceptors>
<!-- 攔截器應用到全部action -->
<default-interceptor-ref name="mydefault"/>
<global-results>
<!-- 普通http請求時 系統出現異常返回到錯誤頁 -->
<result name="exception">/file/smartmanager/public/globalException. jsp</result>
<!-- 普通http請求時 無操作許可權 -->
<result name="noLimit">/file/smartmanager/public/noLimit.jsp</result>
<!-- 普通http請求時 session過期 -->
<result name="sessionTimeOut">/file/smartmanager/public/sessionTimeOut.jsp</result>
</global-results>
<global-exception-mappings>
<!-- 全域性異常返回exception字串 -->
<exception-mapping exception="java.lang.Exception" result="exception" />
</global-exception-mappings>
</package>
下面是一個簡單的Action例子:
[java]
public class MyAction
{
/**
* Http請求
* @return
* @throws Exception
* @see
*/
public String httpReqMethod()
throws Exception
{
try
{
//do yourself
}
catch(Exception e)
{
//捕獲異常時丟擲 觸發global-results中的exception 然後跳轉到提示頁面
throw e;
}
return "httpReqMethod";
}
/**
* Ajax請求
* @return
* @throws Exception
* @see
*/
public String ajaxReqMethod()
{
try
{
//do yourself
}
catch(Exception e)
{
//no throw
//此處在捕獲異常時 新增提示資訊至json 方便在頁面展示
//ajaxMap.put("success", false);
//ajaxMap.put("opMsg", ResultMsg.CHANGE_PWD_ERROR);
}
return "ajaxReqMethod";
}
}
配置此Action的xml(此Action需要被攔截 故extends定義的攔截器self-default):
[ html]
<package name="willPackage" extends="self-default" namespace="/">
<action name="my_*" class="xx.xx.MyAction" method="{1}">
<result name="httpReqMethod">/file/smartmanager/main/httpReqMethod.jsp</result>
<result name="ajaxReqMethod" type="json">
<param name="root">ajaxMap</param>
</result>
</action>
</package>
全域性提示頁面,globalException.jsp:
[html]
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>xxx管理 系統</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="icon" href="file/img/rhy.ico" type="image/x-icon" />
<link rel="shortcut icon" href="file/img/rhy.ico" type="image/x-icon" />
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/file/css/easyui.css" ></link>
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/file/css/icon.css" ></link>
<script type="text/javascript" src="${pageContext.request.contextPath}/file/scripts/jquery-1.8.3.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/file/scripts/jquery.easyui.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/file/scripts/easyui-lang-zh_CN.js"></script>
<body>
<script type="text/javascript">
$(function(){
$.messager.alert('操作提示','系統內部異常!請聯絡系統管理員!','warning');
});
</script>
</body>
全域性ajax配置publicSetup.js:
[javascript]
//全域性ajax控制,用於session超時 無許可權時 提示
$.ajaxSetup({
cache: false, //close AJAX cache
contentType:"application/x-www-form-urlencoded;charset=utf-8",
complete:function(XHR,textStatus){
var resText = XHR.responseText;
if(resText=='ajaxSessionTimeOut'){
sessionTimeOut();
}
else if(resText=='ajaxNoLimit'){
noLimit();
}
}
});
function sessionTimeOut(){
$.messager.alert('操作提示','使用者登入會話已過期,請重新登入!','warning');
setTimeout('window.top.location.href = "login!exit.action"', 15);
}
function noLimit(){
$.messager.alert('操作提示','無相應操作許可權,請聯絡系統管理員!','warning');
}
在ajax請求頁面,引入上述的publicSetup.js,在ajax請求時會觸發上述js,如果session過期則會觸發全域性提示。
[html]
<%@ page contentType="text/html; charset=UTF-8" isELIgnored="false"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!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"></meta>
<title>xx管理系統</title>
<link rel="icon" href="${contextPath}/file/img/rhy.ico" type="image/x-icon" />
<link rel="shortcut icon" href="${contextPath}/file/img/rhy.ico" type="image/x-icon" />
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/file/css/easyui.css" ></link>
<script type="text/javascript" src="${pageContext.request.contextPath}/file/scripts/jquery-1.8.3.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/file/scripts/jquery.easyui.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/file/scripts/easyui-lang-zh_CN.js"></script>
<!-- 引入ajax配置 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/file/scripts/publicSetup.js"></script>
<script type="text/javascript">
function ajaxPost() {
$.post('my_ajaxReqMethod.action', params, function (data) {
if (data.success) {
}
$.messager.alert('操作提示', data.opMsg, data.success?'info':'warning');
});
}
</script>
</head>
<body>
</body>
</html>
綜上,在Http請求時,會攔截到session過期、無操作許可權,然後跳轉到制定的全域性提示頁面,全域性的exception配置是通過在使用者自定義action方法中丟擲Exception,然後觸發跳轉到全域性提示頁面。
而Ajax請求時,攔截到session過期、無操作許可權時,會通過全域性設定的ajax.js進行控制,如果不滿足,則Alert提示語,ajax的Exception配置在ajax方法中捕獲,然後拼裝異常提示語至返回頁面Json,在頁面進行Exception提示。
二者的提示區別,Http請求攔截時跳轉到頁面進行提示,而Ajax請求攔截時採用的是Alert提示方式(當然你可以用EasyUI、ExtJS的Alert那樣更美觀)