2018-05-10 18:58:46
浏览数 (1)
struts2之配置拦截器
- 本人独立博客https://chenjiabing666.github.io
什么是拦截器
- java里的拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行,同时也提供了一种可以提取action中可重用部分的方式。在AOP(Aspect-Oriented Programming)中拦截器用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。
- 拦截器是可插拔式的,一旦出现了问题,可以不用改变软件的很多代码就可以实现修复,给维护工作带来方便,其实过滤器也是这样的。
- Struts2其实就实现了很多的拦截器,可以在struts-default.xml中看到定义很多的拦截器,其中向类型转换,文件上传都是通过拦截器实现的。
- Struts2拦截器实现原理与Servlet过滤器实现原理类似,它以链式执行,对真正要执行的方法(execute())进行拦截。首先执行Action配置的拦截器,在Action和Result执行之后,拦截器会再次执行(与先前调用的顺序相反),在此链式执行的过程中,每一个拦截器都可以直接返回,从而终止余下的拦截器、Action及Result的执行。
拦截器的作用
- 拦截器适合封一些通用处理,便于重复利用,比如日志的记录,访问权限的检查,事务处理等,拦截器通过配置方式调用,因此使用方法比较灵活,便于维护和扩展
拦截器的配置元素
<interceptors>
用来定义拦截器,所有的拦截器和拦截器栈都是在此元素中定义的,可以包含子元素<interceptor>,<interceptor-stack><Interceptor>
用来定义拦截器,需要指定两个属性,name属性指定了拦截器的名字,class指定了拦截器的实现的类。这个是在<interceptors>下定义的<interceptor-stack>
用来定义拦截器栈,其中的name属性指定了拦截器栈的名称。另外在此元素下可以指定<interceptor-ref>引入其他的拦截器或者拦截器栈<interceptor-ref>
用来引用其他的拦截器或者拦截器栈,name属性指定了拦截器或者拦截栈的名称<param>
用来为拦截器指定参数,可以作为<interceptor>或者<interceptor-ref>的子元素。并且可以定义多个。其中的name属性指定了参数的名称<default-interceptor-ref>
将某一个拦截器定义为默认拦截器
内建的拦截器
- struts2中提供了许多内建的拦截器,在struts-core.jar中,我们只需要在struts.xml中引用这个内建的拦截器即可
- 比如我们在实现文件上传的时候,使用的就是内建的拦截器
- 内建的拦截器使用的很少,通常我们都是使用自定义的拦截器,比如验证访问权限的拦截器
自定义拦截器
- 实现自定义的拦截器有两种方法,一种是实现接口,一种是继承
需求
- 我们需要将表单传递过来的数据转换成大写的,再传递给action
实现接口(com.opensymphony.xwork2.interceptor.Interceptor)
接口中的方法
void init()
初始化拦截器执行的方法String intercept(ActionInvocation invocation) throws Exception
实现拦截器逻辑的主要方法。
ActionInvocation
包含了Action的引用,因此使用这个对象可以对Action进行相应的操作,比如可以获取和设置Action类的成员变量ActionInvocation
包含了Action的引用,可以调用其中的invoke()
方法继续调用下一个拦截器,如果后面没有拦截器了,那么就会执行Action中对应的映射方法,如果有,那么就会继续执行下一个拦截器,直到执行完全部的拦截器才会执行对应的映射方法- invoke()方法将拦截器的作用分成了两个部分,在调用invoke()之前的实在Action方法执行之前的逻辑,在之后的代码是在Action执行result,跳转到指定视图之后执行的逻辑
- 这个方法返回的是一个字符串,对应的也是结果视图,如果在其中没有调用invoke()方法,那么返回的字符串就作为Action跳转的视图,因此在<result>一定要定义这个对应的视图。如果调用了invoke()方法,那么返回的字符串就会失效,就会以Action中方法返回的字符串为主
void destroy()
销毁拦截器开启的资源
实现
- 拦截器类
- 这里并没有在init和destroy方法中写什么逻辑,可以根据实际情况来定义其中的逻辑
代码语言:javascript
复制import com.jsnu.struts2.controller.SimpleAction;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
public class TestInterceptor implements Interceptor{
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void init() {
// TODO Auto-generated method stub
}
@Override
public String intercept(ActionInvocation invocation) throws Exception {
Object object=invocation.getAction(); //获取当前调用拦截器的Action类的对象
//如果不为null,就可以获取其中的属性,否则空指针
if (object!=null) {
SimpleAction simpleAction=(SimpleAction)object;
//将User属性全部转换成大写字母
simpleAction.getUser().setName(simpleAction.getUser().getName().toUpperCase());
simpleAction.getUser().setPassword(simpleAction.getUser().getPassword().toUpperCase());
String result=invocation.invoke(); //调用下一个拦截器
System.out.println("成功跳转视图后执行的逻辑");
return result;
}
return null;
}
}
继承AbstractInterceptor(推荐)
- 继承
AbstractInterceptor
抽象类,里面只有一个抽象方法String intercept(ActionInvocation invocation)
,只需要实现这个方法即可,如果你需要初始化和销毁,那么也可以覆盖其中的init()和destroy()方法 - 继承抽象类的方式比实现接口对一个类的更加简洁,对这个类的污染更加小
- 其中的方法逻辑还是和上面的一样
- 还是完成上面的需求,把传递的请求参数转换成大写字母
代码语言:javascript
复制import com.jsnu.struts2.controller.SimpleAction;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
//继承类AbstractInterceptor
public class AbstractInterceptorTest extends AbstractInterceptor {
@Override
public String intercept(ActionInvocation invocation) throws Exception {
Object object = invocation.getAction(); // 获取当前调用拦截器的Action类的对象
// 如果不为null,就可以获取其中的属性,否则空指针
if (object != null) {
SimpleAction simpleAction = (SimpleAction) object;
// 将User属性全部转换成大写字母
simpleAction.getUser().setName(
simpleAction.getUser().getName().toUpperCase());
simpleAction.getUser().setPassword(
simpleAction.getUser().getPassword().toUpperCase());
String result = invocation.invoke(); // 调用下一个拦截器
System.out.println("成功跳转视图后执行的逻辑");
return result;
}
return null;
}
}
配置拦截器
- 因为struts2的很多功能都要依赖内建的拦截器,比如表单传值。这一系列的拦截器都定义在一个拦截器栈中,如果在一个<action>中引用了拦截器,那么这拦截器就会被覆盖,因此一定要在自定义的拦截器之前定义默认的拦截器栈
<interceptor-ref name="defaultStack"></interceptor-ref>
- 配置拦截器只需要在<package>下定义拦截器即可,如果哪个action想要引用拦截器,使用
<interceptor-ref >
引用已经定义好的拦截器即可 - 一个action中可以引用多个拦截器,在上面配置的拦截器先执行,因此默认的拦截器栈一定要在最上面
- 在struts.xml中配置上面我们自定义的拦截器
代码语言:javascript
复制<package name="test" extends="struts-default" namespace="/">
<!-- 定义拦截器 -->
<interceptors>
<!-- 实现接口的拦截器 -->
<interceptor name="testInterceptor" class="com.jsnu.struts2.Interceptor.TestInterceptor"></interceptor>
<!-- 继承类的 -->
<interceptor name="abstractInterceptorTest" class="com.jsnu.struts2.Interceptor.AbstractInterceptorTest"></interceptor>
</interceptors>
<action name="simple" class="com.jsnu.struts2.controller.SimpleAction">
<result name="success">/jsp/success.jsp</result>
<result name="input">/jsp/input.jsp</result>
<!-- 在使用了自定的拦截器之后,那么系统默认的拦截器栈将会失去作用,因此这里需要重新指定拦截器栈-->
<interceptor-ref name="defaultStack"></interceptor-ref>
<!-- 引用自定义的拦截器,在上面要定义 -->
<interceptor-ref name="abstractInterceptorTest"></interceptor-ref>
<interceptor-ref name="testInterceptor"></interceptor-ref>
</action>
</package>
配置拦截器栈
- 如果一个action中的需要用到的拦截器很多,或者同时引用几个相同的拦截器的action很多,那么我们此时在action一个一个的引用拦截器效率太低,此时我们就需要将这些拦截器定义在一个拦截器栈中,直接在action中引用了拦截器栈即可。
- 直接使用<interceptors>标签中使用<interceptor-stack name>定义即可
- 拦截器栈中的拦截器一定要在上面定义过的,否则将会引用出错
- 拦截器栈中的拦截器引用是有顺序的,在上面的拦截器最先执行
- 我们把上面自定义的两个拦截器放在拦截器栈中,并在action中引用拦截器栈,注意此时的默认的
default-stack
还是要放在最上面
代码语言:javascript
复制<package name="test" extends="struts-default" namespace="/">
<!-- 定义拦截器 -->
<interceptors>
<!-- 实现接口的拦截器 -->
<interceptor name="testInterceptor" class="com.jsnu.struts2.Interceptor.TestInterceptor"></interceptor>
<!-- 继承类的 -->
<interceptor name="abstractInterceptorTest" class="com.jsnu.struts2.Interceptor.AbstractInterceptorTest"></interceptor>
<!-- 自定拦截器栈,其中引用了上面的两个拦截器 -->
<interceptor-stack name="myStack">
<!-- 引用自定义的拦截器,在上面要定义 -->
<interceptor-ref name="abstractInterceptorTest"></interceptor-ref>
<interceptor-ref name="testInterceptor"></interceptor-ref>
</interceptor-stack>
</interceptors>
<action name="simple" class="com.jsnu.struts2.controller.SimpleAction">
<result name="success">/jsp/success.jsp</result>
<result name="input">/jsp/input.jsp</result>
<!-- 在使用了自定的拦截器之后,那么系统默认的拦截器栈将会失去作用,因此这里需要重新指定拦截器栈-->
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="myStack"></interceptor-ref>
</action>
</package>
拓展
- 拦截器中还可以包含其他的拦截器栈,那么此时我们就可以将struts2中内建的拦截器放在自己的拦截器栈顶,那么就不用在每个action中引用了,直接引用这个拦截器栈即可
代码语言:javascript
复制<package name="test" extends="struts-default" namespace="/">
<!-- 定义拦截器 -->
<interceptors>
<!-- 实现接口的拦截器 -->
<interceptor name="testInterceptor" class="com.jsnu.struts2.Interceptor.TestInterceptor"></interceptor>
<!-- 继承类的 -->
<interceptor name="abstractInterceptorTest" class="com.jsnu.struts2.Interceptor.AbstractInterceptorTest"></interceptor>
<!-- 自定拦截器栈,其中引用了上面的两个拦截器 -->
<interceptor-stack name="myStack">
<!-- 在使用了自定的拦截器之后,那么系统默认的拦截器栈将会失去作用,因此这里需要重新指定拦截器栈-->
<interceptor-ref name="defaultStack"></interceptor-ref>
<!-- 引用自定义的拦截器,在上面要定义 -->
<interceptor-ref name="abstractInterceptorTest"></interceptor-ref>
<interceptor-ref name="testInterceptor"></interceptor-ref>
</interceptor-stack>
</interceptors>
<action name="simple" class="com.jsnu.struts2.controller.SimpleAction">
<result name="success">/jsp/success.jsp</result>
<result name="input">/jsp/input.jsp</result>
<interceptor-ref name="myStack"></interceptor-ref>
</action>
</package>
自定义默认的拦截器栈
- 在一个包中定义一个默认的拦截器栈后(使用<default-interceptor-ref>定义),那么当<action>下没有显式的配置拦截器的时候,那么此时就会默认使用自定义的默认的拦截器或者默认的拦截器栈。
- 一个包中只能定义一个默认的拦截器,如果想要定义多个拦截器可以使用拦截器栈,定义一个默认的拦截器栈即可解决。
- 在定义了默认的拦截器之后一定要在每一个action都定义系统默认的拦截器栈defaultStack,前面已经说过如果action定义了拦截器(这里虽然不是显式的定义,但是实际上是定义了),那么就会失去defaultStack的作用,其实我们需要很多defaultStack的功能,因此还是要定义的。
- 比如登录检查的拦截器,这个是每一个action都需要用到的,那么我们可以设置一个默认的拦截器栈,栈顶引用的是struts2内建的默认的拦截器栈
- 使用<default-interceptor-ref name=""></default-interceptor-ref> 即可定义
代码语言:javascript
复制<struts>
<package name="test" extends="struts-default" namespace="/">
<!-- 定义拦截器 -->
<interceptors>
<!-- 实现接口的拦截器 -->
<interceptor name="testInterceptor" class="com.jsnu.struts2.Interceptor.TestInterceptor"></interceptor>
<!-- 继承类的 -->
<interceptor name="abstractInterceptorTest" class="com.jsnu.struts2.Interceptor.AbstractInterceptorTest"></interceptor>
<!-- 自定拦截器栈,其中引用了上面的两个拦截器 -->
<interceptor-stack name="myStack">
<!-- 在使用了自定的拦截器之后,那么系统默认的拦截器栈将会失去作用,因此这里需要重新指定拦截器栈-->
<interceptor-ref name="defaultStack"></interceptor-ref>
<!-- 引用自定义的拦截器,在上面要定义 -->
<interceptor-ref name="abstractInterceptorTest"></interceptor-ref>
<interceptor-ref name="testInterceptor"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 定义默认的拦截器栈,其中引用了上面定义的拦截器栈 -->
<default-interceptor-ref name="myStack"></default-interceptor-ref>
<action name="simple" class="com.jsnu.struts2.controller.SimpleAction">
<result name="success">/jsp/success.jsp</result>
<result name="input">/jsp/input.jsp</result>
</action>
</package>
</struts>
配置拦截方法的拦截器
- 一般我们的Action类中有很多的方法,但是我们在使用动态调用的时候会调用其中不同的方法,如果不想Action类中的某个方法不被拦截,此时就需要使用拦截方法的拦截器
- 其中可以设置拦截的方法,也可以设置不拦截的方法
自定义拦截器类
- 继承MethodFilterInterceptor
- 其中的方法doIntercept是在执行其中指定方法之前执行,和前面的逻辑一样,也有invoke方法
代码语言:javascript
复制import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
public class SimpleActionInteceptor extends MethodFilterInterceptor{
@Override
protected String doIntercept(ActionInvocation invocation) throws Exception {
System.out.println("拦截方法的拦截器起了作用");
String result=invocation.invoke();
System.out.println("执行之后");
return result;
}
}
struts中配置
<param name="excludeMethods">login</param>
用来定义不拦截的方法<param name="includeMethods">regist</param>
用来定义拦截的方法,如果有多个使用逗号隔开- 这里使用的是动态调用的
method
的,但是我们也可以使用 action!方法名
- 假设我们的项目名称为web1,并且把method=“”去掉,那么我们开启
action!方法名
进行调用,具体方法前面有介绍,开启之后,我们在地址栏输入 http://localhost:8080/web1/simple.regist
,将会成功被拦截器拦截器,但是我们输入http://localhost:8080/web1/simple.login
,拦截器不起作用
代码语言:javascript
复制<package name="test" extends="struts-default" namespace="/">
<!-- 定义拦截器 -->
<interceptors>
<!-- 配置拦截方法的拦截器 -->
<interceptor name="simpleMethod" class="com.jsnu.struts2.Interceptor.SimpleActionInteceptor"></interceptor>
</interceptors>
<action name="simple" class="com.jsnu.struts2.controller.SimpleAction" method="regist">
<result name="success">/jsp/success.jsp</result>
<result name="input">/jsp/input.jsp</result>
<!-- 在使用了自定的拦截器之后,那么系统默认的拦截器栈将会失去作用,因此这里需要重新指定拦截器栈-->
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="simpleMethod">
<!-- 定义不拦截login方法 -->
<param name="excludeMethods">login</param>
<!-- 定义需要拦截器的方法 -->
<param name="includeMethods">regist</param>
</interceptor-ref>
</action>
</package>