Struts2 学习笔记
2015年3月7日11:02:55
MVC思想
Strust2的MVC对应关系如下:
在MVC三个模块当中,struts2对应关系如下:
Model:
负责封装应用的状态,并实现应用的功能。通常分为数据模型和业务逻辑模型,数据模型用来存放业务数据,比如订单信息、用户信息等;而业务逻辑模型包含应用的业务操作,比如订单的添加或者修改等。
封装应用状态:某些应用数据封装起来,使得视图只能通过接口获取对应的数据
响应状态查询:对应用的状态改变进行处理
暴露应用功能:暴露接口
通知视图改变:主动向视图传递数据
Controller:
用来控制应用程序的流程和处理视图所发出的请求。当控制器接收到用户的请求后,会将用户的数据和模型的更新相映射,也就是调用模型来实现用户请求的功能;然后控制器会选择用于响应的视图,把模型更新后的数据展示给用户。
接受并验证HTTP请求的数据:对一个url请求,通过Controller将请求分发到指定的处理模块上。
将用户数据域模型的更新相映射:用户数据模型改变并不会立即对应到Model,而是需要controller来分发
选择用于响应的视图:根据配置文件,选择对应与某个模型的视图
View:
用来将模型的内容展现给用户,用户可以通过视图来请求模型进行更新。视图从模型获得要展示的数据,然后用自己的方式展现给用户,相当于提供界面来与用户进行人机交互;用户在界面上操作或者填写完成后,会点击提交按钮或是以其它触发事件的方式,来向控制器发出请求。
解析模型的数据:如velocity的功能
产生HTML的响应:
请求模型的更新:向后台发送表单
发送用户输入给控制器
Struts2工作流程
一个请求在Struts2框架中的处理大概分为以下几个步骤:
- 客户端提起一个(HttpServletRequest)请求
- 请求被提交到一系列(主要是三层)的过滤器(Filter),如ActionContextCleanUp、其他过滤器、SiteMesh等、FilterDispatcher。注意这里是有顺序的,先ActionContextCleanUp,再其他过滤器(SiteMesh等)、最后到FilterDispatcher。
- FilterDispatcher是控制器的核心,就是mvc中controller控制层的核心。FilterDispatcher进行初始化并启用核心doFilter
- ActionProxy通过Configuration Manager(struts.xml)询问框架的配置文件,找到需要调用的Action类.
- ActionProxy创建一个ActionInvocation的实例,同时ActionInvocation通过代理模式调用Action。但在调用之前ActionInvocation会根据配置加载Action相关的所有Interceptor。(Interceptor是struts2另一个核心级的概念)
- Interceptor 的调度流程大致如下:
1.
ActionInvocation初始化时,根据配置,加载Action相关的所有Interceptor。
2. 通过ActionInvocation.invoke方法调用Action实现时,执行Interceptor。
整体流程
l 客户端提交一个HttpServletRequest请求(action或JSP页面)。
l 请求被提交到一系列Filter过滤器,如ActionCleanUp和FilterDispatcher等。
l FilterDispatcher是Struts2控制器的核心,它通常是过滤器链中的最后一个过滤器。
l 请求被发送到FilterDispatcher后,FilterDispatcher询问ActionMapper时候需要调用某个action来处理这个Request。
l 如果ActionMapper决定需要调用某个action,FilterDispatcher则把请求交给ActionProxy进行处理。
l ActionProxy通过Configuration Manager询问框架的配置文件struts.xml,找到调用的action类。
l ActionProxy创建一个ActionInvocation实例,通过代理模式调用Action。
l action执行完毕后,返回一个result字符串,此时再按相反的顺序通过Intercepter拦截器。
l 最后ActionInvocation实例,负责根据struts.xml中配置result元素,找到与之相对应的result,决定进一步输出。
Action
Struts2的action生命周期
Struts2的action接口隔离
Struts2中的Action,并不需要依赖于特定的Web容器。我们看不到类似HttpServletRequest,HttpServletResponse等Web容器相关的对象。
提问:Struts2的Action并不带有任何Web容器相关的对象,Action又是如何工作在Web容器中的呢?
虽然Struts2的Action只是一个非常普通的Java对象,并不具备任何Web容器的特质,但是我们需要把Action放到一个更加大的环境中来看。事实上,Struts2为Action的执行,准备了完整的数据环境和执行环境。而这个执行环境,就保证了Action在Web容器中的顺利运行。
在Struts2中,每个Http的请求,会被发送到一个Filter。而这个Filter,就会针对每个请求,创建出一个代码的执行环境,并在这个基础上,为每个执行环境配备与之对应的数据环境,这个数据环境中的内容,就来自于Web容器中的一个又一个对象。这样,就能够顺利调用Action执行代码而无需担心它是否运行在Web容器中了。
提问:Struts2的Action并不带有任何Web容器相关的对象,Action中又如何与Web容器进行通信并获取Web容器的相关对象呢?
刚刚我们提到Struts2会为每个Http的请求建立一个执行环境和数据环境。其中,数据环境就成为了Action获取Web容器的基础。所以,当Action需要获取Web容器的相关对象,需要通过数据环境来进行。
Struts2设置的优点
1. 使得Struts2的Action非常易于测试
如果我们完全不考虑Action的执行环境,仅仅把Action看作一个普通的Java对象,那么我们甚至可以直接new一个Action的对象,通过执行其中的方法完成测试。这样,我们就不需要任何的Mock,来模拟Web容器的环境。
2. 结合Action的执行环境,使得Struts2在Control这个层次上,能够定义更加丰富的执行层次
因为Action是一个普通的Java类,而不是一个Servlet类,完全脱离于Web容器,所以我们就能够更加方便地对Control层进行合理的层次设计,从而抽象出许多公共的逻辑,并将这些逻辑脱离出Action对象本身。事实上,Struts2也正是这么做的,无论是Interceptor,还是Result,其实都是抽象出了Action中公共的逻辑部分,将他们放到了Action的外面,从而更加简化了Action的开发。
3. 使得Struts2的Action看上去更像一个POJO,从而更加易于管理
Struts2的Action是一个线程安全的对象。而Web容器传递过来的参数,也会传递到Action中的成员变量中。这样,Action看上去就更像一个POJO,从而能够方便的被许多对象容器进行管理。比如说,你可以非常方便得把Action纳入到Spring的容器中进行管理。
数据交互上下文 ActionContext(BeatContext)
由于Action是应对于一个又一个的URL请求,所以ActionContext应该具备以下的特性:
1. ActionContext应成为Action与Web容器之间的桥梁
2. ActionContext中应该保存有针对某个请求的详细信息
3. ActionContext应该是一个线程安全的类对象
Struts2拦截器与过滤器
拦截器和过滤器的区别:
1、拦截器是基于java的反射机制的,而过滤器是基于函数回调
2、过滤器依赖与servlet容器,而拦截器不依赖与servlet容器
3、拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用
4、拦截器可以访问action上下文、值栈里的对象,而过滤器不能
5、在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次
过滤器
首先讨论struts2过滤器,struts2的主要过滤器是FilterDispatcher,相当于MVC框架当中的controller,有如下几个功能:
(1)执行Actions:过滤器通过ActionMapper对象,来判断是否应该被映射到Action.如果mapper对象指示他应该被映射,过滤链将会被终止,然后Action被调用。这一点非常重要,如果同时使用SiteMesh filter,则SiteMesh filter应该放到该过滤器前,否则Action的输出将不会被装饰。
(2)清除ActionContext:过滤器为了确保内存溢出,会自动的清除ActionContext。这可能会存在一些问题,在和其它的框架集成时,例如SiteMesh(一致的web页面布局框架,类似装饰器)。ActionContextCleanUp提供了怎么处理这些问题的一些信息。在配置了FilterDispatcher的前提下已经配置了ActionContextCleanUp拦截器。
(3)维护静态内容:过滤器也会维护在Struts2中使用的一些公共的静态的内容,例如JavaScript文件,CSS文件等。搜索/struts/*范围内的请求,然后将/struts/后面的值映射到一些struts的公共包中,也可以在你的类路径中搜索。
默认情况下会去查找以下包:org.apache.struts2.static.template。这样你只用请求/struts/xhtml/styles.css,XHTML UI主题默认的样式表将会被返回。同样,AJAX UI组件需要的JavaScript文件,也可以在org.apache.struts2.static包中被找到。如果你想加入其它被搜索的包,在web.xml中设置filter时,通过给"actionPackages"初始参数一个逗号隔开的包列表值来设定。
(4)清除request生命周期内的XWork的interceptors
自定义过滤器
应该知道如果我们自己定义过滤器的话, 是要放在strtus2的过滤器之前的, 如果放在struts2过滤器之后,你自己的过滤器对action的过滤作用就废了,不会有效!除非你是访问jsp/html!
那我现在有需求, 我必须使用Action的环境,而又想在执行action之前拿filter做一些事, 用FilterDispatcher是做不到的.
那么StrutsPrepareAndExecuteFilter可以把他拆分成StrutsPrepareFilter和StrutsExecuteFilter,可以在这两个过滤器之间加上我们自己的过滤器.!
过滤器也可以自己定义,在使用新的StrutsPrepareAndExecuteFilter作为核心过滤器的情况下,可以将自定义的过滤器放在各种位置上。
具体的配置在web.xml当中进行配置。
拦截器
在使用拦截器的时候,在Action里面必须最后一定要引用struts2自带的拦截器缺省堆栈defaultStack,如下所示:
<interceptor-ref name="checkbox">
<param name="uncheckedValue">0</param>
</interceptor-ref>
<interceptor-ref
name="defaultStack"/>(必须加,否则出错)
Strust2拦截器构成拦截器栈,在使用过程中,相当于递归调用这些拦截器的intercept方法。通常我们采用struts2的默认拦截器,自己开发,则要遵循以下的步骤:
1 自定义一个实现Interceptor接口(或者继承自AbstractInterceptor)的类。
2 在strutx.xml中注册上一步中定义的拦截器。
3 在需要使用的Action中引用上述定义的拦截器,为了方便也可将拦截器定义为默认的拦截器,这样在不加特殊声明的情况下所有的Action都被这个拦截器拦截。
开发
Interceptor接口声明了三个方法:
public interface Interceptor extends
Serializable {
void destroy();
void init();
String intercept(ActionInvocation invocation) throws Exception;
}
Init方法在拦截器类被创建之后,在对Action镜像拦截之前调用,相当于一个post-constructor方法,使用这个方法可以给拦截器类做必要的初始话操作。
Destroy方法在拦截器被垃圾回收之前调用,用来回收init方法初始化的资源。
Intercept是拦截器的主要拦截方法,如果需要调用后续的Action或者拦截器,只需要在该方法中调用invocation.invoke()方法即可,在该方法调用的前后可以插入Action调用前后拦截器需要做的方法。如果不需要调用后续的方法,则返回一个String类型的对象即可,例如Action.SUCCESS。另外AbstractInterceptor提供了一个简单的Interceptor的实现。
注册拦截器
<interceptors>
<interceptor name="login" class="com.jpleasure.teamware.util.CheckLoginInterceptor"/>
<interceptor-stack
name="teamwareStack">
<interceptor-ref
name="login"/>
<interceptor-ref
name="defaultStack"/>
</interceptor-stack>
</interceptors>
将上述拦截器设定为默认拦截器
<default-interceptor-ref
name="teamwareStack"/>
这样在后续同一个package内部的所有Action执行之前都会被login拦截。
每一个拦截器都有两个默认的参数:
excludeMethods - 过滤掉不使用拦截器的方法和
includeMethods – 使用拦截器的方法。
需要说明的几点:
1 拦截器执行的顺序按照定义的顺序执行
2 使用默认拦截器配置每个Action都需要的拦截器堆栈
3 如何访问HttpServletRequest,HttpServletResponse或者HttpSession
有两种方法可以达到效果,使用ActionContext:
Map attibutes =
ActionContext.getContext().getSession();
或者实现相应的接口:
HttpSession SessionAware
HttpServletRequest
ServletRequestAware
HttpServletResponse
ServletResponseAware
剩余部分
集成spring与hibernate
OGNL与标签
高级主题