Struts2 拦截器

    Struts2框架中拦截器几乎完成了70%的工作,包括解析请求参数,将参数赋值给Action属性,数据校验,文件上传等. Struts2的设计灵活,拦截器采用可插拔的设计,对于需要的拦截器可以手工引入.大部分时候包继承了struts-default包的时候,其内建拦截器就会发挥作用.

一、配置拦截器

    <interceptors>

        <interceptor name="拦截器名一" class="拦截器实现类">

                <param name="参数名">参数值</param>

        </interceptor>    

        <interceptor name="拦截器名二" class="拦截器实现类">

                <param name="参数名">参数值</param>

        </interceptor>

        <interceptor-stack name="拦截器栈二">

                <interceptor-ref name="拦截器名一"/>

        </interceptor-stack>

        ...

    </interceptors>


二、配置拦截器栈

    <interceptor-stack name="拦截器栈一">

            <interceptor-ref name="拦截器名一"/>

            <interceptor-ref name="拦截器名二">

                    <param name="参数名">参数值</param> <!-- 会覆盖拦截器名二中参数值 -->

            </interceptor-ref>

            <interceptor-ref name="拦截器栈二"/><!-- 有定义,直接使用,实现软件复用 -->

            ...

    </interceptor-stack>

当上面的项不是多个可以不用interceptors和interceptoref-stack


三、配置默认拦截器

    在包名下配置

    <default-interceptor-ref name="拦截器名一或者拦截器栈二"/><!-- 要在该包下之前有定义拦截器名一或拦截器栈二 -->

    注意,每个包只能指定一个默认拦截器,但是可以通过默认拦截器栈来实现. 只有当Action中没有显示应用拦截器的时候,默认拦截器会起作用. 否则要显示指定默认拦截器.


四、实现拦截器

    4.1 拦截器实现类必须实现Interceptor接口,一般用于继承AbstractInterceptor类,实现其中的intercept方法,该方法带有invocation参数. 使用getAction获取拦截的Action实例,然后invoke方法执行,如果还有下一个拦截器则将控制权转给下一个拦截器,否则调用Action的execute方法,将execute方法的返回字符串给invoke方法的字符串用于返回到逻辑视图中.

SimpleInterceptor.java

package DeepUse;

import java.util.Date;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

public class SimpleInterceptor extends AbstractInterceptor{

	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private String name;//简单拦截器的名字
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String intercept(ActionInvocation invocation) throws Exception {
		// TODO Auto-generated method stub
		LoginPutSession action=(LoginPutSession)invocation.getAction();//获取被拦截的Action实例
		System.out.println(name+" 拦截器的动作------"+"开始执行登录Action的时间为: "+new Date());
		long start=System.currentTimeMillis();
		String result=invocation.invoke();//该拦截器的后一个拦截器,如果没有则直接执行当前Action的被拦截方法
		System.out.println(name+" 拦截器动作-------"+"执行完成登录Action的时间为: "+new Date());
		long end=System.currentTimeMillis();
		System.out.println(name+" 拦截器的动作------"+"执行完成该Action的时间为: "+(end-start)+"毫秒");
		return result;
	}
}

struts.xml

        <interceptors>
		<interceptor name="mySimple" class="DeepUse.SimpleInterceptor">
			<param name="name">简单拦截器</param>
		</interceptor>
	</interceptors>
        <action name="loginForm" class="DeepUse.LoginPutSession">
		<result>/Struts2DeepUse/downloadForm.jsp</result>
		<interceptor-ref name="defaultStack"/><!-- 系统默认拦截器 -->
		<interceptor-ref name="mySimple">
			<param name="name">改名后的拦截器</param>
		</interceptor-ref>
	</action>

loginForm.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>登录界面</title>
    
	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">    
	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
	<meta http-equiv="description" content="This is my page">
	<!--
	<link rel="stylesheet" type="text/css" href="styles.css">
	-->

  </head>
  
  <body>
    <s:form action="loginForm">
    	<s:textfield name="user" label="用户名"/>
    	<s:textfield name="pass" label="密码"/>
    	<s:submit value="登录"/>
    </s:form>
  </body>
</html>

LoginPutSession.java

package DeepUse;

import java.util.Map;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

public class LoginPutSession extends ActionSupport{
	private String user;

	public String getUser() {
		return user;
	}

	public void setUser(String user) {
		this.user = user;
	}
	
	@Override
	public String execute() throws Exception {
		// TODO Auto-generated method stub
		ActionContext ctx=ActionContext.getContext();
		Map session=ctx.getSession();
		session.put("user", user);
		return SUCCESS;
	}
}

结果:


   

五、拦截方法

默认会拦截Action中的所有方法,但是可以使用Struts2的过滤属性。这样需要继承MethodFilterInterceptor类,重写其中的doIntercept方法,该方法和intervept方法类似. MethodFilterInterceptor是AbstractInterceptor的子类. 同时MethodFilterInterceptor实现了intercept方法的合适处理. 同时还包含setExculdeMethod和setIncludeMethods方法. 当实现了doIntercept后,就可以在struts2.xml文件中配置如下:

<action name="loginForm" class="DeepUse.LoginPutSession">
		<result>/Struts2DeepUse/downloadForm.jsp</result>
		<interceptor-ref name="defaultStack"/><!-- 系统默认拦截器 -->
		<interceptor-ref name="mySimple">
			<param name="excludeMethods">execute</param>
		</interceptor-ref>
	</action> 

这样就排除了execute方法的执行,由于在action中默认Action实例只执行execute方法,因此控制台中没有输出。如果再加一个参数<param name="includeMethods">execute</param>看似冲突,实则按照includeMethods的方式执行,因此控制台会输出.


六、拦截器执行顺序

    修改struts2.xml如下

<action name="loginForm" class="DeepUse.LoginPutSession">
		<result>/Struts2DeepUse/downloadForm.jsp</result>
		<interceptor-ref name="defaultStack"/><!-- 系统默认拦截器 -->
		<interceptor-ref name="mySimple">
			<param name="name">第一个</param>
			<param name="excludeMethods">execute</param>
			<param name="includeMethods">execute</param>
		</interceptor-ref>
		<interceptor-ref name="mySimple">
			<param name="name">第二个</param>
		</interceptor-ref>
	</action>

结果


即使在同一个action也可以使用重复的拦截器,执行顺序是首先第一个拦截器执行登录,然后到invoke方法调用的时候控制权转移给下一个拦截器,直到没有下一个拦截器的时候调用前面所有拦截器的execute方法,然后递归退出.


七、拦截监听器

    在处理物理资源转向之前的动作,Struts2提供了拦截结果的监听器.该监听器需要实现PreResultListener接口

    MyPreResultListener.java

package DeepUse;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.PreResultListener;

public class MyPreResultListener implements PreResultListener{

	@Override
	public void beforeResult(ActionInvocation invocation, String resultCode) {
		// TODO Auto-generated method stub
		System.out.println("返回的逻辑视图是: "+resultCode);//这里千万不要调用invocation的invoke方法,否则会再次执行Action处理
							//然后处理Action之后又是beforeResultfangf...这样一个循环
	}

}

  修改SimpleInterceptor.java

package DeepUse;

import java.util.Date;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;

public class SimpleInterceptor extends MethodFilterInterceptor{

	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private String name;//简单拦截器的名字
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String doIntercept(ActionInvocation invocation) throws Exception {
		// TODO Auto-generated method stub
		invocation.addPreResultListener(new MyPreResultListener());//添加监听器***
		LoginPutSession action=(LoginPutSession)invocation.getAction();//获取被拦截的Action实例
		System.out.println(name+" 拦截器的动作------"+"开始执行登录Action的时间为: "+new Date());
		long start=System.currentTimeMillis();
		String result=invocation.invoke();//该拦截器的后一个拦截器,如果没有则直接执行当前Action的被拦截方法
		System.out.println(name+" 拦截器动作-------"+"执行完成登录Action的时间为: "+new Date());
		long end=System.currentTimeMillis();
		System.out.println(name+" 拦截器的动作------"+"执行完成该Action的时间为: "+(end-start)+"毫秒");
		return result;
	}
}

结果



八、覆盖参数

    当覆盖拦截器的参数,只要同名即可覆盖。但是对于拦截器栈,需要指定拦截器栈中的对应拦截器后再实现该拦截器中参数的覆盖. 具体是用 <拦截器名>.<参数名>作为指定参数来实现覆盖.

    <interceptor-ref name="myStack">

            <param name="seconde.name">拦截器栈中有个拦截器引用为seconde的拦截器中name参数的值被覆盖</param>

    </interceptor-ref>


九、权限控制

    可以使用拦截器来获取ActionContext的实例,进而获取session来判断是否用户在session中进而控制权限

    Authority.java

package DeepUse;

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;

public class AuthorityInterceptor extends AbstractInterceptor{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@SuppressWarnings("rawtypes")
	@Override
	public String intercept(ActionInvocation invocation) throws Exception {
		// TODO Auto-generated method stub
		//invocation.invoke();//调用execute方法来设置session
		ActionContext ctx=invocation.getInvocationContext();//获取ActionContext实例
		Map session=ctx.getSession();//获取session
		String user=(String)session.get("user");
		System.out.println("interceptor准备获取user, user= "+user);
		if(user!=null && user.equals("hello"))
		{
			return invocation.invoke();
		}
		return Action.LOGIN;
	}

}

struts.xml

<interceptors>
		<interceptor name="mySimple" class="DeepUse.SimpleInterceptor">
			<param name="name">简单拦截器</param>
		</interceptor>
		<interceptor name="authority" class="DeepUse.AuthorityInterceptor"/>
		<interceptor-stack name="myDefault">
			<interceptor-ref name="defaultStack"/>
			<interceptor-ref name="authority"/>
		</interceptor-stack>
	</interceptors>
        <action name="loginForm" class="DeepUse.LoginPutSession">
		<result name="success">/Struts2DeepUse/downloadForm.jsp</result>
	</action>
        <action name="download">
		<param name="inputPath">/uploadFiles/listbox_1.png</param>
		<result type="stream">
			<param name="contentType">application/zip</param><!-- 指定文件的下载类型 -->
			<param name="inputName">targetFile</param>
			<param name="contentDisposition">filename="myimage.png"</param>
			<param name="bufferSize">4096</param><!-- 缓冲大小 -->
		</result>
		<result name="login">/Struts2DeepUse/loginForm.jsp</result>
		<interceptor-ref name="myDefault"/>
	</action>

对于action没有指定类,则默认使用ActionSupport类中execute方法返回Action接口中的SUCCESS字段

结果



可见,当输入hello的时候验证成功,进而可以下载,由于下载的action指定了ActionSupport类,但该类中没有inputName指定的方法因此报错,但是这可以说明并不是返回login页面,而是成功进入下载页面了。


十、注意事项

    invoke方法. 该方法一般调用一次,一旦使用该方法,拦截器会执行execute方法,获取返回的逻辑视图字符串。当执行完拦截器后会将该字符串提交给物理视图.

    <default-interceptor-ref>对包下的所有Action均有效. 且必须定义在action的外面.

阅读更多
文章标签: SSH 拦截器
个人分类: SSH框架
想对作者说点什么? 我来说一句

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

关闭
关闭
关闭