先看1-9章和13,12,15,这12章;
再看第10章;
第11章以后需要了再说。
struts2原则:
约定优于配置;
框架本质:成熟的运用机制;(常见任务,架构解决方案)
第一章:Struts2:现代web框架;
1.1 web应用程序;
Web基础技术:(图)
http协议的客户/服务器数据交换;
Java servlet api 又负责将这些低级的http通信公开给java语言;
Struts2使用Java servlet api ;
http:
大多数web应用程序运行在http之上;http协议是一系列无状态的客户/服务器信息交换;
对于web应用程序而言,需要跨越http协议的两个障碍——无状态和基于文本;
Java servlet api:
Servlet是一个单例的java对象,它的全部用途是接收请求,以及在任意的后端处理之后返回响应;
打包web应用程序;
部署web应用程序;
web应用程序部署在servlet容器中,servlet是一种"托管生命周期的应用程序",把servlet部署在一个容器内,容器通过调用不同的servlet生命周期方法来管理它的执行;
当servlet容器收到请求的时候,容器找到处理这个请求的servlet,然后调用servlet的service()方法,service()方法负责完成实际的工作;(图)
servlet api的高级功能:
会话机制;
1.1.3:
Web应用程序处理请求时必须解决的问题:
请求参数到java数据类型的数据绑定;
验证数据;
访问业务逻辑;
访问数据层;
呈现表示层(html等);
提供国际化和本地化支持;
---
可重用的解决方案;---框架的使用;
1.2 web应用程序框架;
框架自动化了常见任务;
框架提供了架构解决方案;
1.3 struts2框架;
Struts2概览:MVC模式;
Mvc:关注点分离;模型、视图和控制器;(图)
Struts2中,通过动作、结果和过滤分配器实现;
控制器:---过滤分配器(filterDispatcher);
将请求映射到动作;
Struts2的过滤分配器,是一个servlet过滤器,它检查每一个请求,决定哪个struts2动作来处理这个请求;
框架完成控制器的任务;
你只需要告诉框架哪个请求URL需要映射到哪个动作;---可以通过xml配置文件或者java注解来完成这个任务;
模型:---动作;
模型是应用程序的内部状态,由数据模型和业务逻辑共同组成;
Struts2的动作组件有两个作用,首先,一个动作将业务逻辑调用封装到一个单独的工作单元中;其次,动作是一个数据传输的场所。
控制器调用动作并将请求处理的控制权转交给它;由框架负责管理的调用过程既准备必要的数据又执行动作的业务逻辑;动作完成它的工作后,将结果转发到Struts2视图组件。
视图:---结果;
1.3.3:Struts2的工作原理:(图)
Struts2提供了一个更整洁的mvc实现,依赖于其他几个参与每一个请求处理的关键架构组件的帮助;
这些架构组件包括:拦截器、OGNL和valueStack;
请求处理流程:
Struts2请求处理使用在动作和结果之前或之后调用的拦截器;
过滤分配器已经完成了自身的控制工作,并选择了相应的动作来处理请求;
拦截器:
拦截器允许常见的、横切的任务在间接、可重用的组件中定义,从而能够和动作的代码分离;
例如:日志;数据验证,类型转换,文件上传等;(公共方法)
valueStack和OGNL:
valueStack是保管与请求处理相关的数据的一个存储区域;
OGNL是一种访问存储在中央存储库中数据的工具;---操作valueStack中的数据;
valueStack存储在一个线程本地对象中,actioncontext;
Actioncontext包含所有的数据,这些数据构成了动作执行的环境;它包含valueStack,也包含框架会使用的内部数据,如请求对象、会话对象以及从servlet api 中得来的应用程序映射。
Struts生命周期:
第二章:初始Struts2;
2.1声明性架构:
通过高级的声明性架构特性来描述应用程序的架构组件,而将运行时创建这些架构组件的任务交给框架;
2.1.1两种配置
声明应用程序的struts2组件的行为称为配置;2种配置;
1.配置框架;管理性质的配置;
2.声明应用程序的架构;---声明性架构;包括定义应用程序使用的struts2组件,以及将它们连接起来形成需要的工作流程路径。描述。
开发人员只需要声明哪些对象作为应用程序的动作、结果以及拦截器。
开发人员只需要实现动作,之后将它们与内建的结果和拦截器关联起来即可。
2.1.2声明架构的两种方式
通过基于xml的配置文件或者通过java注解。
框架都会产生相同的运行时应用程序。图;
1基于xml的声明性架构
使用xml文件描述应用程序需要的struts2架构组件;
入口xml文件struts.xml;
2基于java注解的声明性架构
在java源代码文件中直接添加元数据。
2.1.3智能默认值;
2.2简单的helloworld示例:
2.2.1部署示例应用程序;
Servlet容器---tomcat;
Web.xml文件(应用程序配置文件);
<filter> //过滤分配器;
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern> //url模式,/*,---检查所有的请求;
</filter-mapping>
---检查所有的传入请求,查找指向struts2动作的请求;
2.2.2探索helloworld应用程序;
1),struts.xml文件:xml声明性架构的入口点;
使用include元素引入模块化的xml文档;
<include file="manning/chapterTwo/chapterTwo.xml"/>
使用常量调整struts的属性;
<constant name="struts.devMode" value="true" />
<package> 容器元素,用来组织动作元素、结果元素和其它组件元素;
Package元素声明了一个当框架将url映射到动作时会用到的命名空间;(即,使用包的命名空间来决定映射到动作的url)。
最佳实践:
使用动作转发请求;无论动作是否有实现类;
Struts2 ui 组件标签;
<s:form action="HelloWorld">
<s:textfield name="name" label="Your name"/>
<s:submit/>
</s:form>
动作实现类;
Javabean存储数据;
业务逻辑访问、操作数据;
Jsp页面:
取得javabean保存的数据;
数据同时存储在动作和valuestack中;
动作保存数据,动作的方法可以很方便的访问数据;
动作放在valuestack(值栈)中,框架的其它部分也可以访问这些数据;
2.3使用注解的helloworld
描述应用程序中struts2组件的方式;
1.注解直接放在动作的源代码中;
2.动作的位置在struts2过滤分配器的初始化参数中设置,在应用程序的web.xml部署描述符中定义;
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
<init-param>
<param-name>actionPackages</param-name>
<param-value>manning</param-value> <!--manning包名;-->
</init-param>
3.标记哪些类时动作类:1),让动作类实现com.opensymphony.xwork2.Action接口;2),使用命名约定,也就是所有动作类的命名以Action结尾。
注解机制的智能默认值;
转发动作时最佳实践(不直接指向jsp页面);
示例:
输入名字,单击submit按钮,返回一个新页面、提示问候语;
流程:
Index.html---web.xml---struts.xml---menu.jsp
Menu.jsp---chapterTwo.xml---NameCollector.jsp---chapterTwo.xml---HelloWorld.java
---HelloWorld.jsp
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
第二部分:核心概念:动作、拦截器和类型转换;
第三章:使用Struts2动作;
3.1 struts2动作简介
Struts2是一个面向动作的框架;
动作的作用:
1,动作封装工作单元;
动作控制业务逻辑;---使用execute()方法,只关注与请求相关的工作逻辑;
如果业务逻辑很复杂,我们可能会把业务逻辑构建成一个业务组件,再把这个业务组件注入到动作中。使用spring框架来依赖注入。
2,动作为数据转移提供场所;
动作必须能够携带数据。
动作只需把每一个期望承载的数据实现为javabean属性。来源于表单的请求参数被放入到动作中名字匹配的属性上;动作中的javabean属性也将数据公开给结果。
动作作为一个集中的数据转移对象,可以让应用程序的数据在框架的所有层次可用。
3,动作为结果路由选择返回控制字符串;
返回控制字符串以选择应该被呈现的结果页面。
3.2打包动作:
Struts2的包;---基于功能或者领域的共性将动作组件分组的机制。
Struts2公文包示例:
Secure-安全包,用来容纳安全动作;
Public-公共包,用来容纳公共动作;
---都继承Struts-default包;
Struts-default包中的组件,包括:默认的拦截器栈;
3.3实现动作:
Sturts 2动作不必实现action接口。任何对象都可以通过实现一个返回控制字符串的execute()方法来非正式地实现动作与框架之间的契约。
3.3.1 可选的action接口:
智能默认值;
3.3.2 actionSupport类:
它是一个提供了action接口和其他几个有用接口的默认实现的便利类,提供了诸如数据验证、错误信息本地化等功能。
动作如何与拦截器协作,来达成日常任务强大的可重用的解决方案:
---
数据验证和文本本地化服务就是通过拦截器和接口的协作实现的。拦截器控制服务的执行,动作实现接口提供被拦截器调用的方法。
1,基本验证:
Struts-default.xml文件;
Params拦截器将请求数据转移到动作对象上。
Workflow拦截器:致力于将横切任务(此时是验证)从动作的执行逻辑中转移出去。
Register.java:
扩展了actionSupport类; ---提供创建和存储错误信息的方法(例如addFieldError);
提供了Execute()方法; ---只关注业务逻辑;
Javabean属性; ---接收传输的数据,携带数据。
Validate()方法; ---验证逻辑;
在调用Validate()方法执行动作的验证逻辑之后,Workflow拦截器检查验证逻辑是否生成了错误信息。如果找到了错误信息,Workflow拦截器会改变请求的工作流。它会立即终止请求处理,将用户带回到输入表单,并且在表单中显示合适的错误信息。
拦截器清理动作的执行逻辑:关注点分离,验证逻辑与动作执行逻辑清楚地分离了。
验证过程的控制流也从动作中分离出去了。Workflow拦截器控制着验证逻辑的执行。这些拦截器在动作执行之前触发。控制流的分离使得Workflow拦截器在进入动作的Execute()方法之前可以中止整个请求处理并且重定向回输入页面。
2.使用资源包处理文本信息:
属性文件;
textProvider提供了对这些消息的访问;
actionSupport也为本地化消息文本提供了一个基本的国际化解决方案。
3.4向对象传递数据:
动作把从请求接收到的所有数据放在简单的javabean属性上。
可以把复杂对象本身提供给平台的数据转移机制。
使用复杂对象,有两种选择来实现这样深层的数据转移:
1)基于javabean对象,可以公开一个复杂对象作为javabean属性,让数据直接传输到这个对象上。
2)使用modelDriven动作,涉及一个简单的接口和另一个默认拦截器,也使用一个复杂的java对象接收数据。
3.4.1 对象支持的javabean属性:
数据自动转移,在动作上提供javabean属性;
收集被转移的独立数据元素,并且将它们转移到必须我们自己实例化的应用程序域对象上。
public String execute(){
/*
* 手动收集数据并且构建域对象;
*/
User user = new User();
user.setPassword( getPassword() );
user.setPortfolioName( getPortfolioName() );
user.setUsername( getUsername() );
getPortfolioService().createAccount( user );
return SUCCESS;
}
Sturts2数据转移和类型转换工具:
public String execute(){
getPortfolioService().createAccount( user ); //(1)
return SUCCESS;
}
/* JavaBeans Properties to Receive Request Parameters */
private User user; //(2)
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public void validate(){
/* Retrieve our simple portfolio service object. */
PortfolioService ps = getPortfolioService();
/* Check that fields are not empty */
if ( getUser().getPassword().length() == 0 ){ //(3)
addFieldError( "user.password", getText("password.required") );
}
(1)把一个已实例化并且填满数据的User对象传递给服务账号创建方法。
(2)使用一个user对象支持的属性替换个别的javabean属性。
(3)Javabean属性标记中加深一层。
3.4.2 ModelDriven动作:
通过getModel()方法公开应用程序的域对象;
拦截器已经在默认拦截器栈中了,Modeldriven接口公开了getModel()方法;
public class ModelDrivenRegister extends ActionSupport implements ModelDriven {
public String execute(){
getPortfolioService().createAccount( user );
return SUCCESS;
}
/* Instance field and getModel() to support the ModelDriven interface */
private User user = new User(); //初始化user对象
public Object getModel() {
return user;
}
public void validate(){
/* Retrieve our simple portfolio service object. */
PortfolioService ps = getPortfolioService();
/* Check that fields are not empty */
if ( user.getPassword().length() == 0 ){
addFieldError( "password", getText("password.required") );
}
3.4.3 域对象用作数据转移的潜在危险;
3.5案例研究:文件上传:
框架使用拦截器从动作分层出常见任务的逻辑的持久模式。
3.5.1通过struts-default包获得内建的支持:
struts-default包包含了fileUpload拦截器的声明;
3.5.2 fileUpload拦截器做什么:
当ileUpload拦截器执行时,它处理一个多重请求并且将文件和其他一些元数据一起转换到请求参数中。
3.5.3 struts2公文包示例代码研究:
ImageUploadForm.jsp ---struts2标签表单,包括上传标签file;
表单的编码类型multipart/form-data,上传属性;
表单提交文件的name属性。
第四章:使用拦截器追加工作流;
4.1为什么要拦截请求:
Struts2框架实现了一个非常整洁的架构;
MVC关注点分离;
拦截器的关注分离作用:横切,预处理,后加工;
---
框架不直接调用动作的execute()方法,而是创建一个叫做actionInvocation的对象,它封装了动作和一系列配置在动作执行之前之后触发的拦截器。
从拦截器受益:可重用和可配置;
4.2拦截器的工作原理:
actionInvocation类指挥着动作的完整执行,以及与之相关的拦截器栈的顺序触发。
actionInvocation的invoke()方法:
通过调用invoke()方法将控制转移给后续的拦截器,最后直到动作,或者通过返回一个控制字符串中断执行。
4.3研究内建的struts2拦截器:
4.3.1工具拦截器;
这些拦截器提供了辅助开发,调优以及解决问题的简单工具;
Timer拦截器;
Logger拦截器;
4.3.2数据转移拦截器;
1,params拦截器;
将请求参数转移到通过valuestack公开的属性上;
2,static-params拦截器;
将请求参数转移到通过valuestack公开的属性上;这个拦截器转移的参数定义在声明性架构的动作元素中;
3,autowiring拦截器;
为使用spring管理应用程序资源提供了一个集成点。
4,servlet-config拦截器;
将来源于servlet api 的各种对象注入到动作的简洁方法。
5,fileUpload拦截器;
将文件和元数据从多重请求转换为常规的请求参数。
4.3.3工作流拦截器;
改变请求处理的工作流;
1,workflow拦截器:验证功能;
2,validation拦截器:简单形式的验证,struts2验证框架的有一部分;
3,prepare拦截器:向动作追加额外工作流处理的通用入口点;
4,modelDriven:
4.3.4其他拦截器;
1,exception拦截器:异常处理; ---完成所有动作的异常处理;
2,token拦截器和token-session拦截器:避免表单重复提交;
3,scoped-modelDriven拦截器:为动作的模型对象提供跨请求的向导式的持久性;
4,execAndWait:请求等待处理;
4.3.5 内建拦截器栈:
一般就使用defaultStack;
4.4声明拦截器:
声明拦截器,栈;
将拦截器映射到动作组件;
设置、覆盖拦截器参数;
4.5构建自定义拦截器:
安排栈的顺序;
用户身份验证拦截器:
4.5.1 实现interceptor接口;
4.5.2构建authenticationInterceptor拦截器:
登录的身份验证;---登陆成功后,将用户对象存储在会话作用域映射中;---
当authenticationInterceptor触发时,它检查用户对象是否出现在会话中;---
然后工作流处理。
Login动作验证用户身份并且将用户存储在会话作用域中;
Session;
authenticationInterceptor检测:
获得会话映射;---得到用户对象;---动作使用户对象自动注入到设置方法;---控制转交。
第五章:数据转移:OGNL和类型转移;
5.1数据转移和类型转换:web应用程序领域的常见任务:
从基于字符串的http向java语言的不同数据类型移动和转换数据;
框架将数据从基于文本的http请求移动到javabean属性。
当结果被呈现时,从这些javabean属性中过滤出一些数据回到结构html页面;---意味着数据从java类型再被转换回字符串格式。
Sturts2类型转换机制。
5.2 OGNL和struts2:
OGNL,对象图导航语言;
帮助实现数据转移和类型转换。
OGNL包含两件事:表达式语言和类型转换区。
1,表达式语言:
表达式语言允许我们使用简单的语法来引用Java环境中存在的对象。
Ognl的作用是提供一个简单的语法将struts2标签与特定的java端属性绑定起来,用来将数据移入、移出框架。Ognl创建了数据流经框架的路径。它帮助将数据从请求参数移动到动作的javabean属性,并且帮助将数据从这些属性移动到呈现的html页面。
2,类型转换:
每一次数据移入或移出java环境,必须在驻留在html中的数据的字符串版本和合适的java数据类型之间发生数据转换。
5.5.2: OGNL如何融入框架:(图)
页面---OGNL---valueStack;数据流入,数据流出。
<s:property value="user.age" />
5.3内建的类型转换器:
为了使用内建的类型转换器,你只需要构造一个指向valuestack上某个属性的OGNL表达式。
OGNL表达式可以是表单字段的名字,也可以在视图标签层的某个地方。
5.3.2使用OGNL表达式从表单字段名映射到属性:
1,原始类型和包装类:
在动作对象上公开javabean属性。
1),页面表单;---OGNL表达式;
<s:form action="Register">
<s:textfield name="user.username" label="Username"/>
<s:password name="user.password" label="Password"/>
<s:textfield name="user.portfolioName" label="Enter a name for your portfolio"/>
<s:textfield name="user.age" label="Enter your age, with double precision!"/>
<s:textfield name="user.birthday" label="Enter your birthday. (mm/dd/yy)"/>
<s:submit/>
</s:form>
2),Register动作:---公开user对象的javabean属性;
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
2,处理多值请求参数:
多个参数值可以被映射到传入请求中的一个参数名。
动作对象只需公开接收数据的属性。
动作仅仅作为这些示例的一个数据容器,表单会提交数据请求,框架会将这些数据转移到动作动作公开的属性上,动作只转发到成功结果,结果将显示使用struts2标签从动作取得的数据。
3,数组:
编写数组类型的OGNL表达式;
表单OGNL数组表达式---动作对象上公开数组属性---框架自动将请求参数转移、转换到动作的属性上---动作将请求转发到结果页面。
4,List:
默认类型的list:使用同于数组,但不需要设置类型,直接标明list。
为元素指定类型:使用“类型转换属性文件”,指定基于List类型的属性的元素类型。
示例:User类作为list属性的元素类型;
5,Map:
Map使用关键字而非索引来关联到它的值。
使用泛型来类型化collection和map,可以不需要属性文件配置。
5.4自定义类型转换:
指定一个转换逻辑,将任何字符串翻译为任何java类型。
创建字符串语法和对应的java类,之后使用一个类型转换器把它们连接起来。
例如:在字符串和简单的circle类之间转换。
5.4.1实现类型转换器:
继承StrutsTypeConverter类,实现两个抽象方法;
5.4.2在string和circle之间转换:
circleTypeConverter自定义类型转换方法。
5.4.3配置框架使用自定义转换器:
还是:
表单OGNL表达式---动作对象上公开属性---属性文件配置。
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
第三部分:构建视图---标签和结果
第六章:构建视图-标签;
在将传入的请求参数映射到valuestack公开的java属性上,本章将展示如何将数据从这些属性中取出用于结果页面的呈现。
6.1 入门:
当一个请求达到框架时,struts2首先要做的事情是创建存储请求的所有重要数据段的对象。应用程序的特定领域数据存储在valueStack中;另一些更基础的数据存储在其它对象中;都存储在一个叫做actionContext的对象中。
1,actionContext和OGNL:
actionContext通过提供一个动作执行的环境让所有的内容变得更整洁。
actionContext中的对象:
Parameters; request; session; application; attr; valueStack;
OGNL默认选择valueStack对象;显示选择其它对象。
2,虚拟对象valueStack:
struts2接收到一个请求时,它立即创建一个actionContext、一个valueStack和一个动作对象。作为应用程序数据的承载者,动作被马上放到valueStack中,以便框架可以通过OGNL访问它的属性。
6.2 struts2标签概要:
标签分为4种类别:数据标签;流程控制标签;UI标签和其他标签。
struts2标签api在3种视图层技术中实现:
1,jsp语法;
<s:property value="name"/>
2,velocity语法;
#sproperty("value=name")
3,FreeMarker语法;
<@s.property value="name"/>
使用OGNL设置标签属性:
1,字符串和非字符串类型的属性;
2,强制使用OGNL解析;
6.3 数据标签:
Property标签:
提供一种将属性写入呈现的html页面的快速、方便的方法。
<s:property value="user.username"/>
Set标签:
创建指向值的新引用。
之后使用#操作符引用它。
<s:set name="username" value="user.username"/>
Your username is <s:property value="#username"/>.
Push标签:
把属性放到valueStack上。
之后它的所有属性可以通过第一级别的OGNL表达式访问。
<s:push value="user">
<h2>This is the "<s:property value="portfolioName"/>" portfolio</h2>
It was created by none other than <s:property value="firstName"/> <s:property value="lastName"/>.
</s:push>
Bean标签:
创建一个对象的实例把它放到valueStack上或者设置为actionContext的顶级引用。默认情况下,对象会被放到valueStack上,并在标签存在期间一直保留在valueStack上。
如果你想在标签之外继续引用创建的对象,可以使用var属性为这个对象指定一个引用名,那么这个引用会作为一个命名参数存在于actionContext中,在请求周期内可以使用#操作符访问这个对象。
<s:bean name="manning.chapterSix.utils.JokeBean" >
<s:param name="jokeType">adult</s:param>
<s:property value="startAJoke()"/>
</s:bean>
Action标签:
从当前的视图层调用其他的动作。
<s:action name="TargetAction" executeResult="true"/>
6.4 控制标签:
使用控制标签控制页面执行的流程。
Iterator标签:
遍历集合对象。
Status属性。
<s:iterator value="users" status="itStatus">
<li>
<s:property value="#itStatus.count" />
<s:property value="portfolioName"/>
</li>
</s:iterator>
If和else标签:
控制逻辑。
<s:if test="user.age > 35">This user is too old.</s:if>
<s:elseif test="user.age < 35">This user is too young</s:elseif>
<s:else>This user is just right</s:else>
6.5 其他标签:
Include标签:
这个标签可以执行servlet api 样式的包含,你可以再当前呈现的页面中包含其他web资源的输出,可以向被包含的资源传递请求参数。
Url标签:
支持与url相关的所有操作,从控制参数到cookie缺失时自动持久化会话。
Var属性---如果指定,这个url不会被写出,而会存储在actionContext留待后用。
URL = <s:url action="IteratorTag" id="myUrl">
<s:param name="id" value="2"/>
</s:url>
<a href='<s:property value="#myUrl" />'> Click Me </a>
Il8n和text标签:
国际化支持的标签。
Param标签:
向对象传递参数。
6.6 使用JSTL和其他本地标签:
6.7 OGNL表达式语言的基础知识:
6.7.1 什么是OGNL:
在Struts2中使用OGNL表达式语言来引用java环境中的数据属性,使用OGNL类型转换器来管理HTTP字符串值和类型化的java值之间的类型转换。
6.7.2 Struts2中常用的表达式语言特性:
1,引用bean属性;
User.name;
2,设置和取得;
设置:
<s:form action="Register">
<s:textfield name="username" label="Username"/>
<s:password name="password" label="Password"/>
<s:textfield name="portfolioName" label="Enter a name for your portfolio"/>
<s:submit/>
</s:form>
取得:
<h3>The <s:property value="portfolioName" /> Portfolio</h3>
3,使用java collection类型;
OGNL表达式语言简化了collection的操作。
4,使用List和数组;
访问list或者数组属性的基本语法。
在OGNL中动态创建list。
5,使用map;
Map属性的OGNL表达式语言语法。
在OGNL中动态创建map。
6,过滤(filtering)和投影(projecting)集合;
collectionName.{?expression};
collectionName.{ expression};
6.7.3 表达式语言的高级特性:
1,字面值和操作符:
2,调用方法:
3,访问静态方法和字段:
第七章:UI组件标签;
通过UI组件标签构建用户界面。
7.1 为什么需要UI组件标签:
UI组件功能:
生成html标记。
绑定html表单字段和java端属性。
与框架提供的类型转换关联起来。
与框架提供的验证关联起来。
与框架提供的国际化功能关联起来。
1,生成HTML标记:
每一个UI组件生成一组HTML标记。
UI组件实现更简单;
<s:textfield name="username" label="Username"/>
2,将表单字段绑定到valueStack的属性:
UI组件通过将name属性指定为OGNL表达式将自己同时绑定到valueStack上的传出和传入属性,以实现表单的预先填充和表单提交时的自动数据转移。
3,与类型转换、数据验证以及国际化集成:
7.2 标签、模板和主题:
UI组件的迷你MVC架构:
Ui组件标签---jsp,velocity,freeMarker3种视图层技术---Struts2 UI组件标签API---模板(xhtml,css_xthml,ajax等主题);
标签:
模板:
主题:
内建的UI组件主题;
默认主题xhtml,使用HTML表格来布局表单。
改变主题:使用配置文件。
7.3 UI组件标签:
7.3.1通用属性:
属性 主题 数据类型 描述
Name simple string name属性指向valueStack上的属性
Value simple object 指向valueStack上的属性的OGNL表达式
Key XHTML string 从ResourceBundle取得本地化的标签
Label XHTML string 为组件创建一个HTML标签
labelPosition XHTML string 元素标签label的位置
Required XHTML boolean 默认为true,表示必填
Id simple string HTML的id属性
cssClass simple string html的css属性,css使用
cssStyle simple string html的style属性,css使用
Disabled simple string html的disabled属性
Tabindex simple string html的tabindex属性
Theme N/A string 在哪个主题下呈现这个组件
templateDir N/A string 用来覆盖从中取出模板的默认目录名
Template N/A string 用来呈现UI标签的模板
7.3.2简单组件:
1,head组件
<s:head/>
2,form组件
常用的form标签属性:
属性 类型 描述
action string name属性指向valueStack上的属性
Namespace string struts2命名空间,默认为当前空间
Method string 与HTML form属性相同,默认post
Target string 与HTML form属性相同
Enctype string 上传文件时设置为multipart/form-data
Validate string 与验证框架一起使用,打开客户端js验证
示例:login.jsp页面中的表单:
<s:form action="Login">
<s:textfield name="username" label="Username"/>
<s:password name="password" label="Password"/>
<s:submit/>
</s:form>
通过action指定了动作名,
这里给出的动作名是在声明性架构中为动作指定的逻辑名。
struts2会为这个动作生成一个完整的URL。
Form标签为HTML表单生成最终动作URL的过程:
(1)如果没有指定action属性,则会重新指向生成当前页面的动作。
(2)如果指定了action属性,它首先被当做struts2动作解析。
(3)如果action属性中指定的值不是声明性架构中的struts2动作,那么这个值会被用来直接构建URL。
最佳实践是指向动作名。
3,textfield组件
文本输入组件。
重要的textfield属性:
属性 类型 描述
maxlength string 字段数据的最大长度
Readonly boolean 如果为true,字段不可编辑
Size string 可视长度
可以使用key属性和本地化配置文件。
4,password组件
重要的password属性:
属性 类型 描述
maxlength string 字段数据的最大长度
Readonly boolean 如果为true,字段不可编辑
Size string 可视长度
showPassword boolean 如果设置为true,并且在valeStack中对应的属性有值,密码会预填充。默认为false。
5,textarea组件
重要的textarea属性:
属性 类型 描述
Cols Integer 列数
Rows Integer 行数
Readonly boolean 如果为true,字段不可编辑
Wrap string 指定textarea中的内容是否应该被包装起来
6,checkbox组件
重要的checkbox属性:
属性 类型 描述
fieldvalue string
value string
7.3.3基于集合的组件:
1,select组件:下拉列表
重要的select属性:
属性 类型 描述
list collection/map/array/iterator 用来生成下拉列表选项的数据集合
listKey string 当list中的元素是复杂类型时,值key
listValue string 当list中的元素是复杂类型时,字符串value
headerKey string 与标题一起使用,值key
headerValue string 与标题一起使用,字符串value
emptyOption boolean 与标题一起使用,在标题和真实选项之间放置一个空的间隔选项
Multiple boolean 用户可以选择多个值
Size string 一次显示的选项个数
示例:
<s:form action="SelectPortfolio">
<s:select name="username" list='users' listKey="username"
listValue="username" label="Select an artist" />
<s:submit value="Browse" />
</s:form>
2,radio组件:
重要的radio属性:
属性 类型 描述
list collection/map/array/iterator 生成选项的数据集合
listKey string 集合的元素的属性,值key
listValue string 集合的元素的属性,字符串value
3,checkboxlist组件:
重要的checkboxlist属性:
属性 类型 描述
list collection/map/array/iterator 生成选项的数据集合
listKey string 集合的元素的属性,值key
listValue string 集合的元素的属性,字符串value
4,预填充基于集合的组件:
public String execute() {
Collection users = getPortfolioService().getUsers(); 1)
setUsers(users);
String selectedUsername = getPortfolioService().getDefaultUser();
setDefaultUsername(selectedUsername); 2)
return SUCCESS;
}
首先,我们设定了用来创建基于集合的组件的一系列用户。1)
之后取得了需要默认展示的艺术家的用户名,并且把这个用户名设定到动作的javaBean属性defaultUsername上。2)
这使得需要展示的用户在valueStack上可以访问。
<s:form action="SelectPortfolio">
<s:select name="username" list='users' value="defaultUsername" listKey="username" listValue="username" label="Select an artist" />
<s:submit value="Browse" />
</s:form>
7.3.4额外的组件:
1,label组件:只读组件;
Label组件用来在一个表单内部显示只读数据。
<s:label name="username" label="Username"/>
2,hidden组件:隐藏组件;
<s:hidden name="username"/>
3,doubleselect组件:关联下拉列表;
<s:form action="ViewPortfolio">
<s:doubleselect name="username" list='users' listKey="username"
listValue="username" doubleName="portfolioName"
doubleList="portfolios" doubleListKey="value.name"
doubleListValue="value.name" label="Select an artist and portfolio" />
<s:submit value="View" />
</s:form>
第八章:结果;
8.1 动作之后:
传统Web应用程序架构:
传统web应用程序向客户返回完整的HTML页面响应:
客户发起了一个指向某个动作的请求。
这个动作很可能接收一些请求数据,调用一些业务逻辑,然后将后续的业务数据放在valueStack上。
之后,动作将控制转交给一个结果,这个结果使用预先准备好的数据构建并呈现一个完整的HTML页面。
---响应是一个完整的HTML页面,客户浏览器使用这个完整的页面呈现了整个窗口。
---发送回客户的响应很可能由默认dispatcher结果类型下的JSP页面呈现。
Ajax应用程序:
从服务器接收HTML片段、XML或者JSON响应,而不是完整的HTML页面。
8.1.2 实现JSON结果类型:
JSON提供了一种简洁的、基于文本的数据对象序列化的方式。
JSON是Web应用程序服务器和Ajax客户之间数据通信的一种非常简洁的轻量级的方式。
使用JSON,我们可以将java端的数据对象序列化,并且在响应中将序列化的数据发送到客户。另一方面,我们可以很容易地将这些JSON数据反序列化成JS运行时的对象,并且在不需要刷新整个页面的情况下更新客户端视图。
1,展示结果的ajax客户:
示例:艺术家信息查看器;
2,JSONResult编码:
使用ajax客户请求JSON响应,需要构建一个自定义的结果,自定义JSONResult结果。
从valueStack到JSON响应序列化对象:
public class JSONResult implements Result {
public static final String DEFAULT_PARAM = "classAlias";
String classAlias;
public String getClassAlias() {
return classAlias;
}
public void setClassAlias(String classAlias) {
this.classAlias = classAlias;
}
public void execute(ActionInvocation invocation) throws Exception {
ServletActionContext.getResponse().setContentType("text/plain");
PrintWriter responseStream = ServletActionContext.getResponse()
.getWriter();
/* Retrieve Objects to Serialize to JSON from ValueStack */
ValueStack valueStack = invocation.getStack();
Object jsonModel = valueStack.findValue("jsonModel");
XStream xstream = new XStream(new JettisonMappedXmlDriver());
/*
* If there's no parameter passed in, just write the objects under a
* default name.
*/
if (classAlias == null) {
classAlias = "object";
}
xstream.alias(classAlias, jsonModel.getClass());
/* Write to the response stream */
responseStream.println(xstream.toXML(jsonModel));
}
}
1实现Result接口;
2实现了一个javabean属性classAlias;
3默认参数classAlias;
4实现接口的execute()方法;
5在servlet响应上设置内容类型;
6得到输出流;
7从valueStack取出想要序列化的域对象;
8声明把java对象序列化为XML的实例;
9使用classAlias设置需要序列化的对象的别名;
10将jsonModel序列化到响应的输出流。
3,Ajax客户:
ajaxUserBrowser.jsp页面;
下拉列表; 信息窗口; 下拉列表中fetchUser()事件;
ajaxUserBrowser.js
function fetchUser(){
console=document.getElementById('console');
var selectBox = document.getElementById('AjaxRetrieveUser_username');
var selectedIndex = selectBox.selectedIndex;
var selectedValue = selectBox.options[selectedIndex].value
sendRequest("AjaxRetrieveUser.action", "username=" + selectedValue , "POST");
}
处理服务器的响应的onReadyState函数:
function onReadyState() {
var ready=req.readyState;
var jsonObject=null;
if ( ready == READY_STATE_COMPLETE ){ //1,响应是否完成
jsonObject=eval( "("+ req.responseText +")" ); //2
toFinalConsole ( jsonObject ); //3
}
}
---2,将json响应文本实例化为一个js对象;
---3,把这个对象发送给函数,这个函数动态修改蓝色窗口以展现新的艺术家的信息。
4,动作:
RetrieveUser.java;
传入和传出数据依然由javabean属性来承载;
execute()方法荣然会调用业务逻辑,包含对服务对象getUser()方法的调用;
之后通过将用户设置到一个本地的javabean属性上而把结果数据公开出来。
5,声明和使用JSONResult结果类型:
在自己的包中将JSONResult声明为可用的结果类型;
在动作的返回中指定结果类型;
ajaxRetrieveUser动作准备user数据,把它放在valueStack上,并且将响应的处理转交给customJSON结果。这个结果将用户对象序列化为JSON,并且把它发送回客户。
在客户端,一个回调函数接收JSON,从这些数据生成一个js对象,将这个js对象传入一个动态更新页面显示新艺术家信息的方法。
8.2 常用的结果类型:
8.2.1 dispatcher:分发器;
Struts2的struts-default包的默认结果类型。
当你想呈现一个JSP页面作为动作的结果时可以所使用这个结果。
普通的struts2工作流:一个请求访问一个动作,动作处理这个请求,之后将控制转交给结果向客户写回响应。在这个常规的用例中,使用dispatcher结果很简单。
Dispatcher的特点是转交完全发生在服务器端,所有的处理都发生在servlet api 内部,并且在同一个线程内部。这意味着第一个资源的数据通过servlet api 和struts2的actionContext都可以被第二个资源访问。这是第二个servlet能够完全访问所有的数据的关键。
8.2.2 redirect:重定向;
在浏览器中新URL替换原始URL;
1,建立重定向的结果类型:
struts-default.xml中该结果类型的声明;
在配置文件中配置一个重定向结果,以高速浏览器指向其他URL;
2,嵌入OGNL表达式创建动态的位置:
<action name="SendUserToSearchEnhineAction" class="myActionClass">
<result type='redirect'>
http://www.google.com/?maParam=${defaultUsername}
</result>
</action>
---OGNL表达式在valueStack上查找对应的属性。假如myActionClass做了某些操作让defaultUsername属性出现在valueStack上。
8.2.3 redirectAction:重定向动作;
1),可以从动作和包的声明中提供redirectAction的名字和命名空间,使得声明在面对URL模式变化时更加灵活。
2),配置传递到目标动作的请求参数;param
3),使用嵌入OGNL表达式将动态值传递到结果参数值中。
<action name="Login" class="manning.chapterEight.Login">
<result type="redirectAction">
<param name="actionName">AdminPortfolio</param>
<param name="namespace">/chapterEight/secure</param>
<param name="param1">hardCodedValue</param>
<param name="param2">${testProperty}</param>
</result>
<result name="input">/chapterEight/Login.jsp</result>
</action>
8.3 jsp替代品:
8.3.1 velocity:
使用velocity结果;
不同视图层技术语法的不同;
OGNL表达式完全相同;
8.3.2 freemarker:
将结果的type属性指向FreeMarker,并且将location参数指向FreeMarker模板。
使用嵌入式的OGNL表达式将动态值传递到参数中。
不同视图层技术语法的不同。
8.4 全局结果:
示例:错误页面声明为全局结果;
<global-results>
<result name="error">/chapterEight/Error.jsp</result>
</global-results>
全局结果声明在global-results元素内部;
在包内声明了这个全局结果后,包的任何动作只要返回一个error控制字符串,结果页面就会由这个JSP结果处理。
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
第四部分:完善应用程序
第九章:集成spring和hibernaer/jpa;
只关注spring的依赖注入;
使用hibernate处理数据持久化;
9.1 为什么在Struts2 中使用Spring:
9.1.1 依赖注入能做什么:
Struts2的一些紧密耦合的对象,例如:portfolioServer;
Spring最小化对象之间的耦合。
示例:紧密耦合的对象;
public class Register extends ActionSupport implements SessionAware {
public String execute() {
getPortfolioService().createAccount(user); //1)
session.put(Struts2PortfolioConstants.USER, user);
return SUCCESS;
}
private String username; //用于接收数据
private String password; 转移属性
private String portfolioName;
private boolean receiveJunkMail;
public PortfolioService getPortfolioService() { //2)
return new PortfolioService();
}
---2),这个服务对象通过new操作符直接实例化获得;
紧密耦合到一个具体的实现和紧密耦合到一种取得引用的方法。
使用spring容器将依赖注入到对象,这样避开了耦合到一个具体的取得引用的方法。同时,也会引入一个接口以提供一个分离层,从而将具体服务对象的实现和使用这个服务对象的代码分离开来。
9.1.2 spring如何管理对象和注入依赖:
1,元数据,applicationContext.xml;
2,使用被管理对象提供的设置方法把对象注入到动作;
9.1.3 使用接口隐藏实现:
引入服务对象的接口;
动作依赖于一个服务对象,并且提供了针对这个接口类型的设置方法来接收spring注入。
Login动作公开了一个设置方法,spring向其中注入服务对象:
public class Login extends ActionSupport implements SessionAware {
public String execute(){
User user = getPortfolioService().authenticateUser( getUsername(), getPassword() );
if ( user == null )
{
return INPUT;
}
else{
session.put( Struts2PortfolioConstants.USER, user );
}
return SUCCESS;
}
private String username;
private String password;
//省略了获取方法和设置方法;
PortfolioServiceInterface portfolioService;
public PortfolioServiceInterface getPortfolioService( ) {
return portfolioService;
}
public void setPortfolioService(PortfolioServiceInterface portfolioService) {
this.portfolioService = portfolioService;
}
private Map session;
public void setSession(Map session) {
this.session = session;
}
}
9.2 将Spring添加到Struts2:
将spring 添加到struts2应用程序;
让spring提供一个对struts2 objectFactory的扩展;
将spring插件添加到应用程序中;spring就有机会管理任何由框架创建的对象的创建过程;在pring配置文件中将需要管理的对象声明为spring Bean 对象。
9.2.1 让spring管理动作、拦截器和结果的创建:
applicationContext.xml文件中声明spring bean;
动作的映射中使用 spring bean 的id;
9.2.2 使用自动连线将依赖注入到动作、拦截器和结果:
如果你只想注入依赖,有一个更简单的方法:自动连线;
自动连线是一种不需要在applicationContext.xml文件显示声明的依赖注入方式;
通过name自动连线:
使用name的自动连线是通过匹配被管理的spring bean 的id和潜在的目标对象公开的设置方法的名字工作的。
9.3 为什么在Struts2中使用JPA:
集成JPA到web应用程序;
9.3.1 使用JPA和hibernate建立项目:
1,需要的jar文件;
2,mysql数据库;
3,使用spring 管理JPA依赖;
applicationContext.xml:
让spring创建JPA entityManager,并且将这个对象注入到公文包服务对象。
4,使用spring的openEntityManagerInViewFilter过滤器处理延迟加载:
持久化技术优化之一:延迟加载;
在一个MVC Web应用程序中,通常情况下动作类从数据库加载数据,例如前面提到的User对象。之后它将控制转移给视图层,如一个JSP页面。通常,这个User对象引用的一个给定的Portfolio,直到呈现结果页面时JSP标签遍历这一系列Portfolio时才会被读取。如果持久化上下文已经关闭,对没有加载的Portfolio数据的访问失败,因为延迟加载已经不再使用。
解决方案:hibernate的openSessionInView模式;
JPA的openEntityManagerInView解决方法;spring提供了一个广泛使用的Servlet过滤器实现的解决方法;
Web.xml;
9.3.2 基于spring管理JPA编写代码:
1,持久化单元;
Persistence.xml;
2,使用注解将java类映射到数据库表;
JPA持久化实体对应的User类;
3,使用JPA EntityManager实现服务对象;
使用JPA管理user和Portfolio对象的持久化;
第十章:搜索验证框架;
10.1 熟悉数据验证框架:
10.2 将动作关联到验证框架:
10.3 编写自定义验证器:
10.4 验证框架的高级主题:
第十一章:理解国际化;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
第五部分:高级主题和最佳实践
第十二章:使用插件扩展sturts2;
12.1 插件概要:
Struts2插件架构使得开发人员可以通过只在应用程序类路径中追加一个JAR文件来扩展框架,这些扩展可以用来支持框架也可以用来扩展Web用户体验。
Struts2框架的任何一部分都可以以标准的、一致的方式被替换、扩展或者删除。
Struts2运行时配置:
1),struts-default.xml;(存在于Struts2-core-x.y.z.jar文件中)
2),struts-pluginxml;(存在于所有插件的jar文件中)
3),struts.xml;(由应用程序提供)
Struts2网站的插件注册表。
12.2 常用插件:
12.2.1 SiteMesh:
SiteMesh是一个网页界面外观、布局和导航框架;
Struts2提供了一个SiteMesh插件可以讲框架的ValueStack公开给SiteMesh页面装饰器。
12.2.2 Tiles:
Tiles是SiteMesh的一个不错的替代;
Struts2 Tiles插件提供了一个新的结果类型来使用Tile定义呈现页面。
配置web.xml;
动作映射的配置,使用Tiles页面呈现框架。
12.2.3 JFreeChart:
JFreeChart插件允许一个动作返回包含生成的图表和图形的页面。
应用程序中的声明性配置文件。
12.3 内部组件系统:
有两种类型的对象可以被注册到注入框架:常量和bean。
可用的框架扩展点和Struts2中可用的常量选择器。
12.4 编写浏览路径插件:
拦截器接口;
拦截器;
第十三章:最佳实践;
13.1 建立开发环境:
Eclipse IDE;
需要的类库;
13.2 对动作进行单元测试:
13.2.1 将IoC用于 测试的优势;
如果运行一个有效的测试需要触发动作的拦截器,那么通过ActionProxy测试动作。
否则直接把动作当做一个单纯的POJO测试。
13.2.2 JUnit与测试:
典型的动作类;
一个单纯的POJO动作的简单JUnit测试;
使用ActionProxy的JUnit测试;
13.2.3 测试validation.xml文件:
13.3 最大化重用:
13.3.1 使用component标签组件化:
Component标签使用指定的模板呈现UI部件。
编写自己的freeMarker模板,并且将它传入被呈现的组件自定义标签;
<s:component template = "now.ftl" />
Now.ftl文件:
13.3.2 重用模板化的标签;
13.3.3 连接UI标签和对象;
13.4 高级UI标签的使用:
13.4.1 覆盖既有模板;
13.4.2 编写自定义模板;
第十四章:从经典Struts迁移;(去除不看)
第十五章:高级主题;
15.1 高级动作的应用:
首先的:包含多个相关方法的动作类;(代码清单15-2)
然后的:在配置动作映射时,指定应该调用的方法;(代码清单15-1)
15.2 动态方法调用:
动态方法调用,只编写一个映射,将每个方法被调用的具体细节交给框架。
15.2.1 通配符方法的选择:
CoinAction的通配符映射;(代码清单15-4)
15.2.2 动态工作流:
通配符映射中更动态的替换。
15.3 使用令牌防止表单重复提交:
15.3.1 使用<s:token/>表单标签;
<s:token/>令牌标签;
使用令牌拦截器声明动作映射;
阻止重复请求;(代码清单15-10)tokenSession拦截器。
15.3.2 令牌拦截器规则的例外:
根据方法名决定是否拦截的拦截器栈;(代码清单15-11)
15.4 自动显示等待页面:
为长时间运行的动作声明动作映射;加入等待拦截器栈;
长时间运行动作的拦截器栈;execAndWait拦截器。
waitPage页面:
这个页面设置了浏览器定时器2秒之后再刷新页面;动作未执行完,则继续显示此等待页面;最终,动作执行完后,返回成功的结果页面。
15.5 完成CRUD操作的一个动作:
15.5.1 CRUD:
包声明;
15.5.2 拦截器和接口:
CRUD动作类;
超类;
模型;
网页;
15.5.3 连接各部分:
Struts2请求的旅程。
15.6 Tiles和Struts2:
15.6.1 关注网站的界面外观:
一致的网站外观的重要性以及能够简单地变更整个网站外观的需求。
布局与网页的分离;
在Tiles中,网页实际由很多小的方块(tile)组成,小页面放置咋这些小方块中。一个独立的小方块可以进一步分为方形区域,一次类推。
15.6.2 配置相互关系:
Tiles定义;
网站的观感定义页面;(base.jsp)
全部的观感页面;
15.6.3 使用声明性架构:
Tiles插件的jar文件;
在web.xml中追加需要的条目;
Struts.xml文件中的配置;
动作映射;
15.6.4 使用Tiles控制器准备网页内容:
Tiles调制器(preparer);
这个调制器是一个Tiles控制器,可以在Tiles页面组合之前写出一些需要预先完成的工作;
这里指定ListMembers类来取得membersBody.jsp页面中包含的用户。
////////////////////////////////////////////////////////////////////////////
本书对应的struts2版本:2.2.3;
代码下载:
下载struts-2.3.1.2-lib.zip;struts2的类库;---(没问题;)
(旧的找不到地方;)
http://www.manning.com/ 下载示例代码:SampleApplication.zip
War文件打开方式,将war文件复制到Tomcat 7.0\webapps下---关闭,重启tomcat工具---解压出文件夹;可以使用。---(没问题;)
helloWorld示例:
WebContent/web-inf/lib下放置类库;(使用2.2.3的类库)
Webcontent,右键,可以建立jsp/html页面,也可以建立文件夹,文件夹中再建立jsp/html页面;
WebContent/web-inf下整个应用程序的中心配置文件web.xml;
Java Resources/src下放置所有类文件;属性文件和配置文件;
Java Resources/src下建立struts.xml文件;
Java resources\src,右键,建立包文件(manning.chapterTwo ),包下建立类,xml文件;
manning.chapterTwo右键建立类;
放置新类库出错,放置struts2-2.2.3的类库运行正确;
---原因,struts2版本不同,造成的web.xml等的不同,而出错。