6拦截器

拦截器体系是struts2的一个重要的组成部分,正式大量的内建拦截器完成了该框架的大部分操作。比如:params拦截器将HTTP请求中的参数解析出来,设置成Action的属性;servlet-config拦截器直接将HTTP请求中的HttpServletRequest实例和HttpServletResponse实例传给Action;fileUpload拦截器则负责解析请求参数中的文件域,并将一个文件域设置成Action的三个属性等等。对于struts2的拦截器体系而言,当我们需要使用某个拦截器时,只需要再配置文件中应用该拦截器即可。如果不需要使用该拦截器,只需要取消在配置文件中应用该拦截器。

拦截器时对调用方法的改进,实际上,当称某个实例是一个拦截器时,这是就其行为上而言,但从代码角度来看,拦截器就是一个类,这个类也包含方法,只是这个方法是个特殊方法,它会在目标方法调用之前自动执行。

拦截器与AOP的关系

代理工厂负责根据目标对象和对应的拦截器生成新的代理对象,代理对象的方法是目标方法和拦截器器方的组合,通过这种方式实现了在目标方法之前或之后,自动调用拦截器方法大的目的。代理对象也称为AOP代理,这是由系统动态生成的一个对象,该对象将代替目标对象来使用。

拦截器域AOP是密切关系的,在AOP的编程方式中,有三个重要概念:

目标对象:包含被拦截方的原始对象。

被插入的处理方:定义在拦截器中,会在被拦截方法之前,之后自动执行的方法。

代理对象:以目标对象为蓝本,由系统创建的新对象。

1配置拦截器

拦截器一般写在<package>中,在struts.xml文件中定义拦截器只需要为拦截器类指定一个拦截器名,就完成拦截器定义。定义拦截器使用<interceptor../>元素来定义,定义拦截器最简单的格式如下:

<interceptors>

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

<!--

大部分时候,只需要通过上面得格式来完成拦截器的配置,如果还需要在配置拦截器时传入拦截器参数,则需要在<intercepter../>元素中使用<param../>子元素,如:

-->

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

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

</interceptor>

<interceptors>

例如:

<interceptors>

<interceptor name="firstInterceptor" class="action.firstInterceptor">

<param name="lanjie">my first interceptor</param>

</interceptor>

</interceptors>

此外,还可以包含多个拦截器连在一起组成拦截器栈,定义拦截器栈使用<intercepter-stack../>元素,拦截器栈由多个<intercepter-ref../>元素指定的拦截器组成。拦截器栈和拦截器是统一的,它们包含的方法都会在Action的execute方法执行之前自动执行。拦截器栈与拦截器的功能几乎完全相同,因此可以在拦截器栈中包含拦截器栈。

<interceptor-ref name="defaultStack"/>是系统默认的拦截器栈,如果我们在<action../>中添加了自己的拦截器后还需要添加:<interceptor-ref name="defaultStack"/>,因为它是系统默认的拦截器栈。它可以将参数的值赋给Action相应的属性。

在<action..>...</action>中使用拦截器时通过<interceptor-ref.../>元素来引用在<package.../>中定义的拦截器。

默认拦截器

当配置一个包时,可以为其指定默认拦截器,一旦为某个包指定了默认了默认的拦截器,如果该包中的Action没有显式指定拦截器,则默认的拦截器将会起作用。但是一旦我们为该包中的Action显式指定了某个拦截器,则默认的拦截器不会起作用,如果该Action需要使用该默认拦截器,则必须手动配置该拦截器的引用。

配置默认呢拦截器使用<default-interceptor-ref../>元素,该元素作为<package.../>元素的子元素使用,为该包下的所有Action配置了默认拦截器。配置<default-interceptor-ref../>元素时,需要制定一个name属性,该name属性值是一个已经存在拦截器的名或拦截器栈名,表明将该拦截器配置成该包的默认拦截器。注意每个<package../>元素只能有一个<default-interceptor-ref../>子元素,即每个包只能指定一个默认拦截器。

与Action中使用拦截器一样,也可以在配置默认拦截器时为该拦截器指定参数,因此,指定默认拦截器的<default-interceptor-ref../>元素

同样支持<param../>子元素:该元素用于定义

在Action中定义的包都是struts-default包的子包,当我们定义的包继承struts-default包时,也继承了它的默认拦截器栈:defaultStack,这就意味着,如果我们不为Action指定人很拦截器引用,则defaultStack拦截器栈拦截Action。

<interceptors ../>:该元素用于定义拦截器,所有的拦截器和拦截器栈都在该元素下定义,而不能直接放在<package..>中。该元素包含<interceptor../>和<interceptor-stack/>子元素,分别用于定义拦截器和拦截器栈。

<interceptor../>元素,该元素用于定义拦截器,定义拦截器只需要指定两个属性:name和class

<interceptor-stack../>元素,该元素用于定义拦截器引用,该元素中包含多个<interceptor-ref../>元素。

<interceptor-ref../>元素,该元素引用一个拦截器或拦截器栈,该元素只需要制定一个name属性,该name属性值为一个已经定义的拦截器和拦截器栈。

<param../>该元素用于为拦截器指定参数,可以作为<interceptor.../>和<interceptor-ref../>元素的子元素使用。注意使用<param.../>元素向拦截器传递参数与<action.../>元素中使用<param../>一样。可以参考<action.../>中的<param.../>

2使用自定义拦截器

如果用户要开发自己的拦截器类,应该实现com.opensymphony.xwork2.interceptor.Interceptor接口,该接口的类定义代码如下:

public interface Interceptor extends Serializable{

//销毁该拦截器之前的回调方法

void destroy();

//初始化拦截器的回调方法

void init();

//拦截器实现拦截的逻辑方法

String intercept(ActionInvocation invocation)throws Exception;

}

init(),在该拦截器被初始化之后,在该拦截器执行拦截之前,系统将回调该方法。对于每个拦截器而言,该init()方法只执行一次。

destroy(),在拦截器实例被销毁之前,系统将回调该拦截器的destroy方法。

intercept(ActionInvocation invocation),该方法是用户需要实现的拦截动作,就像Action的execute方法一样,intercept方法会返回一个字符串作为逻辑视图,如果该方法直接返回一个字符串,系统将会跳转到该逻辑视图对应的实际视图资源,不会调用被拦截的Action。该方法的ActionInvocation参数包含了被拦截的Action的引用,可以通过调用该参数的invoke方法,将控制权转给下一拦截器,或转给Action的execute方法。

struts2还提供了一个AbstractInterceptor类,该类提供了一个init和destroy方法的空实现,我们也可以继承AbstractInterceptor类来实现自定义拦截器。

下面是一个简单的拦截器类:

package action;

import com.opensymphony.xwork2.ActionInvocation;

import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

public class firstInterceptor extends AbstractInterceptor {

//定义属性lanjie对应于<param name="lanjie">my first interceptor</param>

private String lanjie;

public String getLanjie() {

return lanjie;

}

public void setLanjie(String lanjie) {

this.lanjie = lanjie;

}

//重写intercept方法

public String intercept(ActionInvocation invocation) throws Exception{

System.out.println("*****************start interceptor"+lanjie);

//将控制权转交给下一个拦截器,如果没有拦截器了就执行Action中方法

String result=invocation.invoke();

System.out.println("*****************"+result);

return result;

}

}

3方法过滤

默认情况下,如果我们为某个Action定义了拦截器,则这个拦截器会拦截Action内的所有方法。可能我们只需要拦截某些方法,就需要实现方法过滤,struts2提供了一个MethodFilterInterceptor类,该类是AbstractInterceptor类的子类,如果用户需要自己实现的拦截支持方法过滤特性,则应该继承MethodFilterInterceptor。

实际上,实现方法过滤的拦截器与实现普通拦截器并没有太大区别,只需要注意两个地方:实现方法过滤的拦截器需要继承MethodFilterInterceptor抽象类和重写doIntercept方法定义对Action的拦截逻辑。在MethodFilterInterceptor方法,额外增加了如下两个方法:

public void setExcludeMethods(String excludeMethods),排除需要过滤的方法,所有在excludeMethods字符串中列出的方法都不会被拦截。

public void setIncludeMethod(String includeMethods),设置需要过滤的方法,所有在includeMethods字符串中列出的方法都会被拦截。

如果一个方法同时在excludeMethods和includeMethods中列出,则该方法会被拦截。

因为MethodFilterInterceptor类包含了上面的两个方法,所以它的子类也包含这两个方法,便可以直接在配置文件中指定需要被拦截或不需要被拦截的方法,方法过滤示例应用的配置片段:

<interceptor-ref name="myfilter">

<!--重新指定name属性的属性值-->

<param name="name">改名后的方法过滤拦截器</param>

<!--指定execute方法不需要拦截-->

<param name="excludeMethods">execute,nofilter</param>

<!--指定test方法需要拦截-->

<param name="includeMethods">test</param>

</interceptor-ref>

如果需要同时指定多个方法不被该拦截器拦截,则多个方法之间以英文逗号(,)隔开。

方法过滤类的实例:

package action;

import com.opensymphony.xwork2.ActionInvocation;

import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;

public class firstInterceptor extends MethodFilterInterceptor {

private String lanjie;

public String getLanjie() {

return lanjie;

}

public void setLanjie(String lanjie) {

this.lanjie = lanjie;

}

//重写dointercept方法

public String doIntercept(ActionInvocation invocation) throws Exception{

System.out.println("*****************start interceptor"+lanjie);

String result=invocation.invoke();

System.out.println("*****************result");

return result;

}

}

拦截器的执行顺序

在Action中的方法执行之前的拦截动作,将按照拦截器定义的先后顺序执行,在Action中的方法执行之后的拦截动作,则执行顺序相反。

4拦截结果的监听器

在前面的拦截器中,我盟将在execute方法执行之前,执行之后的动作都定义在拦截器的intercept方法或doIntercept方法中,为了精确定义在execute方法执行结束后,再处理Result执行的动作,struts2提供了用于拦截结果的监听器,这个监听器是通过手动注册在拦截内部的。

实现拦截结果的监听器必须实现PreResultListener接口,例如:

package action;

import com.opensymphony.xwork2.ActionInvocation;

import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;

import com.opensymphony.xwork2.interceptor.PreResultListener;

public class firstInterceptor extends MethodFilterInterceptor  {

private String lanjie;

public String getLanjie() {

return lanjie;

}

public void setLanjie(String lanjie) {

this.lanjie = lanjie;

}

public String doIntercept(ActionInvocation invocation) throws Exception{

//将拦截结果的监听器手动注册给某个拦截器

invocation.addPreResultListener(new myresultListener());

System.out.println("*****************start interceptor"+lanjie);

String result=invocation.invoke();

System.out.println("*****************"+lanjie+"            "+result);

return result;

}

//定义在处理Result之前的行为

}

//在firstInterceptor.java这个类定义了两个类firstInterceptor和myresultListener

class myresultListener implements PreResultListener{

public void beforeResult(ActionInvocation invocation,String resultCode){

System.out.println("返回的逻辑类型:"+resultCode);

}

}

拦截结果的监听器是实现了PreResultListener接口的监听器。该接口有一个beforeResult方法,

beforeResult方法中的参数resultCode,这个参数就是被拦截的Action的execute方法的返回值,虽然beforeResult方法也获得ActionInvocation类型的参数,但是这时Action的execute方法已经执行结束了。通过.addPreResultListener()方法注册拦截结果的监听器。该监听器中的beforeResult方法可定会在系统处理Result之前执行。

注意:不要再beforeResult方法中可以获得ActionInvocation实例,但不要再次调用invoke()方法,如果再次调用invoke()方法,将会再次执行Action处理,将陷入一个死循环。

5覆盖拦截器中特定拦截器的参数

我们在Action配置中引用拦截器并通过<param.../>元素来修改拦截器属性值。但是这种方式有个缺点,加入我们引用的是一个拦截器栈,那么要修改这个拦截器栈中的拦截器的属性,则必须在该Action内重新引用这个拦截器。struts2提供了另一个更加简单的修改方式:当引用拦截器栈时直接修改该栈内拦截器的属性值,采用如下方式的配置片段:

<!--引用拦截器栈my-stack-->

<interceptor-ref name="my-statck">

<param name="second.name">更改拦截器second的属性name的值</param>

</interceptor-ref>

可以看出:如果需要再引用拦截器栈时直接覆盖栈内某个拦截器的属性值,则在指定需要被覆盖的属性时,不能只指定该属性的属性名,必须加上该属性属于的拦截器。即采用如下形式:

<param name="拦截器名.属性名">新的属性值</param>

在struts-default.xml文件时struts2默认的配置文件,这个配置文件会自动加载,struts2大部分的内建拦截器都配置在该文件中。如果我们定义的package继承了struts2的默认struts-default包,则可以自由使用struts2内建的拦截器。

********************

如果给一个action配置了多个拦截器,如果有几个拦截器同名,则这些拦截器都会被执行。invoke方法将控制权移交给下一个拦截器,直到所有的拦截器都执行完毕,则将控制权移交给Action。

********************

如果我们给action定义了拦截器,需把这个拦截器放在默认拦截器<interceptor-ref name="defaultStack"/>前面。另外在默认拦截器栈执行之前Action的属性是没有值的。

**************

ActionInvocation实例的getAction()获得被拦截的Action类的对象,返回的是一个Object对象。例如:

checkLogin fc=(checkLogin)invocation.getAction();

ActionInvocation实例的getInvocationContext()方法获得ActionContext对象。例如:

ActionContext ctx=invocation.getInvocationContext();ctx.getSession();获得session对象。

时间: 2024-10-10 14:27:57

6拦截器的相关文章

java web 过滤器跟拦截器的区别和使用

1.首先要明确什么是拦截器.什么是过滤器 1.1 什么是拦截器: 拦截器,在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作.拦截是AOP的一种实现策略. 在Webwork的中文文档的解释为--拦截器是动态拦截Action调用的对象.它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行.同时也是提供了一种可以提取action中可重用的部分的方式.

微信小程序之页面拦截器

场景 小程序有52个页面,其中13个页面无需任何身份,另外39个页面需要系统角色.对于这39个页面,如果微信用户没有系统角色,则跳转到登录页.是否有系统角色信息需要通过异步请求来获取. 需求分析&实现 对需求进行抽象,其实要的就是一个过滤器,对小程序页面的访问进行过滤,符合条件的通过,不符合条件进行其他处理. 使用过php的laravel框架的童鞋,肯定一下子就联想到了laravel框架的http中间件:HTTP 中间件提供一个方便的机制来过滤进入应用程序的 HTTP 请求,例如,Laravel

SpringMvc拦截器小测试

前言 俗话说做项目是让人成长最快的方案,最近小编写项目的时候遇到了一个小问题.小编在项目中所负责的后台系统,但是后台系统是通过系统的页面是通过ifame联动的,那么这时候问题就来了,后台所做的所有操作都是联动操作(都是基于所联动的)那么我后台所做的所有操作都是基于后台用户登录的情况下所做的.但是在联动中中所有页面都是单独存在的,如果要解决这个问题就需要在做操作之前判断用后台用户是否已经登录.想知道小编是如何实现的那就接着往下看. 简介 Spring MVC的拦截器不仅可实现Filter的所有功能

7.添加基于Spring的WebService拦截器

客户端拦截器: public class AccountInterceptor extends AbstractPhaseInterceptor<SoapMessage>{ private String name; private String password; public AccountInterceptor(String name,String password) { //Phase值决定了拦截器什么时候拦截到消息 //PRE_PROTOCOL准备请求时拦截 super(Phase.P

struts2学习笔记---自定义拦截器

什么是拦截器? struts2中拦截器分为Struts2定义好的拦截器和自定义的拦截器.其作用是在一个Action执行之前进行拦截,在Action执行之后又加入某些操作. 实现原理 当请求一个Action时,struts2会查找配置文件,并根据这个Action的配置实例化对应的拦截器对象,然后串成一个列表(list),最后一个一个地调用列表中的拦截器. 拦截器的执行流程 1.对Action进行预处理.(正序执行) 2.拦截器自身决定该不该执行后续的拦截器(由invoke()方法的返回值决定).

使用方法拦截器MethodInterceptor和AOP统一处理log

对每个接口的请求记录log的方法有很多种,比如用filter.mvc interceptor.method interceptor等.如果需要记录请求消息的payload,前两种不适用.下面介绍第三种的实现方法. 第一步:引入包依赖 <span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></span><pre name=&

过滤器、监听器、拦截器的区别

1.过滤器 Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序,主要的用途是过滤字符编码.做一些业务逻辑判断等.其工作原理是,只要你在web.xml文件配置好要拦截的客户端请求,它都会帮你拦截到请求,此时你就可以对请求或响应(Request.Response)统一设置编码,简化操作:同时还可进行逻辑判断,如用户是否已经登陆.有没有权限访问该页面等等工作.它是随你的web应用启动而启动的,只初始化一次,以后就可以拦截相关请求,只有当你的web应用

spring mvc 方法注解拦截器

应用场景,在方法级别对本次调用进行鉴权,如api接口中有个用户唯一标示accessToken,对于有accessToken的每次请求可以在方法加一个拦截器,获得本次请求的用户,存放到request或者session域. python中,之前在python flask中可以使用装饰器来对方法进行预处理,进行权限处理 先看一个实例,使用@access_required拦截: @api.route('/post_apply') @access_required def apply():     "&q

【struts2】预定义拦截器

1)预定义拦截器 Struts2有默认的拦截器配置,也就是说,虽然我们没有主动去配置任何关于拦截器的东西,但是Struts2会使用默认引用的拦截器.由于Struts2的默认拦截器声明和引用都在这个Struts-default.xml里面,因此我们需要到这个文件的struts-default包里去看一下.定义如下: 1 <interceptors> 2 <interceptor name="alias" class="com.opensymphony.xwor

mybatis拦截器

业务需求:由于公司业务需要在所有的sql的增删改查中必须包含officeId,业务以officeId做隔离.因此做了一个Mybatis的的过去器.通过拦截sql处理的过程来判断接口sql是否包含officeId,如果不包含则添加officeId.@NoNeedOffice的注解可以添加在Dao的接口类或方法上.用于标识不需要处理的接口. package com.example.springcloud.provider; import com.example.springcloud.provide