Struts2
来源:互联网 发布:java 线程挂起与恢复 编辑:程序博客网 时间:2024/05/23 09:40
一:背景
struts2 的前身是webwork,WebWord的前身是Xwork,Xwork的延伸是命令模式.
Struts 2以WebWork优秀的设计思想为核心,吸收了Struts 1的部分优点,建立了一个兼容WebWork和Struts 1的MVC框架。
Struts 2的目标是希望可以让原来使用Struts 1、WebWork的开发人员,都可以平稳过渡到使用Struts 2框架。
二:struts2 的工作流程及其原理 Struts2简单请求流程介绍
(参考 有详细源代码分析:http://www.javaeye.com/topic/450979)
1、客户端发送请求
2、请求先通过ActionContextCleanUp-->FilterDispatcher
3、FilterDispatcher通过ActionMapper来决定这个Request需要调用哪个Action
4、如果ActionMapper决定调用某个Action,FilterDispatcher把请求的处理交给ActionProxy,这儿已经转到它的Delegate--Dispatcher来执行
5、ActionProxy根据ActionMapping和ConfigurationManager找到需要调用的Action类
6、ActionProxy创建一个ActionInvocation的实例
7、ActionInvocation调用真正的Action,当然这涉及到相关拦截器的调用
8、Action执行完毕,ActionInvocation创建Result并返回,当然,如果要在返回之前做些什么,可以实现PreResultListener。添加PreResultListener可以在Interceptor中实现,
Result对象可以是jsp,freemarker 等等表现层的技术。
三、struts2与struts1的区别
— 在Action实现类方面的对比:
Struts 1要求Action类继承一个抽象基类;Struts 1的一个具体问题是使用抽象类编程而不是接口。Struts 2 Action类可以实现一个Action接口,也可以实现其他接口,使可选
和定制的服务成为可能。Struts 2提供一个ActionSupport基类去实现常用的接口。即使Action接口不是必须实现的,只有一个包含execute方法的POJO类都可以用 作Struts
2的Action。
----- 线程模式方面的对比:
Struts 1 Action是单例模式并且必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts 1 Action能做的事,并且要在开发
时特别小心。Action资源必须是线程安全的或同步的;Struts 2 Action对象为每一个请求产生一个实例,因此没有线程安全问题。
---- Servlet依赖方面的对比:
Struts 1 Action依赖于Servlet API,因为Struts 1 Action的execute方法中有HttpServletRequest和HttpServletResponse参数。Struts 2 Action不再依
赖于Servlet API,从而允许Action脱离Web容器运行,从而降低了测试Action的难度。 当然,如果Action需要直接访问HttpServletRequest和
HttpServletResponse参数,Struts 2 Action仍然可以访问它们。但是,大部分时候,Action都无需直接访问HttpServetRequest和 HttpServletResponse,从
而给开发者更多灵活的选择。
— 可测性方面的对比:
测试Struts 1 Action的一个主要问题是execute方法依赖于Servlet API,这使得Action的测试要依赖于Web容器。为了脱离Web容器测试Struts 1的Action,
必须借助于第三方扩展:Struts TestCase,该扩展下包含了系列的Mock对象(模拟了HttpServetRequest和HttpServletResponse对象),从而 可以脱离
Web容器测试Struts 1的Action类。Struts 2 Action可以通过初始化、设置属性、调用方法来测试。
— 封装请求参数的对比:
Struts 1使用ActionForm对象封装用户的请求参数,所有的ActionForm必须继承一个基类:ActionForm。普通的JavaBean不能用 作ActionForm,因此,开发
者必须创建大量的ActionForm类封装用户请求参数。虽然Struts 1提供了动态ActionForm来简化ActionForm的开发,但依然需要在配置文件中定
ActionForm;Struts 2直接使用Action属性来封装用户请求属性,避免了开发者需要大量开发ActionForm类的烦琐,实际上,这些属性还可以是包含子属性的
Rich 对象类型。如果开发者依然怀念Struts 1 ActionForm的模式,Struts 2提供了ModelDriven模式,可以让开发者使用单独的Model对象来封装用户请求参
数,但该Model对象无需继承任何Struts 2基类,是一个POJO,从而降低了代码污染。
— 表达式语言方面的对比:
Struts 1整合了JSTL,因此可以使用JSTL表达式语言。这种表达式语言有基本对象图遍历,但在对集合和索引属性的支持上则功能不强;Struts 2可以使用
JSTL,但它整合了一种更强大和灵活的表达式语言:OGNL(Object-Graph Navigation Language),因此,Struts 2下的表达式语言功能更加强大。
— 绑定值到视图的对比:
Struts 1使用标准JSP机制把对象绑定到视图页面;Struts 2使用“ValueStack”技术,使标签库能够访问值,而不需要把对象和视图页面绑定在一起。
— 类型转换的对比:
Struts 1 ActionForm 属性通常都是String类型。Struts 1使用Commons-Beanutils进行类型转换,每个类一个转换器,转换器是不可配置的;Struts 2使OGNL
进行类型转换,支持基本数据类型和常用对象之间的转换。
— 数据校验的对比:
Struts 1支持在ActionForm重写validate方法中手动校验,或者通过整合Commons alidator框架来完成数据校验。Struts 2支持通过重写validate方法进行校验,
也支持整合XWork校验框架进行校验。
--- Action执行控制的对比:
Struts 1支持每一个模块对应一个请求处理(即生命周期的概念),但是模块中的所有Action必须共享相同的生命周期。Struts 2支持通过拦截器堆栈
(Interceptor Stacks)为每一个Action创建不同的生命周期。开发者可以根据需要创建相应堆栈,从而和不同的Action一起使用。
四; WebWork和Struts 2对比(面试话题 一点点扩展)
从某种程度上来看,Struts 2是WebWork的升级,而不是Struts 1的升级,甚至在Apache的Struts 2的官方文档都提到:WebWork到Struts 2是一次平滑的过渡。实际
上,Struts 2.0其实是WebWork 2.3而已,从WebWork 2.2迁移到Struts 2.0不会比从WebWork 2.1到2.2更麻烦。在很多方面,Struts 2仅仅是改变了WebWork下的名称,因此,
如果开发者具有WebWork的开发经验,将可以更加迅速地进入Struts 2的开发领域。下面是Struts 2与WebWork命名上存在改变(见表1.1):
表1.1 Struts 2和WebWork成员名称的对应
Struts 2成员
Struts 2成员 WebWork成员
com.opensymphony.xwork2.* com.opensymphony.xwork.*
org.apache.Struts2.* com.opensymphony.webwork.*
struts.xml xwork.xml
struts.properties webwork.properties
Dispatcher DispatcherUtil
org.apache.Struts2.config.Settings com.opensymphony.webwork.config.Configuration
除此之外,Struts 2也删除了WebWork中少量特性:
--- AroundInterceptor:
Struts 2不再支持WebWork中的AroundInterceptor。如果应用程序中需要使用AroundInterceptor,则应该自己手动导入WebWork中的AroundInterceptor类。
— 富文本编辑器标签:
Struts 2不再支持WebWork的富文本编辑器,如果应用中需要使用富文本编辑器,则应该使用Dojo的富文本编辑器。
--- IoC容器支持:
Struts 2不再支持内建的IoC容器,而改为全面支持Spring的IoC容器,以Spring的IoC容器作为默认的Object工厂。
五、struts2的属性驱动和模型驱动:
Struts2的属性驱动指的是在action中JSP页面的每一个form中的name都对应在action中有一个属性与之对应。
当表单提交到Action后,Struts2将会自动将根据表单的name属性调用Action中相应的属性setter,去自动赋值。
Struts2的模型驱动,它需要一个pojo对象封装表单属性,然后action类必须要实现ModelDriven接口,并重写getModel方法,
同时Action提供一个这个封装表单属性的对象(私有),并提供相应的getter与setter,
这样在表单数据提交到action时,action就会自动将表单的属性值赋值到这个pojo对象中,模型驱动的好处就是使得struts2的action类里
更加清晰,更好地体现类的单一职责原则
六、OGNL表达式:
OGNL,全称是Object-Graph Navigation Language,中文意思就是对象图导航语言,它是一种功能强大的表达式语言(Expression Language,简称为EL),通过它简单一致的
表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。Struts2.x中使用OGNL
取代原来的EL来做界面数据绑定,所谓界面数据绑定,也就是把界面元素(例如一个textfield,hidden)和对象层某个类的某个属性绑定在一起,修改和显示自动同步这样就可以支
持在jsp页面来进行对象方法调用,如MyClass.doSomething();它还支持类静态的方法调用和值访问,调用静态方法的表达式或值的格式为@[类全名(包括包路径)]@[方法名|值
名]例如调用静态方法:@java.lang.String@format('foo %s', 'bar');调用静态属性值:@tutorial.MyConstant@APP_NAME;Struts2使用ognl的上下文环境中,包含
request,session,application等servlet对象的Map封装,所以可以直接通过#符号来对这些变量的值进行访问,
而这样做最大地好处就是降低了servlet与action之间的耦合度,从而struts2就弥补了struts1难以调试的缺陷,
如:
七、优缺点:
1、简化设计,类与类之间是松散的耦合;
2、简化Action,Struts2中Action摇身变为普通的JAVA类,任何具有execute()方法的类都可以作为Struts2的Action,不必实现某个接口、继承某个类;
3、取消了ActionForm类,Action可以直接获得用户参数;
4、易于测试;
5、智能的默认配置;
6、改进返回值,不同于ActionForwards,Struts2的Action能返回多种类型的数据;
7、Struts2的标签库提供了对JSF、Freemarkerdede的支持;
8、快速启动;
9、与Spring整合;
10、支持Ajax;八. Struts 2的标签库
参考网址:http://su3390.blog.51cto.com/176528/41190
标签:标签使我们开发JSP画面的时候使用的最小组件单元,一小段代码,在JSP,Velocity或者FreeMarker中执行。程序开发的最小单位,用来生成HTML对应
的元素我们根据客户的需要组合各种Tag达到客户的需求
1:通用标签:用来在页面表示的时候控制代码执的过程,这些标签也允许从Action或者值堆栈中取得数据
* 控制标签控制程序执行,例如:if,append,iterator
If标签:用来控制基本的条件处理流程,通常和else标签或者elseif标签连用
append标签:用来做iterator标签的辅助,将不同iterator中的内容合在一个iterator中
iterator标签:迭代处理一个java.util.Connection或者java.util.Iterator对象
* 数据标签管理数据的取得和创建,例如:bean,push,i18n
il8n:描述:加载资源包到值堆栈。它可以允许text标志访问任何资源包的信息,而不只当前action相关联的资源包。
2:UI标签:UI标签主要是指Form相关的标签,每一个UI标签都是基于模板的,即:每一个标签都有一个对应的模板用来生成UI标签的样式
九.Struts 2的控制器组件
参考网址:http://hi.baidu.com/hjysuccess/blog/item/5e7727601409c041ebf8f8f7.html
1:FilterDispatcher(核心控制器) FilterDispatcher 是struts2框架的核心控制器,该控制器作为一个Filter运行在Web应用中,它负责拦截所有用户请求,当用户请求到达
时,该Filter会过滤 用户请求。如果用户请求以.action结尾,该请求将被转入struts2框架处理。
里面主要有三个方法: Init():初始化filter方法 destroy():销毁filter方法 doFilter():在此方法中,将调用dispatcher.serviceAction,该方法如果找到相应的
Action,将把用户请求交给ActionProxy
2:Action(业务控制器) 业务控制器Action是由开发者自己编写实现的,Action类可以是一个简单的Java类,无需实现任何父接
口,无需继承任何Struts2基类,与Servlet API完全分离。Action一般都有一个execute()方法,该方法返回一个字符串,该字符串就是一个逻辑视图名,每个字符串对应一个视图
名,在Action类里也可以定义其他业务控制方法 它的优点: * Action类完全是一个POJO,因此具有很好的代码复用性。
* Action类无需与Servlet API耦合,因此进行单元测试非常简单。
* Action类的execute方法仅返回一个字符串作为处理结果,该处理结果可映射到任何的视图,甚至是另一个Action。
十.struts2 Action 的优势
该Action类有如下优势:
--- Action类完全是一个POJO,因此具有很好的代码复用性。
--- Action类不与Servlet API耦合,因此进行单元测试非常简单。
--- Action类的execute方法仅返回一个字符串作为处理结果,该处理结果可映射到任何的视图,甚至是另一个Action。
十一.使用Struts 2的校验框架
一种验证就是采用xwork框架进行验证。首先,action类要extends ActionSupport
一种是使用AJAX 校验
十二.struts2 有哪几种主题
Struts2默认提供了四种主题:
Simple 主题:最简单的主题
simple主题是最简单的主题,它是最底层的结构,主要用于构建附加的功能或者行为(例如在此主题基础上进行扩展),使用simple主题时,每个UI标签只生成一个简单的HTML
元素,不会生成其他额外的内容。
Struts2的xhtml, css_xhtml主题都是对simple主题的包装和扩展。
XHTML 主题:默认主题,使用常用的HTML技巧
xhtml主题是Struts2的默认主题,它对simple主题进行扩展,在该主题的基础上增加了如下附加的特性:
1,针对HTML标签(如textfield和select标签)使用标准的两列表格布局。
2,每个HTML标签的Label,即可以出现在HTML元素的左边,也可以出现在上边,这取决于labelposition属性的设置。
3,自动输出校验错误信息。
4,输出JavaScript的客户端校验。
CSS XHTML主题: 使用CSS实现的XHTML主题
css_xhtml主题则对原有的xhtml主题进行了扩展,在xhtml主题基础上加入了CSS样式控制。
AJAX 主题:基于XHTML主题,但是同工了AJAX功能
ajax主题目对xhtml主题目进行了扩展,在xhtml主题上为每个标签提供了额外的Ajax支持。ajax主题的Ajax支持是以Dojo和DWR为基础的。ajax主题在xhtml主题基础上增加了如
下特性:
1,支持Ajax方式的客户端校验。
2,支持远程表单的异步提交(最好和submit标签一起使用)。
3,提供高级的div标签,允许实现局部更新部分HTML的功能。
4,提供高级的a标签,允许动态加载并执行远端的javaScript代码。
5,提供支持ajax的tabbedPanel。
6,提供"富客户端"模型的pub-sub事件模型。
十三.struts2 的国际化
struts2的国际化大致上分为
页面的国际化,
Action的国际化
xml的国际化
首先在struts.properties文件中加入以下内容:
struts.custom.i18n.resources=messageResource
或在struts.xml中加入
<constant name="struts.custom.i18n.resources" value="messageResource"></constant>
资源文件的命名格式: 名称_语言代码_国家代码. Properties
如果创建中文和英语国际化,那么资源文件名称为
messageResource_zh_CN.properties和messageResource_en_US.properties
1. jsp页面的国际化
通过使用标签输出国际化
label.helloWorld为资源文件中定义的key label.helloWorld=你好,世界
在messageResource_en_US.properties加入以下内容
label.hello=hello{0}
label.helloWorld=hello,world
在messageResource_zh_CN.properties加入以下内容
label.hello=你好{0}
(1). 上面两个都为输出一个hello word的两种表示
显示一个文本框,文本框的标题进行国际化
(2). 使用标签指定从某个特定的资源文件中取数据
指定在从messageResource取资源
(3). callan使用带参数的资源.可以替换label.hello=hello{0}中的{0}
2. Action的国际化
Action的国际化主要是通过getText(String key)方法实现的
Java代码
public String execute() throws Exception {
// getText(String) string为key
String str1 = getText("label.helloWorld");
System.out.println(str1);
// 带参数的
String str2 = getText("label.hello",new String[]{"fjf"{color:black}}); #
System.out.println(str2);
// 与上一种实现一样
List l = new ArrayList();
l.add("callan");
String str3 = getText("label.hello",l);
System.out.println(str3);
return SUCCESS;
}
3. 参数化国际化
在messageResource_en_US.properties加入以下内容
userName=userName
userName.required=${getText('userName')} is required
在messageResource_zh_CN.properties加入以下内容
userName=用户名
userName.required=${getText('userName')} 不能为空
在Action中
String str4 = getText("userName.required");
System.out.println(str4);
4. 使用校验框价时,提示信息可以国际化
<field name="userName">
<field-validator type="requiredstring">
<message key=”userName.required”> </message>
</field-validator>
</field>
国际化资源文件分为三种级别
(1) --全局资源文件,可以被整个应该程序引用,它的资源文件放在src目录下,需要在struts.xml中定义常量声明, 在WEB-INF"classes目录下建立一个struts.properties文件,内容
如下: struts.custom.i18n.resources=my 指定的文件在WEB-INF\classes目录下建立一个my.properties文件,当Struts2按着上述的顺序没有找到相应的属性文件时,最后就
会考虑寻找全局 的属性文件,因此,就会找到my.properties。
---局部的国际化资源文件分为包级别的、和类级别的。
包级别和类级别的国际化资源文件均是放在包目录下,
包级别的命名为:package_language_country.properties,作用范围为当前包中的所有类
类级别的命名为:类名_language_country.properties,作用范围为当前类 ---当里面有同名的信息时,类级别的信息会覆盖包级别,包级别会覆盖全局的
(2) 包级资源文件,每个包的根目录下可以新建资源文件,仅被当前包中的类访问.文件名格式为:package_语言代码_国家代码.
(3) Action级资源文件,仅被当前Action引用,名称为action名_语言代码_国家代码 查找顺序为从小范围到大范围, Action级优先级最大
网上资料(供参考)
struts2 默认拦截器介绍(面试时候可以进行一些发散,觉得值得一看)
附带网址:http://blog.csdn.net/jxplus/archive/2009/02/26/3938897.aspx
Interceptor(拦截器)将Action共用的行为独立出来,在Action执行前后运行。这也就是我们所说的AOP(Aspect Oriented Programming,面向切面编程),它是分散
关注的编程方法,它将通用需求功能从不相关类之中分离出来;同时,能够使得很多类共享一个行为,一旦行为发生变化,不必修改很多类,只要修改这个行为就可以。
Interceptor将很多功能从我们的Action中独立出来,大量减少了我们Action的代码,独立出来的行为具有很好的重用性。XWork、WebWork的许多功能都是有Interceptor实
现,可以在配置文件中组装Action用到的Interceptor,它会按照你指定的顺序,在Action执行前后运行。Interceptor在框架中的应用如下图所示当你提交对Aciton(默认
是.action结尾的Url)的请求时,ServletDispatcher会根据你的请求,去调度并执行相应的Action。在Action执行之前,调用被 Interceptor截取,Interceptor在
Action执行前后 运行。
<interceptors>
<interceptor name="timer" class="com.opensymphony.xwork.interceptor.TimerInterceptor"/>
<interceptor name="logger" class="com.opensymphony.xwork.interceptor.LoggingInterceptor"/>
<interceptor name="chain" class="com.opensymphony.xwork.interceptor.ChainingInterceptor"/>
<interceptor name="static-params" class="com.opensymphony.xwork.interceptor.StaticParametersInterceptor"/>
<interceptor name="params" class="com.opensymphony.xwork.interceptor.ParametersInterceptor"/>
<interceptor name="model-driven" class="com.opensymphony.xwork.interceptor.ModelDrivenInterceptor"/>
<interceptor name="component" class="com.opensymphony.xwork.interceptor.component.ComponentInterceptor"/>
<interceptor name="token" class="com.opensymphony.webwork.interceptor.TokenInterceptor"/>
<interceptor name="token-session" class="com.opensymphony.webwork.interceptor.TokenSessionStoreInterceptor"/>
<interceptor name="validation" class="com.opensymphony.xwork.validator.ValidationInterceptor"/>
<interceptor name="workflow" class="com.opensymphony.xwork.interceptor.DefaultWorkflowInterceptor"/>
<interceptor name="servlet-config" class="com.opensymphony.webwork.interceptor.ServletConfigInterceptor"/>
<interceptor name="prepare" class="com.opensymphony.xwork.interceptor.PrepareInterceptor"/>
<interceptor name="conversionError" class="com.opensymphony.webwork.interceptor.WebWorkConversionErrorInterceptor"/>
<interceptor-stack name="defaultStack">
<interceptor-ref name="static-params"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
</interceptor-stack>
</interceptors>
这些都时有框架提供的默认的Interceptor,下面我来看看Interceptor使用的步骤:
1、 创建一个自己需要的Interceptor类,它必需实现
com.opensymphony.xwork.interceptor.Interceptor接口,具体的开发见下面的Interceptor的原理。
2、 在配置文件(xwork..xml)中申明这个Interceptor类,它放在标签<interceptor />中,同是<interceptor />标签嵌入在<interceptors />标签内部。
3、 创建Interceptor栈,使用标签:<interceptor-stack />,让一组Interceptor可以按次序调用。(可选)
4、 指定Action所要用到的Interceptor(前面申明过的),可以用<interceptor-ref />或<default-interceptor-ref />标签。前面的标签指定某个Action所用到的Interceptor,如果
Action没有被用<interceptor-ref />指定Interceptor,它将使用<default-interceptor-ref />指定的Interceptor。
框架中给我们提供了很多实用的Interceptor,它的定义上面已经给出,它的具体功能如下:
l timer:记录Action执行的时间,并做为日志信息输出;
l logger:在日志信息中输出要执行的Action信息;
l chain:将前一个执行结束的Action属性设置到当前的Action中。它被用在ResultType为“chain”指定结果的Action中,该结果Action对象会从OgnlValueStack中获得前一个
Action对应的属性,它实现Action链之间的数据传递;
l static-params:将xwork.xml配置文件里定义的Action参数,设置到对应的Action中。Action参数使用<param />标签,是<action />标签的直接子元素。我们这里定义的
Action类必需实现com.opensymphony.xwork.config.entities. Parameterizable接口;
l params:将Request请求的参数设置到相应Action对象的属性中,用户注册例子用到过这个拦截器;
l model-driven:如果Action实现ModelDriven接口,它将getModel()取得的模型对象存入OgnlValueStack中;
l component:激活组件功能支持,让注册过的组件在当前Action中可用,即为Action提供IoC(依赖倒转控制)框架的支持;
l token:核对当前Action请求(request)的有效标识,防止重复提交Action请求(request)。
l token-session:功能同上,但是当提交无效的Action请求标识时,它会将请求数据保存到session中。
l validation:实现使用xml配置文件(
Unknown macro: {Action}
-validation.xml)对Action属性值进行验证,详细请看后面介绍的验证框架。
l workflow:调用Action类的验证功能,假设Action使用ValidationAware实现验证(ActionSupport提供此功能),如果验证没有通过,workflow会将请求返回到input视图(Action的<result />中定义的)。
l servlet-config:提供Action直接对HttpServletRequest或HttpServletResponse等JavaServlet api的访问,Action要实现相应的接口,例如:ServletRequestAware或
ServletResponseAware等。如果必需要提供对JavaServlet api的访问,我们建议使用ServletActionContext,在前面ActionContext章节中有介绍。
l prepare:在Action执行之前调用Action的prepare()方法,这个方法是用来准备Action执行之前要做的工作。它要求我们的Action必需实现
com.opensymphony.xwork. Preparable接口
conversionError:用来处理框架进行类型转化(Type Conversion)时的出错信息。它将存储在ActionContext中的类型转化(Type Conversion)错误信息转化成相应的Action字段
的错误信息,保存在堆栈中。根据需要,可以将这些错误信息在视图中显示出来。
Interceptor的原理
下面我们来看看Interceptor是如何实现在Action执行前后调用的:
Action和Interceptor在框架中的执行,是由ActionInvocation对象调用的。它是用方法:String invoke() throws Exception;来实现的,它首先会依次调用Action对应的
Interceptor,执行完成所有的Interceptor之后,再去调用Action的方法,代码如下:
if (interceptors.hasNext()) {
Interceptor interceptor = (Interceptor) interceptors.next();
resultCode = interceptor.intercept(this);
} else {
if (proxy.getConfig().getMethodName() == null) {
resultCode = getAction().execute();
} else {
resultCode = invokeAction(getAction(), proxy.getConfig());
}
它会在拦截器栈中遍历Interceptor,调用Interceptor的方法:
String intercept(ActionInvocation invocation) throws Exception;。
我们一直都提到,Interceptor是在Action前后执行,可是从上面的代码我们看到的却是执行完所有Interceptor的intercept()方法之后再去调用我们的Action。“在Action前后执行”是
如何实现的呢?我们来看看抽象类AroundInterceptor的intercept()实现:
public String intercept(ActionInvocation invocation) throws Exception {
String result = null;
before(invocation);
result = invocation.invoke();
after(invocation, result);
return result;
}
原来在intercept()方法又对ActionInvocation的invoke()方法进行递归调用,ActionInvocation循环嵌套在intercept()中,一直到语句result = invocation.invoke();执行结束,
即:Action执行完并返回结果result,这时Interceptor对象会按照刚开始执行的逆向顺序依次执行结束。这样before()方法将在Action执行前调用,after()方法在Action执行
之后运行
struts2 的前身是webwork,WebWord的前身是Xwork,Xwork的延伸是命令模式.
Struts 2以WebWork优秀的设计思想为核心,吸收了Struts 1的部分优点,建立了一个兼容WebWork和Struts 1的MVC框架。
Struts 2的目标是希望可以让原来使用Struts 1、WebWork的开发人员,都可以平稳过渡到使用Struts 2框架。
二:struts2 的工作流程及其原理 Struts2简单请求流程介绍
(参考 有详细源代码分析:http://www.javaeye.com/topic/450979)
1、客户端发送请求
2、请求先通过ActionContextCleanUp-->FilterDispatcher
3、FilterDispatcher通过ActionMapper来决定这个Request需要调用哪个Action
4、如果ActionMapper决定调用某个Action,FilterDispatcher把请求的处理交给ActionProxy,这儿已经转到它的Delegate--Dispatcher来执行
5、ActionProxy根据ActionMapping和ConfigurationManager找到需要调用的Action类
6、ActionProxy创建一个ActionInvocation的实例
7、ActionInvocation调用真正的Action,当然这涉及到相关拦截器的调用
8、Action执行完毕,ActionInvocation创建Result并返回,当然,如果要在返回之前做些什么,可以实现PreResultListener。添加PreResultListener可以在Interceptor中实现,
Result对象可以是jsp,freemarker 等等表现层的技术。
三、struts2与struts1的区别
— 在Action实现类方面的对比:
Struts 1要求Action类继承一个抽象基类;Struts 1的一个具体问题是使用抽象类编程而不是接口。Struts 2 Action类可以实现一个Action接口,也可以实现其他接口,使可选
和定制的服务成为可能。Struts 2提供一个ActionSupport基类去实现常用的接口。即使Action接口不是必须实现的,只有一个包含execute方法的POJO类都可以用 作Struts
2的Action。
----- 线程模式方面的对比:
Struts 1 Action是单例模式并且必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts 1 Action能做的事,并且要在开发
时特别小心。Action资源必须是线程安全的或同步的;Struts 2 Action对象为每一个请求产生一个实例,因此没有线程安全问题。
---- Servlet依赖方面的对比:
Struts 1 Action依赖于Servlet API,因为Struts 1 Action的execute方法中有HttpServletRequest和HttpServletResponse参数。Struts 2 Action不再依
赖于Servlet API,从而允许Action脱离Web容器运行,从而降低了测试Action的难度。 当然,如果Action需要直接访问HttpServletRequest和
HttpServletResponse参数,Struts 2 Action仍然可以访问它们。但是,大部分时候,Action都无需直接访问HttpServetRequest和 HttpServletResponse,从
而给开发者更多灵活的选择。
— 可测性方面的对比:
测试Struts 1 Action的一个主要问题是execute方法依赖于Servlet API,这使得Action的测试要依赖于Web容器。为了脱离Web容器测试Struts 1的Action,
必须借助于第三方扩展:Struts TestCase,该扩展下包含了系列的Mock对象(模拟了HttpServetRequest和HttpServletResponse对象),从而 可以脱离
Web容器测试Struts 1的Action类。Struts 2 Action可以通过初始化、设置属性、调用方法来测试。
— 封装请求参数的对比:
Struts 1使用ActionForm对象封装用户的请求参数,所有的ActionForm必须继承一个基类:ActionForm。普通的JavaBean不能用 作ActionForm,因此,开发
者必须创建大量的ActionForm类封装用户请求参数。虽然Struts 1提供了动态ActionForm来简化ActionForm的开发,但依然需要在配置文件中定
ActionForm;Struts 2直接使用Action属性来封装用户请求属性,避免了开发者需要大量开发ActionForm类的烦琐,实际上,这些属性还可以是包含子属性的
Rich 对象类型。如果开发者依然怀念Struts 1 ActionForm的模式,Struts 2提供了ModelDriven模式,可以让开发者使用单独的Model对象来封装用户请求参
数,但该Model对象无需继承任何Struts 2基类,是一个POJO,从而降低了代码污染。
— 表达式语言方面的对比:
Struts 1整合了JSTL,因此可以使用JSTL表达式语言。这种表达式语言有基本对象图遍历,但在对集合和索引属性的支持上则功能不强;Struts 2可以使用
JSTL,但它整合了一种更强大和灵活的表达式语言:OGNL(Object-Graph Navigation Language),因此,Struts 2下的表达式语言功能更加强大。
— 绑定值到视图的对比:
Struts 1使用标准JSP机制把对象绑定到视图页面;Struts 2使用“ValueStack”技术,使标签库能够访问值,而不需要把对象和视图页面绑定在一起。
— 类型转换的对比:
Struts 1 ActionForm 属性通常都是String类型。Struts 1使用Commons-Beanutils进行类型转换,每个类一个转换器,转换器是不可配置的;Struts 2使OGNL
进行类型转换,支持基本数据类型和常用对象之间的转换。
— 数据校验的对比:
Struts 1支持在ActionForm重写validate方法中手动校验,或者通过整合Commons alidator框架来完成数据校验。Struts 2支持通过重写validate方法进行校验,
也支持整合XWork校验框架进行校验。
--- Action执行控制的对比:
Struts 1支持每一个模块对应一个请求处理(即生命周期的概念),但是模块中的所有Action必须共享相同的生命周期。Struts 2支持通过拦截器堆栈
(Interceptor Stacks)为每一个Action创建不同的生命周期。开发者可以根据需要创建相应堆栈,从而和不同的Action一起使用。
四; WebWork和Struts 2对比(面试话题 一点点扩展)
从某种程度上来看,Struts 2是WebWork的升级,而不是Struts 1的升级,甚至在Apache的Struts 2的官方文档都提到:WebWork到Struts 2是一次平滑的过渡。实际
上,Struts 2.0其实是WebWork 2.3而已,从WebWork 2.2迁移到Struts 2.0不会比从WebWork 2.1到2.2更麻烦。在很多方面,Struts 2仅仅是改变了WebWork下的名称,因此,
如果开发者具有WebWork的开发经验,将可以更加迅速地进入Struts 2的开发领域。下面是Struts 2与WebWork命名上存在改变(见表1.1):
表1.1 Struts 2和WebWork成员名称的对应
Struts 2成员
Struts 2成员 WebWork成员
com.opensymphony.xwork2.* com.opensymphony.xwork.*
org.apache.Struts2.* com.opensymphony.webwork.*
struts.xml xwork.xml
struts.properties webwork.properties
Dispatcher DispatcherUtil
org.apache.Struts2.config.Settings com.opensymphony.webwork.config.Configuration
除此之外,Struts 2也删除了WebWork中少量特性:
--- AroundInterceptor:
Struts 2不再支持WebWork中的AroundInterceptor。如果应用程序中需要使用AroundInterceptor,则应该自己手动导入WebWork中的AroundInterceptor类。
— 富文本编辑器标签:
Struts 2不再支持WebWork的富文本编辑器,如果应用中需要使用富文本编辑器,则应该使用Dojo的富文本编辑器。
--- IoC容器支持:
Struts 2不再支持内建的IoC容器,而改为全面支持Spring的IoC容器,以Spring的IoC容器作为默认的Object工厂。
五、struts2的属性驱动和模型驱动:
Struts2的属性驱动指的是在action中JSP页面的每一个form中的name都对应在action中有一个属性与之对应。
当表单提交到Action后,Struts2将会自动将根据表单的name属性调用Action中相应的属性setter,去自动赋值。
Struts2的模型驱动,它需要一个pojo对象封装表单属性,然后action类必须要实现ModelDriven接口,并重写getModel方法,
同时Action提供一个这个封装表单属性的对象(私有),并提供相应的getter与setter,
这样在表单数据提交到action时,action就会自动将表单的属性值赋值到这个pojo对象中,模型驱动的好处就是使得struts2的action类里
更加清晰,更好地体现类的单一职责原则
六、OGNL表达式:
OGNL,全称是Object-Graph Navigation Language,中文意思就是对象图导航语言,它是一种功能强大的表达式语言(Expression Language,简称为EL),通过它简单一致的
表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。Struts2.x中使用OGNL
取代原来的EL来做界面数据绑定,所谓界面数据绑定,也就是把界面元素(例如一个textfield,hidden)和对象层某个类的某个属性绑定在一起,修改和显示自动同步这样就可以支
持在jsp页面来进行对象方法调用,如MyClass.doSomething();它还支持类静态的方法调用和值访问,调用静态方法的表达式或值的格式为@[类全名(包括包路径)]@[方法名|值
名]例如调用静态方法:@java.lang.String@format('foo %s', 'bar');调用静态属性值:@tutorial.MyConstant@APP_NAME;Struts2使用ognl的上下文环境中,包含
request,session,application等servlet对象的Map封装,所以可以直接通过#符号来对这些变量的值进行访问,
而这样做最大地好处就是降低了servlet与action之间的耦合度,从而struts2就弥补了struts1难以调试的缺陷,
如:
七、优缺点:
1、简化设计,类与类之间是松散的耦合;
2、简化Action,Struts2中Action摇身变为普通的JAVA类,任何具有execute()方法的类都可以作为Struts2的Action,不必实现某个接口、继承某个类;
3、取消了ActionForm类,Action可以直接获得用户参数;
4、易于测试;
5、智能的默认配置;
6、改进返回值,不同于ActionForwards,Struts2的Action能返回多种类型的数据;
7、Struts2的标签库提供了对JSF、Freemarkerdede的支持;
8、快速启动;
9、与Spring整合;
10、支持Ajax;八. Struts 2的标签库
参考网址:http://su3390.blog.51cto.com/176528/41190
标签:标签使我们开发JSP画面的时候使用的最小组件单元,一小段代码,在JSP,Velocity或者FreeMarker中执行。程序开发的最小单位,用来生成HTML对应
的元素我们根据客户的需要组合各种Tag达到客户的需求
1:通用标签:用来在页面表示的时候控制代码执的过程,这些标签也允许从Action或者值堆栈中取得数据
* 控制标签控制程序执行,例如:if,append,iterator
If标签:用来控制基本的条件处理流程,通常和else标签或者elseif标签连用
append标签:用来做iterator标签的辅助,将不同iterator中的内容合在一个iterator中
iterator标签:迭代处理一个java.util.Connection或者java.util.Iterator对象
* 数据标签管理数据的取得和创建,例如:bean,push,i18n
il8n:描述:加载资源包到值堆栈。它可以允许text标志访问任何资源包的信息,而不只当前action相关联的资源包。
2:UI标签:UI标签主要是指Form相关的标签,每一个UI标签都是基于模板的,即:每一个标签都有一个对应的模板用来生成UI标签的样式
九.Struts 2的控制器组件
参考网址:http://hi.baidu.com/hjysuccess/blog/item/5e7727601409c041ebf8f8f7.html
1:FilterDispatcher(核心控制器) FilterDispatcher 是struts2框架的核心控制器,该控制器作为一个Filter运行在Web应用中,它负责拦截所有用户请求,当用户请求到达
时,该Filter会过滤 用户请求。如果用户请求以.action结尾,该请求将被转入struts2框架处理。
里面主要有三个方法: Init():初始化filter方法 destroy():销毁filter方法 doFilter():在此方法中,将调用dispatcher.serviceAction,该方法如果找到相应的
Action,将把用户请求交给ActionProxy
2:Action(业务控制器) 业务控制器Action是由开发者自己编写实现的,Action类可以是一个简单的Java类,无需实现任何父接
口,无需继承任何Struts2基类,与Servlet API完全分离。Action一般都有一个execute()方法,该方法返回一个字符串,该字符串就是一个逻辑视图名,每个字符串对应一个视图
名,在Action类里也可以定义其他业务控制方法 它的优点: * Action类完全是一个POJO,因此具有很好的代码复用性。
* Action类无需与Servlet API耦合,因此进行单元测试非常简单。
* Action类的execute方法仅返回一个字符串作为处理结果,该处理结果可映射到任何的视图,甚至是另一个Action。
十.struts2 Action 的优势
该Action类有如下优势:
--- Action类完全是一个POJO,因此具有很好的代码复用性。
--- Action类不与Servlet API耦合,因此进行单元测试非常简单。
--- Action类的execute方法仅返回一个字符串作为处理结果,该处理结果可映射到任何的视图,甚至是另一个Action。
十一.使用Struts 2的校验框架
一种验证就是采用xwork框架进行验证。首先,action类要extends ActionSupport
一种是使用AJAX 校验
十二.struts2 有哪几种主题
Struts2默认提供了四种主题:
Simple 主题:最简单的主题
simple主题是最简单的主题,它是最底层的结构,主要用于构建附加的功能或者行为(例如在此主题基础上进行扩展),使用simple主题时,每个UI标签只生成一个简单的HTML
元素,不会生成其他额外的内容。
Struts2的xhtml, css_xhtml主题都是对simple主题的包装和扩展。
XHTML 主题:默认主题,使用常用的HTML技巧
xhtml主题是Struts2的默认主题,它对simple主题进行扩展,在该主题的基础上增加了如下附加的特性:
1,针对HTML标签(如textfield和select标签)使用标准的两列表格布局。
2,每个HTML标签的Label,即可以出现在HTML元素的左边,也可以出现在上边,这取决于labelposition属性的设置。
3,自动输出校验错误信息。
4,输出JavaScript的客户端校验。
CSS XHTML主题: 使用CSS实现的XHTML主题
css_xhtml主题则对原有的xhtml主题进行了扩展,在xhtml主题基础上加入了CSS样式控制。
AJAX 主题:基于XHTML主题,但是同工了AJAX功能
ajax主题目对xhtml主题目进行了扩展,在xhtml主题上为每个标签提供了额外的Ajax支持。ajax主题的Ajax支持是以Dojo和DWR为基础的。ajax主题在xhtml主题基础上增加了如
下特性:
1,支持Ajax方式的客户端校验。
2,支持远程表单的异步提交(最好和submit标签一起使用)。
3,提供高级的div标签,允许实现局部更新部分HTML的功能。
4,提供高级的a标签,允许动态加载并执行远端的javaScript代码。
5,提供支持ajax的tabbedPanel。
6,提供"富客户端"模型的pub-sub事件模型。
十三.struts2 的国际化
struts2的国际化大致上分为
页面的国际化,
Action的国际化
xml的国际化
首先在struts.properties文件中加入以下内容:
struts.custom.i18n.resources=messageResource
或在struts.xml中加入
<constant name="struts.custom.i18n.resources" value="messageResource"></constant>
资源文件的命名格式: 名称_语言代码_国家代码. Properties
如果创建中文和英语国际化,那么资源文件名称为
messageResource_zh_CN.properties和messageResource_en_US.properties
1. jsp页面的国际化
通过使用标签输出国际化
label.helloWorld为资源文件中定义的key label.helloWorld=你好,世界
在messageResource_en_US.properties加入以下内容
label.hello=hello{0}
label.helloWorld=hello,world
在messageResource_zh_CN.properties加入以下内容
label.hello=你好{0}
(1). 上面两个都为输出一个hello word的两种表示
显示一个文本框,文本框的标题进行国际化
(2). 使用标签指定从某个特定的资源文件中取数据
指定在从messageResource取资源
(3). callan使用带参数的资源.可以替换label.hello=hello{0}中的{0}
2. Action的国际化
Action的国际化主要是通过getText(String key)方法实现的
Java代码
public String execute() throws Exception {
// getText(String) string为key
String str1 = getText("label.helloWorld");
System.out.println(str1);
// 带参数的
String str2 = getText("label.hello",new String[]{"fjf"{color:black}}); #
System.out.println(str2);
// 与上一种实现一样
List l = new ArrayList();
l.add("callan");
String str3 = getText("label.hello",l);
System.out.println(str3);
return SUCCESS;
}
3. 参数化国际化
在messageResource_en_US.properties加入以下内容
userName=userName
userName.required=${getText('userName')} is required
在messageResource_zh_CN.properties加入以下内容
userName=用户名
userName.required=${getText('userName')} 不能为空
在Action中
String str4 = getText("userName.required");
System.out.println(str4);
4. 使用校验框价时,提示信息可以国际化
<field name="userName">
<field-validator type="requiredstring">
<message key=”userName.required”> </message>
</field-validator>
</field>
国际化资源文件分为三种级别
(1) --全局资源文件,可以被整个应该程序引用,它的资源文件放在src目录下,需要在struts.xml中定义常量声明, 在WEB-INF"classes目录下建立一个struts.properties文件,内容
如下: struts.custom.i18n.resources=my 指定的文件在WEB-INF\classes目录下建立一个my.properties文件,当Struts2按着上述的顺序没有找到相应的属性文件时,最后就
会考虑寻找全局 的属性文件,因此,就会找到my.properties。
---局部的国际化资源文件分为包级别的、和类级别的。
包级别和类级别的国际化资源文件均是放在包目录下,
包级别的命名为:package_language_country.properties,作用范围为当前包中的所有类
类级别的命名为:类名_language_country.properties,作用范围为当前类 ---当里面有同名的信息时,类级别的信息会覆盖包级别,包级别会覆盖全局的
(2) 包级资源文件,每个包的根目录下可以新建资源文件,仅被当前包中的类访问.文件名格式为:package_语言代码_国家代码.
(3) Action级资源文件,仅被当前Action引用,名称为action名_语言代码_国家代码 查找顺序为从小范围到大范围, Action级优先级最大
网上资料(供参考)
struts2 默认拦截器介绍(面试时候可以进行一些发散,觉得值得一看)
附带网址:http://blog.csdn.net/jxplus/archive/2009/02/26/3938897.aspx
Interceptor(拦截器)将Action共用的行为独立出来,在Action执行前后运行。这也就是我们所说的AOP(Aspect Oriented Programming,面向切面编程),它是分散
关注的编程方法,它将通用需求功能从不相关类之中分离出来;同时,能够使得很多类共享一个行为,一旦行为发生变化,不必修改很多类,只要修改这个行为就可以。
Interceptor将很多功能从我们的Action中独立出来,大量减少了我们Action的代码,独立出来的行为具有很好的重用性。XWork、WebWork的许多功能都是有Interceptor实
现,可以在配置文件中组装Action用到的Interceptor,它会按照你指定的顺序,在Action执行前后运行。Interceptor在框架中的应用如下图所示当你提交对Aciton(默认
是.action结尾的Url)的请求时,ServletDispatcher会根据你的请求,去调度并执行相应的Action。在Action执行之前,调用被 Interceptor截取,Interceptor在
Action执行前后 运行。
<interceptors>
<interceptor name="timer" class="com.opensymphony.xwork.interceptor.TimerInterceptor"/>
<interceptor name="logger" class="com.opensymphony.xwork.interceptor.LoggingInterceptor"/>
<interceptor name="chain" class="com.opensymphony.xwork.interceptor.ChainingInterceptor"/>
<interceptor name="static-params" class="com.opensymphony.xwork.interceptor.StaticParametersInterceptor"/>
<interceptor name="params" class="com.opensymphony.xwork.interceptor.ParametersInterceptor"/>
<interceptor name="model-driven" class="com.opensymphony.xwork.interceptor.ModelDrivenInterceptor"/>
<interceptor name="component" class="com.opensymphony.xwork.interceptor.component.ComponentInterceptor"/>
<interceptor name="token" class="com.opensymphony.webwork.interceptor.TokenInterceptor"/>
<interceptor name="token-session" class="com.opensymphony.webwork.interceptor.TokenSessionStoreInterceptor"/>
<interceptor name="validation" class="com.opensymphony.xwork.validator.ValidationInterceptor"/>
<interceptor name="workflow" class="com.opensymphony.xwork.interceptor.DefaultWorkflowInterceptor"/>
<interceptor name="servlet-config" class="com.opensymphony.webwork.interceptor.ServletConfigInterceptor"/>
<interceptor name="prepare" class="com.opensymphony.xwork.interceptor.PrepareInterceptor"/>
<interceptor name="conversionError" class="com.opensymphony.webwork.interceptor.WebWorkConversionErrorInterceptor"/>
<interceptor-stack name="defaultStack">
<interceptor-ref name="static-params"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
</interceptor-stack>
</interceptors>
这些都时有框架提供的默认的Interceptor,下面我来看看Interceptor使用的步骤:
1、 创建一个自己需要的Interceptor类,它必需实现
com.opensymphony.xwork.interceptor.Interceptor接口,具体的开发见下面的Interceptor的原理。
2、 在配置文件(xwork..xml)中申明这个Interceptor类,它放在标签<interceptor />中,同是<interceptor />标签嵌入在<interceptors />标签内部。
3、 创建Interceptor栈,使用标签:<interceptor-stack />,让一组Interceptor可以按次序调用。(可选)
4、 指定Action所要用到的Interceptor(前面申明过的),可以用<interceptor-ref />或<default-interceptor-ref />标签。前面的标签指定某个Action所用到的Interceptor,如果
Action没有被用<interceptor-ref />指定Interceptor,它将使用<default-interceptor-ref />指定的Interceptor。
框架中给我们提供了很多实用的Interceptor,它的定义上面已经给出,它的具体功能如下:
l timer:记录Action执行的时间,并做为日志信息输出;
l logger:在日志信息中输出要执行的Action信息;
l chain:将前一个执行结束的Action属性设置到当前的Action中。它被用在ResultType为“chain”指定结果的Action中,该结果Action对象会从OgnlValueStack中获得前一个
Action对应的属性,它实现Action链之间的数据传递;
l static-params:将xwork.xml配置文件里定义的Action参数,设置到对应的Action中。Action参数使用<param />标签,是<action />标签的直接子元素。我们这里定义的
Action类必需实现com.opensymphony.xwork.config.entities. Parameterizable接口;
l params:将Request请求的参数设置到相应Action对象的属性中,用户注册例子用到过这个拦截器;
l model-driven:如果Action实现ModelDriven接口,它将getModel()取得的模型对象存入OgnlValueStack中;
l component:激活组件功能支持,让注册过的组件在当前Action中可用,即为Action提供IoC(依赖倒转控制)框架的支持;
l token:核对当前Action请求(request)的有效标识,防止重复提交Action请求(request)。
l token-session:功能同上,但是当提交无效的Action请求标识时,它会将请求数据保存到session中。
l validation:实现使用xml配置文件(
Unknown macro: {Action}
-validation.xml)对Action属性值进行验证,详细请看后面介绍的验证框架。
l workflow:调用Action类的验证功能,假设Action使用ValidationAware实现验证(ActionSupport提供此功能),如果验证没有通过,workflow会将请求返回到input视图(Action的<result />中定义的)。
l servlet-config:提供Action直接对HttpServletRequest或HttpServletResponse等JavaServlet api的访问,Action要实现相应的接口,例如:ServletRequestAware或
ServletResponseAware等。如果必需要提供对JavaServlet api的访问,我们建议使用ServletActionContext,在前面ActionContext章节中有介绍。
l prepare:在Action执行之前调用Action的prepare()方法,这个方法是用来准备Action执行之前要做的工作。它要求我们的Action必需实现
com.opensymphony.xwork. Preparable接口
conversionError:用来处理框架进行类型转化(Type Conversion)时的出错信息。它将存储在ActionContext中的类型转化(Type Conversion)错误信息转化成相应的Action字段
的错误信息,保存在堆栈中。根据需要,可以将这些错误信息在视图中显示出来。
Interceptor的原理
下面我们来看看Interceptor是如何实现在Action执行前后调用的:
Action和Interceptor在框架中的执行,是由ActionInvocation对象调用的。它是用方法:String invoke() throws Exception;来实现的,它首先会依次调用Action对应的
Interceptor,执行完成所有的Interceptor之后,再去调用Action的方法,代码如下:
if (interceptors.hasNext()) {
Interceptor interceptor = (Interceptor) interceptors.next();
resultCode = interceptor.intercept(this);
} else {
if (proxy.getConfig().getMethodName() == null) {
resultCode = getAction().execute();
} else {
resultCode = invokeAction(getAction(), proxy.getConfig());
}
它会在拦截器栈中遍历Interceptor,调用Interceptor的方法:
String intercept(ActionInvocation invocation) throws Exception;。
我们一直都提到,Interceptor是在Action前后执行,可是从上面的代码我们看到的却是执行完所有Interceptor的intercept()方法之后再去调用我们的Action。“在Action前后执行”是
如何实现的呢?我们来看看抽象类AroundInterceptor的intercept()实现:
public String intercept(ActionInvocation invocation) throws Exception {
String result = null;
before(invocation);
result = invocation.invoke();
after(invocation, result);
return result;
}
原来在intercept()方法又对ActionInvocation的invoke()方法进行递归调用,ActionInvocation循环嵌套在intercept()中,一直到语句result = invocation.invoke();执行结束,
即:Action执行完并返回结果result,这时Interceptor对象会按照刚开始执行的逆向顺序依次执行结束。这样before()方法将在Action执行前调用,after()方法在Action执行
之后运行
- Struts2
- struts2
- struts2
- Struts2
- struts2
- struts2
- Struts2
- struts2
- struts2
- struts2
- Struts2
- Struts2
- Struts2
- struts2
- struts2
- STRUTS2
- Struts2
- Struts2
- Spring介绍
- JavaScript学习知识总结
- Struts1
- 黑马程序员-银行业务调度系统
- HDU--杭电--2189--悼念512汶川大地震遇难同胞——来生一起走--背包
- Struts2
- 从零开始学C++之STL(九):函数适配器bind2nd 、mem_fun_ref 源码分析、函数适配器应用举例
- Qt多个信号连接到一个槽,在槽中识别信号的发送者方法
- Bianchi信道容量(matlab)
- 常用正则表达式
- Ajax
- 学完数据库后的综合小练习
- POJ 2524 Ubiquitous Religions
- HDU 1176 免费馅饼