详解Struts2 * 机制
作者:Single_YAM 发布时间:2022-03-12 23:20:52
Struts2的核心在于它复杂的 * ,几乎70%的工作都是由 * 完成的。比如我们之前用于将上传的文件对应于action实例中的三个属性的fileUpload * ,还有用于将表单页面的http请求参数设置成action中对应的属性的param * 等。总之,在整个Struts框架中 * 的作用是相当大的,本篇将从以下几点详细介绍下有关Struts * 的内容:
* 在Struts中的作用
自定义 * 实现类
配置 * (包含配置默认 * )
引用 *
配置拦截指定方法的 *
* 的拦截顺序
一、 * 在Struts中的作用
在我们的web.xml中,我们配置了一个过滤器,实现将所有请求交付StrutsPrepareAndExecuteFilter类。一旦接受到任意action的请求,该类会创建和初始化一个ActionProxy实例,它代理了具体的action,在其中我们可以添加任意 * 在execute方法执行之前和之后做一些额外的操作,最终会调用该action实例的execute方法,为用户返回视图结果字符串,然后系统会根据该视图结果字符串调取相应的视图页面。下图是 * 和action之间的关系:
这是一种典型的AOP思想,当我们在Struts.xml中定义一个包的时候,大部分情况下我们会继承struts-default文件,所以虽然我们在自己的配置文件中并没有手动配置任何的 * ,但是我们创建的action却被很多 * 拦截处理,就是因为struts-default中配置的 * 生效了。Struts中内建了很多的 * ,他们大多被配置在struts-default文件中,详细的内建 * 的介绍可以参考官方API,接下来我们看如何自定义一个 * 。
二、自定义 * 实现类
想要实现自己的 * 类只需要实现 com.opensymphony.xwork2.interceptor.Interceptor.Interceptor 接口即可,该接口中有如下几个方法:
public abstract void destroy();
public abstract void init();
public abstract String intercept(ActionInvocation paramActionInvocation)
throws Exception;
init 方法在执行拦截方法之前回调,主要用于初始化一些资源,destroy 与init 方法对应,在 * 实例被销毁之前回调,主要用于释放在init 方法中打开的资源。intercept 方法是我们的拦截方法,我们可以重写该方法来完成对action实例的拦截,该方法具有一个ActionInvocation 类型的参数,该参数内部引用了具体的action实例对象(如果该action还有其他 * 的话),我们可以调用该参数的invoke方法调用具体action实例的execute方法或者调用下一个 * ,intercept方法返回一个String 类型的字符串代表了具体视图页面。下面看个具体的例子:
public class TestAction extends ActionSupport {
public String execute(){
System.out.println("执行execute方法......");
return SUCCESS;
}
}
public class MyIntercept implements Interceptor {
public void init() {}
public void destroy() {}
public String intercept(ActionInvocation action) throws Exception{
System.out.println("拦截action开始.......");
String result = action.invoke();
System.out.println("拦截action结束.......");
return result;
}
}
省略了配置 * 和TestAction 的代码,下图是上述程序运行的结果截图:
三、配置和引用 *
上述的示例定义了一个简单的 * 实现类,我们省略了在struts.xml中配置和引用该 * 的代码,本小节将详细的介绍如何在struts.xml中定义和引用我们自定义实现的 * 类。
从struts-default.xml中我们可以看出来,我们使用<interceptors>元素定义 * name和物理位置的配对,例如:
<interceptors>
<interceptor name="test" class="MyPackage.TestAction"/>
......
......
</interceptors>
上述代码定义了一个 * test,它对应于具体的一个class。需要注意的是,定义 * 的元素 interceptors 及其子元素必须被配置在某个package包下。
以上只是定义了一个 * 和具体 * 实现类之间的映射关系,但是想要实现对某个具体的action的拦截需要使用元素<interceptor-ref>根据name属性值引用一个上述已经定义了的 * 。例如:
<action name="test" class="MyPackage.TestAction">
<interceptor-ref name="test"/>
<result name="success">/index.jsp</result>
......
......
</action>
正如上述代码展示的一样,该元素用于引用一个已经定义好了的 * ,并且该元素出现在具体的action内部,表明了该action具有一个test * 。以上代码实现了对单个 * 的定义和引用,其实对于 * 栈(一堆 * 的组合)来说配置也是类似的。定义一个 * 栈的代码是如下的:
<interceptor-stack name=" * 栈名">
interceptor-ref name=" * 一"/>
interceptor-ref name=" * 二"/>
interceptor-ref name=" * 三"/>
.....
</interceptor-stack>
引用一个 * 栈就没什么区别了:
interceptor-ref name=" * 栈名"/>
当然我们也可以通过
<default-interceptor-ref name=" * 名"/>
配置默认 * 或者 * 栈,如果该包下某个action没有显式指定 * ,那么就会调用该默认 * ,否则如果显式配置了 * ,那么默认 * 将会失效。
四、为Action中指定方法配置 *
在默认情况下,我们为action配置了 * 之后,该 * 将会拦截该action中所有的方法,这有时候会给我们带来麻烦,当然struts为我们提供API用来针对具体的某个方法配置 * 。这里涉及到一个抽象类:MethodFilterInterceptor。该类实际上实现了Interceptor并完成了一些默认实现,我们简单看看其中的代码:
public abstract class MethodFilterInterceptor
extends AbstractInterceptor
{
//该set集合保存了该 * 不需要拦截的所有方法
protected Set<String> excludeMethods = Collections.emptySet();
//该set集合保存了所有该 * 需要拦截的方法
protected Set<String> includeMethods = Collections.emptySet();
//省略getter,setter方法
//用于拦截action的入口
public String intercept(ActionInvocation invocation)
throws Exception
{
if (applyInterceptor(invocation)) {
return doIntercept(invocation);
}
return invocation.invoke();
}
//判断当前需要调用的action处理逻辑方法是否需要被此 * 拦截
protected boolean applyInterceptor(ActionInvocation invocation)
{
String method = invocation.getProxy().getMethod();
boolean applyMethod = MethodFilterInterceptorUtil.applyMethod(this.excludeMethods, this.includeMethods, method);
if ((this.log.isDebugEnabled()) &&
(!applyMethod)) {
this.log.debug("Skipping Interceptor... Method [" + method + "] found in exclude list.", new String[0]);
}
return applyMethod;
}
//这是需要我们重写的方法,具体作用下文介绍
protected abstract String doIntercept(ActionInvocation paramActionInvocation)
throws Exception;
}
从上述代码中可以看出,该抽象类实现了Interceptor接口并完成了基本的实现。除此之外,该类提供了两个集合用于保存该 * 需要拦截的所有方法和不需要拦截的所有方法, * 入口intercept中会首先判断此次请求action实例中的逻辑处理方法是否需要被该 * 拦截,如果需要被拦截,那么将会调用doIntercept我们自己实现的 * 逻辑。否则直接调用invoke方法执行处理逻辑。所以一般来说,我们只需要重写doIntercept方法完成 * 的核心处理即可。
当然此处需要注意一点的是,用于判断当前请求的处理逻辑方法是否需要被该 * 拦截的方法applyInterceptor是在intercept中进行校验的,也就是说在执行doIntercept方法之前excludeMethods和includeMethods的值应当是已经初始化完毕了的。所以我们在doIntercept中再次为这两个属性赋值是没用的,因为已经完成了校验。一般我们在struts.xml中为这两个属性赋值,因为该配置文件是先被加载的。下面我们看个实例:
//自定义一个 *
public class MyIntercept extends MethodFilterInterceptor {
protected String doIntercept(ActionInvocation action)
throws Exception{
System.out.println("拦截开始......");
String result = action.invoke();
System.out.println("拦截结束......");
return result;
}
}
//引用该 * 并指定不需要拦截的方法
<action name="test" class="MyPackage.TestAction">
<interceptor-ref name="test">
<param name="excludeMethods">execute</param>
</interceptor-ref>
<result name="success">/index.jsp</result>
</action>
下面我们看运行的结果截图:
显然我们指明了该 * 不用拦截方法execute,当然结果显示的也是如我们所愿。如果我们修改上述struts.xml中内容:
<action name="test" class="MyPackage.TestAction">
<interceptor-ref name="test">
<param name="includeMethods">execute</param>
</interceptor-ref>
<result name="success">/index.jsp</result>
</action>
我们指定该execute方法是需要被 * 拦截的,下面运行的结果截图:
当然如果需要指定多个方法需要被拦截或者不用被拦截,可以使用英文逗号隔开这些方法,例如:
<param name="includeMethods">方法一,方法二,方法三</param>
最后还有一点是:如果一个方法既被放在了includeMethods中也被放在了excludeMethods中,那么框架将会选择拦截该方法。
五、有关 * 机制的其他一些细节
* 的执行顺序是按照引用 * 的顺序决定的,例如我们定义两个 * :
<action name="test" class="MyPackage.TestAction">
<interceptor-ref name="test"/>
<interceptor-ref name="test2"/>
<result name="success">/index.jsp</result>
</action>
也就是说第一个 * 拦截action之后,会调用invoke方法,如果还有其他 * 则会调用下一个 * ,一层层嵌套,最后结束最外层的 * 。
上述实例中我们使用param参数为 * 类中的includeMethods属性赋值,但是如果是一个 * 栈中我们有该如何为其中某个具体的 * 属性赋值呢?
<interceptor-ref name=" * 栈">
<param name=" * 一.属性名">属性值</param>
</interceptor-ref>
至此,我们简单了解了有关struts2中 * 器的相关知识,如需深刻理解还要在具体项目中体会,总结不到之处,望海涵!
来源:http://www.cnblogs.com/yangming1996/p/6902752.html?utm_source=tuicool&utm_medium=referral


猜你喜欢
- 前期准备首先要先明确有个大体的思路,要实现什么样的功能,了解完成整个模块要运用到哪些方面的知识,以及从做的过程中去发现自己的不足。技术方面的
- 本项目为大家分享了Java实现简单计算器功能的具体代码,供大家参考,具体内容如下一 项目说明实训目的:掌握 Java GUI 开发中的布局管
- 一:问题引入前面讲到用户支付完成之后微信支付服务器会发送回调通知给商户,商户要能够正常处理这个回调通知并返回正确的状态码给微信支付后台服务器
- 快速普及1、mybatis是什么 mybatis是一个支持普通SQL查询,存储过
- 在学习monkeyrunner之前,让我们先搭建好eclipse安卓开发环境。对于程序开发人员而言,eclipse并不陌生,它提供了一个非常
- 本文实例讲述了C#简单实现显示中文格式星期几的方法。分享给大家供大家参考,具体如下:1.DateTime.Now.ToString(&quo
- SpringBoot @ConditionalOnBean实现原理在SpringBoot1.5.X时判断条件是OR,SpringBoot2.
- 前提:微信公众平台:注册微信认证的公众号也就是服务号 ,拥有跟高级权限的微信接口。(注册服务号需要一些企业信息,需自己或者公司解决)注: 2
- 一,下载Zookeeper,地址为http://archive.apache.org/dist/zookeeper/,找到你要下载的版本,我
- 在项目中,有时候会用到领域枚举和DTO枚举的映射和转换。有一个现实的问题是:如果领域枚举项发生变化,而DTO枚举项没有及时更新,这样会造成映
- 使用注解的形式,装配在id字段,自动调用fegin赋值给目标字段。使用效果1.先给vo类中字段添加注解 2.调用feignData
- 概述 Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,被称之为 Android 世界的Swift,由 JetBr
- 目录 一、Implicit和Explicit1、Implicit2、、Explicit先上一段奇怪的代码:if (dto.Paym
- 概述:@ResponseBody @RequestMapping(value="/download/{fileName:[a-zA
- 先给大家展示下效果图,如果大家感觉不错,请参考使用方法,效果图如下所示:使用方法:录音工具类:AudioRecoderUtils.java,
- 前言平时日常开发用得最多是Http通讯,接口调试也比较简单的,也有比较强大的框架支持(OkHttp)。个人平时用到socket通讯的地方是A
- 小伙伴私信我说想要研究下Spring的源码,想让我出一期教程来实现IDEA导入Spring源码,今天它来了~版本 :IDEA 2020.2.
- 现在的手游基本都是重复操作,一个动作要等好久,结束之后继续另一个动作.很麻烦,所以动起了自己写一个游戏辅助的心思.这个辅助本身没什么难度,就
- 1.其中包括下载JDBC FRO Microsft SQL_Server2000的驱动程序(在微软官方网站下的,是sp3版的,这里就不写具体
- 一、项目简述环境配置:Jdk1.8 + Tomcat8.5 + mysql + Eclispe(IntelliJ IDEA,Eclispe,