struct2拦截器
来源:互联网 发布:通联支付网络给我打钱 编辑:程序博客网 时间:2024/05/16 09:30
拦截器是Struts2的一个重要特性。Struts2框架的大多数核心功能都是通过拦截器来实现的,像避免表单重复提交、类型转换、对象组装、验证、文件上传等,都是在拦截器的帮助下实现的。
拦截器的一个重要特征是:它可以在Action之前调用。
拦截器,在AOP(Aspect Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截。然后再之前或之后加入某些操作。拦截器是AOP的一种实现策略。
Struts2的拦截原理:
当请求到达Struts2的ServletDispatcher时,Struts2会查找相对应的配置信息,并实例化拦截器对象。串成一个列表(list),最后一个一个地调用列表中的拦截器。
- 配置拦截器
在struts.xml文件中定义拦截器只需为拦截器指定一个拦截器名称即可。使用<interceptor.../>元素来定义拦截器,最简单的格式如下。
<interceptor name="拦截器名" class="拦截器类"></interceptor>
有时,按照上面的配置便可以完成一个简单的拦截器,但是,如果还需要配置拦截器时传入拦截器参数,则需要在<interceptor.../>元素中使用<param.../>子元素。下面是在配置拦截器时,同时传入拦截器参数的配置形式。
<interceptor name="拦截器名" class="拦截器类"> <!-- 下面元素可以出现0次,也可以出现无数次,其中name属性指定需要设置的参数名 --> <param name="参数名">参数值</param> </interceptor>
- 配置拦截器栈
struts2还支持把多个拦截器连在一起组成一个拦截器栈,比如:需要在Action执行前同时进行安全检查,身份验证,数据校验等等操作,可以将这些动作链接成一个拦截器栈。
拦截器栈的定义形式:
<interceptor-stack name="拦截器栈名"> <interceptor-ref name="拦截器一"></interceptor-ref> <interceptor-ref name="拦截器二"></interceptor-ref> </interceptor-stack>
拦截器和拦截器栈的功能是一样的,只不过拦截器栈定义了一组拦截器。
当然我们也可以在拦截器中定义拦截器栈,这样都是可以的,主要是实现了代码的复用。比如:
<interceptor name="a1" class="com.yao.SInterceptor"> </interceptor> <interceptor name="a2" class="com.yao.DInterceptor"> </interceptor> <interceptor name="a3" class="com.yao.Interceptor"></interceptor> <interceptor-stack name="a4"> <interceptor-ref name="a1"> <param name="st">abc</param> </interceptor-ref> <interceptor-ref name="a2"> </interceptor-ref> </interceptor-stack>
- 使用拦截器
拦截器在<package>目录下声明好了以后,下一步就是在Action中使用拦截器了
示例代码如下:
<action name="user" class="com.yao.action.UserAction"> <result name="user">/user.jsp</result> <result name="add_user">/add_user.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>
- 拦截器剖析
- 实现自定义拦截器类
- 实现自定义拦截器类
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; } }
该拦截器类继承了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.yao.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页面的时候,你会看到控制台打印出了相应的语句,也就是下面的代码执行了
System.out.println("result="+result);return result;
也就是说,通过invocation调用invoke()方法执行Action后,Action执行完毕后,又返回到String result=invocation.invoke()代码下面继续执行,直到执行结束,也就说明了拦截器的拦截过程为:如下图。
说明:首先调用拦截器1,满足要求,则通过Invocation.invoke()方法调用下一个拦截器或Action,因为这里有下一个拦截器,所以直接调用拦截器2,如果还是满足条件,则继续向下调用,知道返回结果,返回结果后,注意的是,还会继续回到拦截器2执行未完成的代码,执行完后,继续执行拦截器1未完成的代码,直到最后返回结果。
- Struct2常用的预定义拦截器
1:params拦截器
这个拦截器是必不可少的,因为就是由它把请求参数设置到相应的Action的属性去的,并自动进行类型转换。
2:staticParams拦截器
将struts.xml配置文件里定义的Action参数,设置到对应的Action实例中,Action参数使用<param>标签,是<action>标签的子元素。
struts.xml的示例如下:
<action name="helloworldAction" class="cn.javass.action.action.HelloWorldAction"> <param name="account">test</param> </action>
这要求Action中一定要有一个account的属性,并有相应的getter/setter方法。运行的时候,Action的account属性在初始化过后,会接到这里的赋值“test”。
注意:params拦截器和staticParams拦截器都会为Action的属性赋值,如果碰到了都要赋同一个值呢,比如request里面有account参数,而struts.xml中也有account参数,最终的值是谁?
其实是Action初始化过后,就会把struts.xml中配置的数据设置到Action实例中相应的属性上去。然后,把用户请求的数据设置到Action实例中相应的属性上去。
很明显最后的值是用户请求中account的数据。
3:prepare拦截器
在Action执行之前调用Action的prepare()方法,这个方法是用来准备Action执行之前要做的工作。它要求我们的Action必需实现com.opensymphony.xwork2.Preparable接口
4:modelDriven拦截器
如果Action实现ModelDriven接口,它将getModel()取得的模型对象存入OgnlValueStack中。
5:chain拦截器
将前一个执行结束的Action属性设置到当前的Action中。它被用在ResultType为“chain”所指定的结果的Action中,该结果Action对象会从值栈中获得前一个Action对应的属性,它实现Action链之间的数据传递。
6:execption拦截器
在抛出异常的时候,这个拦截器起作用。它是我们第五章讲的Struts2的错误处理机制(<exception-mapping>)的基础,任何应用都应该引用这个拦截器,而且引用的时候,最好把它放在第一位,让它能捕获所有的异常。
7:validation拦截器
调用验证框架读取 *-validation.xml文件,并且应用在这些文件中声明的校验。
8:token拦截器
核对当前Action请求(request)的有效标识,防止重复提交Action请求 。使用标签<s:token>可以生成表单令牌,该标签会在session中设置一个预期的值并且在表单中创建一个隐藏的input字段。Token拦截器会检查这个令牌,如果不合法,将不会执行action,注意这个拦截器需要手工添加,还需要配置一个invalid.token的result。
9:tokenSession拦截器
扩展了token拦截器的功能,当提交无效的Action请求标识时,它会跳转回到第一次成功后的页面。
10:conversionError拦截器
用来处理框架进行类型转化(Type Conversion)时的出错信息。它将存储在ActionContext中的类型转化(Type Conversion)错误信息转化成相应的Action字段的错误信息,保存在堆栈中。根据需要,可以将这些错误信息在视图中显示出来。
11:fileUpload拦截器
用来处理文件上传。
12:workflow拦截器
Action默认的工作流,如果action实现了Validateable接口,那么interceptor会调用action的validate()方法;如果action实现了ValidationAware接口,那么interceptor将会检查action是否包含错误信息。如果包含任何错误信息,那么interceptor将会返回input,而不让action执行。
13:servletConfig拦截器
这个拦截器提供Action直接对Servlet API的访问,把Servlet API的对象注入到Action中。包括:ServletRequestAware、ServletResponseAware、ParameterAware、SessionAware、ApplicationAware。
14:timer拦截器
记录ActionInvocation余下部分执行的时间,并做为日志信息记录下来,便于寻找性能瓶颈。
15:logger拦截器
在日志信息中输出要执行的Action信息 ,这样,在调试的时候,就能很快的定位到这个对应的Action了。
- 深入struct2拦截器
- Struct2 自定义拦截器
- struct2 的拦截器
- Struct2 自定义拦截器
- struct2拦截器
- Struct2拦截器的原理与实现
- struct2登录拦截器的配置
- struct2中得默认拦截器(类似AOP)
- struct2中得自定义拦截器(类似AOP)
- 教务管理系统-Struct2注解使用拦截器(Interceptor)
- 理清jsp的filter(过滤器)和struct2的拦截器(Interceptor)
- Struct2
- struct2
- Struct2 配置
- 看struct2
- struct2 标签
- Struct2小结
- Struct2相关
- 深入理解Javascript闭包
- 工作积累
- 009_内核对象
- HDU 1010 Tempter of the Bone
- 继承
- struct2拦截器
- Web开发野蛮生长的这17年
- HDU2149 Public Sale(巴什博弈)
- HDU 1258 Sum It Up
- Adb logcat 相关
- NODEJS 安装
- Github客户端安装使用教程(一)
- java中throw与throws的区别
- hdu 1728 逃离迷宫