Struts2 拦截器详解(一)
来源:互联网 发布:单片机步进电机c程序 编辑:程序博客网 时间:2024/05/01 22:17
拦截器是Struts2的一个重要特性。Struts2框架的大多数核心功能都是通过拦截器来实现的,像避免表单重复提交、类型转换、对象组装、验证、文件上传等,都是在拦截器的帮助下实现的。
拦截器的一个重要特征是:它可以在Action之前调用。
拦截器,在AOP(Aspect Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截。然后再之前或之后加入某些操作。拦截器是AOP的一种实现策略。
Struts2的拦截原理:
当请求到达Struts2的ServletDispatcher时,Struts2会查找相对应的配置信息,并实例化拦截器对象。串成一个列表(list),最后一个一个地调用列表中的拦截器。
1.配置拦截器
引入拦截器机制,可以实现对Action通用操作的可插拔式管理,这种可插拨是基于Struts.xml文件实现的。
1)配置拦截器
在struts.xml文件中定义拦截器只需为拦截器指定一个拦截器名称即可。使用<interceptor.../>元素来定义拦截器,最简单的格式如下。
<interceptor name="拦截器名" class="拦截器类"></interceptor>
有时,按照上面的配置便可以完成一个简单的拦截器,但是,如果还需要配置拦截器时传入拦截器参数,则需要在<interceptor.../>元素中使用<param.../>子元素。下面是在配置拦截器时,同时传入拦截器参数的配置形式。
<interceptor name="拦截器名" class="拦截器类"> <!-- 下面元素可以出现0次,也可以出现无数次,其中name属性指定需要设置的参数名 --> <param name="参数名">参数值</param> </interceptor>
2)配置拦截器栈
struts2还支持把多个拦截器连在一起组成一个拦截器栈,比如:需要在Action执行前同时进行安全检查,身份验证,数据校验等等操作,可以将这些动作链接成一个拦截器栈。
拦截器栈的定义形式:
<interceptor-stack name="拦截器栈名"> <interceptor-ref name="拦截器一"></interceptor-ref> <interceptor-ref name="拦截器二"></interceptor-ref> </interceptor-stack>
拦截器和拦截器栈的功能是一样的,只不过拦截器栈定义了一组拦截器。
当然我们也可以在拦截器中定义拦截器栈,这样都是可以的,主要是实现了代码的复用。比如:
<interceptor name="a1" class="com.zhuxuli.SInterceptor"> </interceptor> <interceptor name="a2" class="com.zhuxuli.DInterceptor"> </interceptor> <interceptor name="a3" class="com.zhuxuli.WInterceptor"></interceptor> <interceptor-stack name="a4"> <interceptor-ref name="a1"> <param name="st">gsa</param> </interceptor-ref> <interceptor-ref name="a2"> </interceptor-ref> </interceptor-stack>
2.使用拦截器
拦截器在<package>目录下声明好了以后,下一步就是在Action中使用拦截器了
示例代码如下:
<action name="user" class="com.zhuxuli.action.UserAction"> <result name="user">/user.jsp</result> <result name="add_user">/add_input.jsp</result> <interceptor-ref name="myfilter"> <param name="name">拦截器</param> <!-- 指定execute方法不需要被拦截 --> <param name="excludeMethods">execute</param> </interceptor-ref> </action>
通过<interceptor标签直接引用拦截器。
如果是使用拦截器栈,那示例代码如下:
<action name="ge"> <result name="success">/success.jsp</result> <interceptor-ref name="a1"></interceptor-ref> <!-- 定义使用的拦截器栈,和使用拦截器没有什么区别,都是通过interceptor-ref标签完成 --> <interceptor-ref name="a4"></interceptor-ref> </action>
3.拦截器剖析
拦截器的配置已经说的很明白了,但是我们还一点疑问是,那个拦截器的实现类怎么办?
对于Struts2拦截器的实现有两种形式
第一种方式:自定义拦截器类
第二种方式:Struts2自带的拦截器
首先我们说明下第一种方式:
上述代码
<interceptor name="拦截器名" class="拦截器类"> <!-- 下面元素可以出现0次,也可以出现无数次,其中name属性指定需要设置的参数名 --> <param name="参数名">参数值</param> </interceptor>
我们可以看到,自定义拦截器只有name=“拦截器名”是不可以的,我们还要有拦截器类,那拦截器类是怎么实现的?
1)实现自定义拦截器类
如果要开发自己的拦截器类,应该实现com.opensymphony.xwork2.interceptor.Interceptor接口,此接口的定义代码如下:
import com.opensymphony.xwork2.ActionInvocation;public interface Interceptor {//撤销该拦截器之前的回调方法void destory();//初始化该拦截器的回调方法void init();//拦截器实现拦截的逻辑方法String intercept(ActionInvocation invocation) throws Exception;}
通过接口可以看出,该接口里有三种方法。
init():拦截器初始化之后,在该拦截器执行拦截之前,系统将回调该方法,对于每一个拦截器而言,该init()方法只执行一次。因此,该方法的方法体主要用户打开一些一次性资源,例如数据库资源等。
destory():该方法与init()方法对应。在拦截实例被销毁之前,系统将回调该拦截器的destory()方法,该方法用于销毁在init()方法里打开的资源。
interceptor(ActionInvocation invocation):该方法是用户需要实现的拦截动作。就像Action执行execute()方法一样,interceptor会返回一个字符串作为逻辑视图。如果该方法直接返回了一个字符串,系统将跳转到该逻辑视图队形的实际的视图资源,不会调用被拦截的Action类。该方法的ActionInvocation参数保护那了被拦截的Action的引用,可以通过调用该参数的invoke()方法,将控制权转给下一个拦截器,或者转给Action的execute方法。
除此之外,Struts2提供了一个AbstractInterceptor类,该类提供了空的init()和destory()方法的实现,也就是如果拦截器不需要申请资源,则可以无须实现这两个方法。
注意:
当实现了intercept(ActionInvocation invocation)方法时,可以获得ActionInvocation参赛,这个参数又可以获得被拦截的Action实例,一旦取得了Action实例,几乎得到了全部的控制权。
实例剖析:
通过上面的了解,我们来做一个拦截器的实例
需求:客户端用户名密码登陆,拦截器对其进行拦截,如果用户名和密码满足条件,进入执行execute方法,如果不满足要求,返回index.jsp页面
建立相应的index.jsp页面
<%@ page language="java" import="java.util.*" pageEncoding="GB18030"%><%@ taglib prefix="s" uri="/struts-tags" %><%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>My JSP 'index.jsp' starting page</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="los" method="post"> <s:textfield label="请输入用户名" name="username"></s:textfield> <s:password label="请输入密码" name="userpass"></s:password> <s:submit/> </s:form> </body></html>
定义Action类
Action中定义了接受前台两个参数的属性
import com.opensymphony.xwork2.ActionSupport;public class LoginAction extends ActionSupport {private String username;private String userpass;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getUserpass() {return userpass;}public void setUserpass(String userpass) {this.userpass = userpass;}public String execute() throws Exception{return SUCCESS;}}
import com.opensymphony.xwork2.ActionSupport;public class LoginAction extends ActionSupport {private String username;private String userpass;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getUserpass() {return userpass;}public void setUserpass(String userpass) {this.userpass = userpass;}public String execute() throws Exception{return SUCCESS;}}
定义拦截器类
该拦截器类继承了AbstractInterceptor类,可以不写init()和destory()方法,但是必须实现intercept(ActionInvocation invocation)方法
当拦截到内容后,系统首先打印出"拦截器开始工作......"
由于invocation中已经存在Action对象,所以按照我们说的得Action者得天下原则,为Action中的两个属性username ,userpass赋值。这里存在一个很重要的问题:如果不为Action的两个元素赋值,那Action类不像我们以前没有拦截器认识的一样,Action中的username和userpass将不会在自动取得前台index.jsp页面传送过来的值,即使满足条件,如果Action类中还需要对username和userpass两个属性做进一步处理的话,username和userpass将会是空值。
怎么解决呢?
首先必须明白的是在提交后,Struts2将会自动调用LoginAction动作类中的setUsername方法,并将username文本框中的值通过setUserame方法的参数传入。实际上,这个操作是由params拦截器完成的,params对应的类是com.opensymphony.xwork2.interceptor.ParametersInterceptor。由于params已经在defaultStack中定义,因此,在未引用拦截器的< action>中是会自动引用params的。
但是,如果引用了自定义拦截器,那我们就要现实的在Action中引用params拦截器
如果满足用户名和密码是user 和123,则调用invocation.invoke()方法,该方法的作用是调用下一个拦截器或Action(如果是最后一个拦截器了,则调用Action);
import javax.servlet.http.HttpServletRequest;import org.apache.struts2.ServletActionContext;import com.opensymphony.xwork2.ActionInvocation;import com.opensymphony.xwork2.interceptor.AbstractInterceptor;import com.zhuxuli.action.LoginAction;public class LoInterceptor extends AbstractInterceptor{public String intercept(ActionInvocation invocation) throws Exception{System.out.println("拦截器开始工作.....");HttpServletRequest request=ServletActionContext.getRequest();LoginAction action=(LoginAction)invocation.getAction();action.setUsername(request.getParameter("username"));action.setUserpass(request.getParameter("userpass"));if(action.getUsername().equals("user")&&action.getUserpass().equals("123")){String result=invocation.invoke();System.out.println("result="+result);return result;}else{return "input";}}}
然后配置struts.xml文件
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN" "http://struts.apache.org/dtds/struts-2.1.7.dtd"><struts> <constant name="struts.i18n.encoding" value="gbk" /><constant name="struts.devMode" value="true" /> <package name="zxl" extends="struts-default"> <interceptors> <interceptor name="a1" class="com.zhuxuli.Iterceptors.LoInterceptor"> </interceptor> </interceptors> <action name="los" class="com.zhuxuli.action.LoginAction"> <result name="input">/index.jsp</result> <result name="success">/success.jsp</result> <interceptor-ref name="a1"></interceptor-ref> </action> </package></struts>
实例运行后,如果用户名和密码不是user和123,页面返回index.jsp页面继续输入,满足条件,则返回为success.jsp页面。
必须注意的是:
在执行返回success.jsp页面的时候,你会看到控制台打印出了相应的语句,也就是下面的代码执行了
Stringresult=invocation.invoke();
//代码执行了
System.out.println("result="+result);
returnresult;
也就是说,通过invocation调用invoke()方法执行Action后,Action执行完毕后,又返回到String result=invocation.invoke()代码下面继续执行,直到执行结束,也就说明了拦截器的拦截过程为:如下图,
说明:搜先调用拦截器1,满足要求,则通过Invocation.invoke()方法调用下一个拦截器或Action,因为这里有下一个拦截器,所以直接调用拦截器2,如果还是满足条件,则继续向下调用,知道返回结果,返回结果后,注意的是,还会继续回到拦截器2执行未完成的代码,执行完后,继续执行拦截器1未完成的代码,直到最后返回结果。
- Struts2 拦截器详解(一)
- Struts2 拦截器详解(一)
- Struts2 拦截器详解(一)
- Struts2拦截器(一)
- struts2拦截器(一)
- Struts2拦截器详解
- Struts2拦截器详解
- Struts2拦截器详解
- struts2拦截器详解
- struts2 拦截器详解
- Struts2 拦截器 详解
- Struts2拦截器详解
- Struts2拦截器详解
- Struts2拦截器详解
- Struts2拦截器详解
- Struts2 拦截器详解
- struts2拦截器详解
- Struts2拦截器详解
- Eclipse快捷键
- Javascript作用域原理
- 广州软件测试俱乐部“持续集成”主题研讨会圆满结束!
- flash getCode() and getAscii()
- CSS浏览器兼容问题
- Struts2 拦截器详解(一)
- 第十六章-十七章:线程栈 - 内存映射文件
- jQuery打印插件PrintArea实现jQuery打印插件PrintArea实现
- 第十八章:堆
- Bit-flipping attack
- LaTeX如何显示大小罗马数字
- C#_可空类型及空接合运算符(2.0)(如何给int赋null值,Int? 有何用
- linux2.6内核Makefile详解
- nginx 负载均衡