枯鸦专栏

于无声处听惊雷

Struts2 拦截器处理普通Http请求和Ajax请求时拦截配置

      近期发现以前的系统中存在一个如下的Bug Case:

      在Session过期时,执行页面的ajax请求时,无法正常跳转到session过期提示页面,系统直接hold在那里不动,只有点击左侧菜单时,系统才能跳转到session过期提示页面。

      经过调研,发现是拦截器的处理问题,拦截器只拦截了Http请求,而没有拦截Ajax请求,才导致出现上述Bug。

      下面是解决办法:

      首先,优化拦截器:

     

/**
 * 拦截器
 * @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请求 无操作权限时 返回字符串
                    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方式提示用户。

<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例子:

public class MyAction
{

    /**
     * Http请求
     * @return
     * @throws Exception 
     * @see
     */
    public String httpReqMethod()
        throws Exception
    {
        try
        {
            //do yourself
        }
        catch(Exception e)
        {
            //捕获异常时抛出  触发global-results中的exception 然后跳转到提示页面
            throw e;//当然也可以不throw,struts框架会自动往上抛异常,同样会触发全局exception提示
        }
        
        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,如不想某些action被拦截,package不继承self-default即可):

<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:

<%@ 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:

//全局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过期则会触发全局提示。

<%@ 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那样更美观)。



阅读更多
个人分类: Java
上一篇基于Spring注解方式配置项目
下一篇CSS背景图片自适应 根据浏览器分辨率大小自动伸缩
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭