一、struts2的核心部件
(1)Configuration
(2)Action
(3)Interceptor
(4)Value Stack / OGNL
(5)Result Types
(6)Results / View Technology
二、architectural goals:
(1)separation of concerns
(2)loose coupling
(3)testability
(4)modularization
(5)convention over configuration
1.在Action中访问Web资源:
(1)什么是WEB资源?
HttpServletRequest 、HttpSession 、ServletContext 等原生的 Servlet API
(2)为什么访问WEB资源?
B/S 的应用的 Controller 必须要访问 WEB 资源:向域对象中读写属性,读写 Cookie,获取 realPath。。。
(4)如何访问?
I.和 Servlet API 解耦的方式:只能访问有限的 Servlet API对象,且只能访问其有限的方法(读取请求参数,读写域对象的属性,使 Session 失效。。。)
> 使用 ActionContext
> 实现 XXXAware 接口
> 选用建议:若一个 Action 类中有多个 action 方法,且多个方法都需要使用域对象的 Map 或 parameters,则建议使用 Aware 接口的方式
> session 对应的 Map 实际上是 SessionMap 类型
II.和 Servlet API 耦合的方式:可以访问更多的 Servlet API 对象,且可以调用其原生的方法
> 使用 ServletActionContext
> 使用 ServletXXXAware 接口
2.struts.properties
struts.xml主要负责管理应用中的Action映射,以及该Action包含的Result定义等。除此之外,还包含一个struts.properties文件:定义struts2框架的大量属性,开发者可以通过改变这些属性来满足应用的需求。
struts.properties文件通常放在WEB-INF/classes路径下,其实,它的内容均可以在struts.xml中以<constant name="" value=http://www.mamicode.com/"">加载,或者在web.xml中以标签加载。
3.struts.xml
在其中的action结点(请求与Action类的映射),可以通过 annotation 、web.xml startup parameters 和 alternate URL mapping schemes来代替。
但是如果需要解决global results,exception handling和自定义拦截器栈,则必须要用strusts.xml
struts-default.xml和strut.plugin.xml被自动包含进来。前者提供strust2框架的核心配置,后者提供特殊插件的配置。每一个plug-in jar文件都应该包含一个struts-plugin.xml文件
(1)<struts>标签:包含其他所有的标签
(2)<include>标签:引用一个其他的配置文件
(3)<package>标签:属性abstract为true时,该标签内不能配置action;继承自struts-default package
4.Result Types
(1)dispatcher类型 最常用 后台使用HttpServletRequest的RequestDispatcher来转发请求
> 实现类:org.apache.struts2.dispatcher.ServletDispatcherResult
> 两个属性
<result name="success" type="dispacther">
<param name="location">/success.jsp</param> //指定Action执行完毕后要转向的目标资源
<param name="parse">true</param> //true:解析location参数中的OGNL表达式;反之则不解析
</result>
(2)redirect类型 后台使用HttpServletResponse的sendRedirect方法来请求重定向到指定的URL
> 实现类:org.apache.struts2.dispatcher.ServletRedirectResult
> 两个属性:同上
> 适用场合:用户注册、在线调查等,不会造成刷新导致的重复提交问题
(3)redirectAction类型
> 实现类:org.apache.struts2.dispatcher.ServletActionRedirectResult(继承自ServletRedirectResult)
> 工作原理同redirect一样,区别是重新定向到另外一个action
(4)plainText类型
> 实现类:org.apache.struts2.dispatcher.PlainTextResult
> 可以输出JSP或HTML源代码
> struts2框架自动完成对标记到实体引用或者字符引用的转换
> 两个属性:location和charSet,后者代表输出页面内容时使用的字符编码
(5)全局结果
> 在<global-results>标签内使用
(6)动态结果
> 配置的时候不知道要执行哪一个结果,配置结果时使用了表达式,运行时框架解析表达式,根据表达式的值来确定要执行的结果
> 在结果映射中,使用${...}语法访问的属性一定要在Action中存在,提供对应的JavaBean风格的getter方法。在JavaBean中实例变量名和属性名可以不同,使用${...}访问的是属性名
5.Interceptors
(1)要使某个拦截器能被需要它的Action使用,有两种配置方法:
> 该方法没有拦截器配置的数量限制,唯一要求的是,拦截器的执行顺序就是在Action中配置的顺序
<interceptors>
…
<interceptor name="autowiring"
class="interceptor.ActionAutowiringInterceptor"/>
</interceptors>
<action name="my" class="com.fdar.infoq.MyAction" >
<result>view.jsp</result>
<interceptor-ref name="autowiring"/>
</action>
> 在</package>之前使用<default-interceptor-ref name="autowiring"/>,但是只有一个拦截器才能被定义为默认的拦截器
(2)拦截器栈的表示和使用
<interceptor-stack name="basicStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="servlet-config"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
</interceptor-stack>
<action name="my" class="com.fdar.infoq.MyAction" >
<result>view.jsp</result>
<interceptor-ref name="basicStack"/>
</action>
(3)ActionInvocation提供了可以访问运行环境的权限
(4)struts2将它的核心功能放到拦截器中实现,而不是分散到Action中实现,有利于系统的解耦,使得功能的实现类似于个人电脑的组装,变成了可插拔的:需要某个功能就插入一个拦截器,不需要某个功能就拔出一个拦截器。你可以任意组合拦截器来为Action提供附加功能,而不需要修改Action
(5)实现Interceptor接口:
>init
>destroy
>intercept:在Action执行前被调用,拦截器为Action提供的附加功能在这里实现。 利用invocation参数可以获取Action执行的状态。如果要继续执行后续部分(余下的拦截器、Action、Result)可以调用invocation.invoke();如果要终止后续的执行,可以直接返回一个结果码,框架将根据这个结果码来呈现对应的结果视图
(6)拦截器执行顺序:
我们可以以invocation.invoke()为界,将拦截器中的代码分成2个部分,在invocation.invoke()之前的代码,将会在Action之前被依次执行,而在invocation.invoke()之后的代码,将会在Action之后被逆序执行。
【计算Action执行时间的实例】:
public String intercept(ActionInvocation invocation){
long startTime=System.currentTimeMillis();
String result=invocation.invoke(); //拦截点
long executionTime=System.currentTimeMillis()-startTime;
System.out.println("Action的执行花费的毫秒数是:"+exexutionTime);
return result;
}
(7)MethodFilterInterceptor可以指定要拦截或者排除的方法列表,通过指定included和excluded方法列表来实现,例如:
public String intercept(ActionInvocation invocation){
long startTime=System.currentTimeMillis();
String result=invocation.invoke(); //拦截点
long executionTime=System.currentTimeMillis()-startTime;
System.out.println("Action的执行花费的毫秒数是:"+exexutionTime);
return result;
}
(8)拦截器必须是无状态的,换句话说,在拦截器类中不能有实例变量。
(9)如果包继承自struts-default包,那么defaultStack拦截器栈将是默认的拦截器引用
(10)PreResultListener接口
>在Action执行之后、Result执行之前得到通知,从而在视图呈现给用户之前做一些处理
>实例需要手工注册,在拦截器调用invocation.invoke()方法之前调用invocation.addPreResultListener()方法注册PreResultListener
6.Value Stack/ OGNL
> Value Stack : a stack of objects
> OGNL:access objects within the value stack
(1)Value Stack中Object的种类及顺序
> Temporary Objects
> The Model Object
> The Action Object:the action being executed
> The Named Objects:#application #request #session #attr #parameters
(2)strust2的值栈允许存在许多虚拟根对象:将OGNL上下文设置为ActionContext,并将值栈作为OGNL的根对象
(3)top 结合 [N].xx语法可以访问栈中的任意对象
(4)struts2框架总是把Action实例放置在栈顶,因为在Action在值栈中,而值栈又是OGNL的根,所以引用Action的属性可以省略#标记
(5)struts2中的命名对象
> #parameters.XX 或者 #parameters[‘XX]]:用于访问请求参数,本质上parameters是一个Map对象,用HttpServletRequest对象中的请求参数构造的,一旦对象创建好了(在Action实例之前就创建好了),它和HttpServletRequest就没有关系了,所以只读不可写(写了没有效果)
> #request
> #session
> #application
> #attr:PageContext
(6)值栈能够线程安全地为每个请求提供公共的数据存取服务
> 当有请求到达时,struts2会为每个请求创建一个新的值栈,也就是说,值栈和请求是一一对应的,不同的请求,值栈也不一样,而值栈封装了一次请求所有需要操作的相关数据
(7)怎么讲struts2值栈中的对象删除?
> ValueStack 对象。这个对象贯穿整个 Action 的生命周期(每个 Action 类的对象实例会拥有一个 ValueStack 对象)。当 Struts 2 接收到一个 .action 的请求后,会先建立 Action 类的对象实例,但并不会调用 Action 方法,而是先将 Action 类的相应属性放到 ValueStack 对象的顶层节点( ValueStack 对象相当于一个栈)。
所以删除操作不了。
7.OGNL
(1)为什么使用OGNL?
> 取代Java代码
> 简化数据访问的方式
> 提供更清晰的视图层实现
(2)OGNL表达式的计算都是围绕OGNL上下文来进行的,OGNL上下文实际上是一个Map对象,它可以包含许多JavaBean对象,这些对象中有一个特殊的根对象。
(3)表达式的基础单元:导航链
(4)OGNL提供调用任何方法的能力
(5)调用静态方法:@class@method
(6)调用构造方法:new ,必须使用完整的限定类名
(7)投影、选择
8.标签
(1)通用标签
>数据标签
>控制标签
(2)UI标签
>表单标签
>非表单标签
>Ajax标签