一、理解Struts2拦截器
1. Struts2拦截器是在访问某个Action或Action的某个方法,字段之前或之后实施拦截,并且Struts2拦截器是可动态配置的,拦截器是AOP的一种实现.
2. 拦截器栈(Interceptor Stack)。Struts2拦截器栈就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,Struts2拦截器链中的拦截器就会按其之前定义的顺序被调用。
二、实现Struts2拦截器原理(拦截器栈)
拦截器链(Interceptor Chain,在Struts 2中称为拦截器栈Interceptor Stack)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
当Action请求到来的时候,会由系统的代理生成一个Action的代理对象,由这个代理对象调用Action的execute()或指定的方法,并在struts.xml中查找与该Action对应的拦截器。如果有对应的拦截器,就在Action的方法执行前(后)调用这些拦截器;如果没有对应的拦截器则执行Action的方法。其中系统对于拦截器的调用,是通过ActionInvocation来实现的。
三、定义Struts2拦截器
Struts2规定用户自定义拦截器必须实现com.opensymphony.xwork2.interceptor.Interceptor接口。
其中,init和destroy方法会在程序开始和结束时各执行一遍,不管使用了该拦截器与否,只要在struts.xml中声明了该Struts2拦截器就会被执行。
intercept方法就是拦截的主体了,每次拦截器生效时都会执行其中的逻辑。
不过,struts中又提供了几个抽象类来简化:
public abstract class AbstractInterceptor implements Interceptor;
public abstract class LoginInterceptor extends AbstractInterceptor
这些都是模板方法实现的。
其中AbstractInterceptor提供了init()和destroy()的空实现,使用时只需要覆盖intercept()方法;
而MethodFilterInterceptor则提供了includeMethods和excludeMethods两个属性,用来过滤执行该过滤器的action的方法。可以通过param来加入或者排除需要过滤的方法。
Action代码如下:
package com.redhamr.web.member.interceptor;
import java.util.Map;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.redhamr.persistent.model.Member;
import com.redhamr.web.member.GlobalConstantWeb;
public class LoginInterceptor extends AbstractInterceptor {
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
public String intercept(ActionInvocation invocation) throws Exception {
// TODO Auto-generated method stub
// 取得请求相关的ActionContext实例
ActionContext ctx = invocation.getInvocationContext();
Map session = ctx.getSession();
Member user = (Member) session.get(GlobalConstantWeb.SESSION_MEMBER);
// 如果没有登陆,返回重新登陆
if (user != null) {
return invocation.invoke();
}
ctx.put("tip", "你还没有登录");
return "login";
}
}
<package name="member" extends="json-default">
<interceptors>
<interceptor name="authority"
class="com.redhamr.web.member.interceptor.LoginInterceptor">
</interceptor>
<!-- 拦截器栈 -->
<interceptor-stack name="mydefault">
<interceptor-ref name="authority" />
<interceptor-ref name="defaultStack" />
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="mydefault" />
<global-results>
<result name="login" type="redirect">/Website_index_login.rhm</result>
</global-results>
<action name="Website_user_*">
<result>/WEB-INF/user/{1}.jsp</result>
</action>
</package>
在interceptor-ref中也可以通过param标签来设置一些特殊要求,param的name属性不同效果也不同,例子如下
更改拦截器的name属性
<param name="name">更改拦截器以后的名字</param>
不需要拦截的方法名
<param name="aa ">不需拦截的方法名以逗号隔开</param>
需要拦截的方法名
<param name="bb">需拦截的方法名以逗号隔开</param>
注:当aa和bb属性都存在时,则bb属性优先级更高。
JSP展示页面:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<TITLE><sitemesh:write property='title' /></TITLE>
<sitemesh:write property='head' />
<script type="text/javascript" src="scripts/jquery.js"></script>
<script type="text/javascript" src="scripts/run.js"></script>
<script type="text/javascript" src="scripts/page.js"></script>
<script type="text/javascript" src="scripts/jquery-ui.js"></script>
<script type="text/javascript" src="scripts/jquery.zoomImgRollover.js"></script>
<link type="text/css" rel="stylesheet" href="style/first.css" />
<link type="text/css" rel="stylesheet" href="style/main.css" />
<link type="text/css" rel="stylesheet" href="style/footer.css" />
<link type="text/css" rel="stylesheet" href="style/header.css" />
<link type="text/css" rel="stylesheet" href="style/perCenter.css" />
<link type="text/css" rel="stylesheet" href="style/jquery-ui.css" />
<script>
$(document).ready(function() {
$(".testimg").zoomImgRollover();
});
$(function() {
$("input.datepicker").datepicker();
});
</script>
</head>
<!--导航栏和头部开始-->
<div class="head">
<div class="head1">
<ul class="ul_li_f_left h_margin">
<li>欢迎致电 :</li>
<li class="FontSize17px">400-691-7677</li>
<li>服务时间:</li>
<li>9:00 - 19:00</li>
<li class="h_hei_dad"><div class="h_hei_wid1"></div></li>
<li class="h_hei_dad"><div class="h_hei_wid2"></div></li>
</ul>
<ul class="ul_li_f_left h_margin2">
<li class="firstWord"><a href="#">网站活动</a></li>
<!-- <li><a href="#">下载客户端</a></li> -->
<s:if test="null==#session.MEMBER||#session.MEMBER.isEmpty()">
<li><a href="toLogin.rhm">登录</a></li>
</s:if>
<s:else>
<li>${session.MEMBER.username} <s:a action="merchloginout">注销</s:a></li>
</s:else>
<li class="lastWord"><a href="toRegister.rhm">快捷注册</a></li>
</ul>
</div>
</div>
<div class="PageDad">
<div class="Page">
<ul class="ul_li_f_left P_nav">
<li class="P_logo"><a href="Website_index.rhm"></a></li>
<li><a href="proLists.rhm?pageSize=8">我要投资</a></li>
<li><a href="#">新手专区</a></li>
<li><a href="#">安全保障</a></li>
<li><a href="#">平安论坛</a></li>
<li><a href="memCenter.rhm">我的账户</a></li>
</ul>
</div>
</div>
<sitemesh:write property='body'></sitemesh:write>
拦截器的执行流程:
拦截器的执行顺序和在struts.xml的配置顺序是有关,也就是说如果a拦截器在b拦截器之前被声明,则会先进入a拦截器,然后进入b拦截器。值得注意的是b拦截器执行之后会回到a拦截器继续执行之后的内容。
特别注意,在使用拦截器的时候,在Action里面必须最后一定要引用struts2自带的拦截器缺省堆栈defaultStack.