Struts in Action

转自:http://blog.csdn.net/Jiangcx/article/details/2234196

用了这么长时间的Struts,却从来没有完整地看完一本书,经过一段时间Qone的开发,更是发现了对Struts掌握的不够好,终于完整地把《Struts  in  Action》看了一遍,发现很多以前不会的东东,这本书不错,从原理到实践,都讲的很好。希望以后能有时间再看几遍。现将读书笔记贴在这儿留作纪念。笔记写的很简单,只是捡一些自己不会的或认为很重要的记了一下,看的是英文版,很多不知道怎么翻译的,也直接摘的英文原句。不推荐大家参考我的笔记,呵呵。


Struts In Action

----Building web applications with the leading Java framework

第一部分 初识Struts

第一章   简介

1.1本书宗旨

本书旨在帮助web开发者更好地使用Struts web应用程序框架。Struts基于一些标准的技术,例如Java Beans,Java Servlets,JSP等。Struts能帮助web开发者快速简单地构建web应用。

1.1.1谁创建了Struts

Struts是Apache Software Fundation的Jakarta项目的一部分。Struts的主要架构师和开发者是Craig R. McClanahan。

1.1.2 Struts为何开源

         几乎所有的Java工具和框架都是开源的,开源框架对大家来说是双赢的。

1.1.3 为什么叫做Struts

         Struts名称用以提醒我们结构的重要性。

1.2 什么是应用程序框架

         框架是一个可复用的,半成品的应用,可以被特殊化以生产定制化的应用程序。

1.2.1 其他类型的框架

         Lucene,Scaffold Toolkit,Struts Validator,Tiles tag Library。

1.3 必需的技术

         这些技术也是所有Java web应用必需的技术。

1.3.1 HTTP

         Web应用使用HTTP来在浏览器端和服务器端之间传输数据。HTTP是一种无状态的协议。HTTP能成为通用标准的一个原因在于它的简单性,HTTP请求和相应都是简单的文本文档。

         由于HTTP是无状态的,这使跟踪使用者和请求很成问题,通常的两种方法是使用Cookies和URL重写。Cookie是用户电脑上的特殊的信息包。URL重写在页面地址中存储一种特殊的引用用来跟踪使用者。

1.3.2 CGI(Common Gateway Interface)

         第一种被广泛使用的用来创造动态内容的标准是CGI。CGI使用标准的操作系统特性,例如环境变量或者标准I/O在web服务器和主机的其他应用程序之间创建一个桥或网关,其他应用程序可以查看web服务器发送给它的请求并创建定制化的响应。

         CGI的两个缺点:为每个请求创建CGI程序,操作系统不可移植。

1.3.3 Java Servlets

         Java Servlet平台关注了CGI的两个缺点,一是更好的性能和资源利用率,二是Java的操作系统可移植性。

         为使通用的Web服务器可以访问servlets,servlets被插放在容器中。

         与CGI程序不同,并不对每个request创建一个新的servlet,只是为每一个请求创建一个线程,Java 线程比CGI程序使用的服务器端进程要节省资源。

1.3.4 JavaServer Pages

         Java Servlets使页面设计和业务逻辑处理混在一起,无法实现明确的分工。

         为向页面引入动态元素,开发者可以在HTML中插入JSP脚本元素,共有三种:expressions(<%=%>),Scriplet(<%%>)和declarations(<%!%>)。

         一个JSP页面实际就是一个Java Servlet。

1.3.5 JSP标签

         Scritplet快速、简单、强大,但是把java代码和HTML混合在一起,一个更好的选择是使用JSP标签。

         大部分的Struts开发者使用JSP和自定义的标签来创造应用中的动态内容。

1.3.6 JavaBean

         页面的动态数据可以使用一个JavaBean来传递,JSP标签可以使用这个JavaBean的属性来定制动态内容。

1.3.7 Model 2

         Servlet/JSP的0.92发布版把在同一个应用中使用JSP和Servlet的体系结构描述为Model 2。

         Struts框架基于Model 2,并提供了一个基础的自定义标签库,使Struts更易使用。

1.4 高瞩远瞻Struts

         Struts使用Model 2体系结构,Struts的ActionServlet控制导航流。Struts的Action类用来访问业务类,当ActionServlet从容器接受到一个request时,它使用URI来决定使用哪一个Action来处理这个request。Action可以验证输入和从业务层获取来自数据库或其他数据设备的信息。

         为了获取输入数据,Action并不是从request中获取所有的数据,而是ActionServlet将输入都绑定到一个JavaBean,输入beans都是Struts的ActionForm类的子类。ActionServlet通过request的路径来决定使用哪个ActionForm。ActionForm都继承自org.apache.struts.action.ActionForm。

    每一个HTTP的request,都要使用一个HTTP的response来回答。通常,Struts的Action不直接产生response,而是跳转到另外的资源如JSP。Struts提供了ActionForward类,可以用来使用逻辑名称来存储到达一个页面的路径。Action向Servlet选择和返回一个ActionForward, Servlet使用存储在ActionForward对象中的路径来调用页面和完成response。

         Struts将这些详细信息都绑定到一个ActionMapping对象中,每一个ActionMapping都与一个特定的路径相关,当这个路径被请求时,Servlet获取ActionMapping对象,这个对象告诉 Servlet使用哪一个Action,ActionForm和ActionForward。

         所有这些详细信息,Action,ActionForm,ActionMapping,ActionForward,都在struts-config.xml文件中声明。ActionServlet在启动时读取此文件并创建一个配置对象的数据库。在运行时Struts引用这些对象,而不是文件本身。

1.4.1 构建一个简单应用

         这个应用用来注册用户名和密码,通过这个实例可以接触到使用struts来开发应用的方方面面。

1.4.2 开发前的准备

         所需的工具:

n  JDK

n  一个现代的Web容器(例如Tomcat)

n  一个简单的文本编辑器

部署一个web应用最方便的办法是使用WAR文件(Web Archive file),只要简单的把WAR文件放在Tomcat的webapps目录下。

1.4.3 开始开发

n  创建ActionForm

ActionForm对于HTML表单中的每一个字段都对应一个属性。ActionServlet负责匹配request和ActionForm中的属性的参数,如果匹配就调用ActionForm的setter方法,设置从request得到的值。

n  创建Action

Action继承自org.apache.struts.Action。ActionServlet创建ActionForm并传递给Action。Action一般负责验证输入,获取业务信息和决定向servlet返回哪个ActionForward。

n  创建Struts配置文件(struts-config.xml)

Struts框架使用配置文件作为部署的描述子。这使我们可以创建和改变与路径关联的ActionMapping,而无需重新编译Java类。

n  创建页面

1.4.4 Looking Back
1.5 总结

第二章   探索Struts框架

2.1 Talking the talk
2.2 为何需要Struts
2.2.1 退一步,进三步

         很多现代的开发环境,包括Swing,都使用MVC结构作为框架的基础。

2.2.2 进入Struts

         Struts的中心是一个MVC式的控制器。Struts控制器连接view和model之间的鸿沟。

2.2.3 Struts控制器组件

         Struts控制器是一组可编程的组件,这些组件使开发者可以精确定义他们的应用程序如何与用户交互。这些组件将笨拙的实现细节隐藏在逻辑名称后面,

n  超链接

对于开发者来说,超链接是应用程序中一些资源的路径,这些可能是页面,或者是自定义的Action。它可以包含一些特殊的参数。在Struts中,开发者可以将超链接定义为一个ActionForward。这些对象具有一个逻辑名称和一个path属性,开发者设定path属性,然后通过逻辑名称来引用这个ActionForward。

n  HTML表单

Struts提供了ActionForm类来处理来自HTML表单的输入,验证这些输入,以及重新显示这些表单。

Struts配置通过一组描述子来引用ActionForm类:<form-beans>和<form-bean>元素。Struts配置列出了它使用的ActionForm beans,并且赋予这些ActionForm类一个逻辑名称,以在程序中引用。

n  自定义Actions

HTML表单使用一个action参数告诉浏览器向何处传送表单数据,Struts框架提供了Action类来接受表单数据。框架自动地创建,传送合适的ActionForm给Action对象。Action可以直接从ActionForm得到它需要的数据。Action返回一个ActionForward对象给控制器。

n  ActionMappings

ActionMapping使得同一个Action对象可以被不同的映射使用,例如一个mapping使用需要验证,另一个不需要验证。

n  ActionServlet

Struts的ActionServlet一直在幕后工作,将所有其他的组件连接起来。

n  区域化

Struts组件具有区域化的特性。

2.2.4 使用Struts开发web应用程序

         Struts将表现层与Model分离。

2.3 为何需要框架

         为何web开发具有挑战性?

2.3.1 The web—a never-ending kludge

         Web开发者受双层折磨:一是使用web浏览器作为客户端,二是使用web协议进行通信。Web浏览器使用HTTP协议进行通信,展现使用HTML创建的页面。Web浏览器发送HTTP请求,产生HTML作为响应。这对于预先写好的页面是一个不错的平台,但我们大部分人都是写动态的页面。

         HTTP协议和web浏览器决定了web应用的书写方式,这种方式有很多限制。

2.3.2 Servlet解决方案

         Servlet构建于HTTP之上,并提供了session上下文用以帮助跟踪应用程序的用户。

         Servlet规范描述了一个管理servlets的容器。

         对于数据库访问,Java编程框架提供了JDBC。

         对于访问远程数据库的高性能应用,可以使用EJB平台,大部分的Java应用程序框架,包括Struts,都可以在EJB上使用。

         Struts构建在servlet平台之上,提供了无缝的环境。

2.3.3 Servlet框架

         通常来说,Web应用程序框架的焦点是辅助从web浏览器取得数据,给程序结构使用,和将程序结构的数据输送到web浏览器,展示给用户。

通用框架策略

Java web应用程序框架使用几个通用的技术来使产品的设计、书写、维护更加容易:

n  外部配置文件。提供开发者不想混入代码的一些实现细节。

n  中心控制器

n  外部表现系统

2.3.4 白盒—黑盒体

         白盒框架很强地依赖于面向对象的特性如继承和动态绑定,而黑盒框架倾向于为可插入的组件定义接口,并且提供基于这些接口的基础组件。

2.4 Struts,Model 2和MVC
2.4.1 MVC的演化

         MVC是构建Smalltalk程序的一个框架。

2.4.2 Model 2的兴起

         将JSP与Servlet一起使用被称作是Model 2(只使用JSP为Model 1)。

2.4.3 应用程序分层—解耦View

         Model 2与MVC被认为是不同的一个原因是观察者通知模式在web环境下不能很好地工作。HTTP是一个pull的协议,客户端请求,服务器端响应,没有请求就没有响应。观察者模式需要一个push的协议。

         分层的web应用使用的是一个“平”的MVC模式。

2.4.4 Struts对Model 2,MVC和分层结构的实现

         Struts对Model 2的实现是,提供了一个控制器servlet用来管理jsp页面和其他表现层设备之间的流转。Struts对MVC和分层结构的实现是:使用ActionForwards和ActionMappings保持控制流决策处于表现层之外,

2.5 Struts控制流
2.5.1 The big picture

Struts的请求响应过程:

n  客户请求匹配Action URI模式的路径

n  容器将请求传递给ActionServlet

n  如果是模块化的应用程序,ActionServlet选择相应的模块

n  ActionServlet查找路径的映射

n  如果映射指定了一个form bean,ActionServlet检查是否已经存在,否则创建一个

n  如果存在form bean,则ActionServlet重置form bean,并根据HTTP请求重新计算

n  如果映射的validate属性设置为true,则调用form bean的validate方法

n  如果验证失败,servlet将转发到input属性指定的路径,本控制流结束

n  如果映射指定了一个Action类型,如果已经存在则重用,否则实例化一个对象

n  调用Action的perform或者execute方法,传递给它已经实例化的form bean,或者null。

n  Action可以创建form bean,调用业务对象,或者做其他一些该做的事情

n  Action向ActionServlet返回一个ActionForward对象

n  如果返回的ActionForward是另一个Action URI,则重新开始;否则显示页面或其他资源。通常是一个jsp页面,使用Jasper或同等物来产生页面。

n  如果Jsp使用了Struts的HTML标签,则从request中取得合适的ActionForm,并从ActionForm产生控件。否则<html:form>产生一个ActionForm,从Struts1.1开始,form标签如果自己创建ActionForm则调用ActionForm的reset方法。

2.5.2 细节

Request被容器接收

Struts框架的主干组件是ActionServlet。同所有的servlet一样,他存活在一个容器之中,如Tomcat,Resin或Weblogic。当容器启动的时候,它读取部署描述子(web.xml)来决定加载哪些servlets。

         其中一个标准的servlet设置是servlet mapping。容器使用这样的设置来决定哪些请求发送给哪一个servlet。

<servlet-mapping>

<servlet-name>action</servlet-name>

<url-pattern>/do/*</url-pattern>

</servlet-mapping>

Request被我们的ActionServlet接收

         当我们的ActionServlet接收一个请求时,使用一连串的操作来处理地域化,映射,form bean,最后是Action。

处理MultiPartRequest。如果是Multipart请求(表单具有MIME附件),则servlet使用一个特殊的句柄(handler)来包装这个request,以避免在后来的处理中出错。

处理路径。ActionServlet检查路径是否是一个应用程序模块的路径。如果是,则选择相应模块的配置。

处理地域化。缺省情况下,ActionServlet将检查用户的会话中是否存在一个标准的locale对象。如果不存在ActionServlet将放一个这样的对象在session中。这个对象用来向每一个用户提供区域化的表现。

处理内容和NoCache。缺省的MIME类型和可选的request头被加到响应中。

处理映射。ActionServlet检查是否存在一个mapping与我们正在处理的path相对应,如果没有找到则转发到缺省的Action,如果没有缺省的Action则产生一个“bad request”错误。如果找到这样的mapping,则放在request中以备后来使用。

处理角色。ActionServlet检查用户是否被授权访问这个Action。

处理ActionForm。ActionServlet检查mapping是否指定了一个ActionForm。如果指定了,则ActionServlet检查在指定的范围内(缺省是session范围)是否存在一个对象,如果不存在,则创建一个对象。

处理算值。调用ActionForm的reset方法,并使用反射自动产生值。符合ActionForm属性的参数将被应用。其他的参数或属性被忽略。

处理验证。调用ActionForm的validate方法,如果返回false,则控制交给mapping指定的input属性,action不会被处理。

处理转发或包含。如果ActionMapping指定了forward或include属性,则控制转交给另一个资源。否则ActionServlet将请求代理给Action对象。

处理Action。如果mapping指定了一个Action类型,则servlet检查是否已经存在一个Action类型的实例化对象,如果没有找到则实例化一个Action类型的对象,每一个类只有一个Action对象(单例模式),这个Action对象通过多线程处理所有的请求。Servlet调用Action的perform或execute方法,并把actionmapping,request,response和form bean传递给这个方法。

         Action是一个控制类,不应该用来处理应用程序的核心业务逻辑。

Action返回一个ActionForward

Jasper或同等物产生一个Jsp

         当Servlet发送一个请求给Jsp时,请求由其他的服务,如Jasper来处理。

其他的servlet产生响应

         处理完Action后,request可以传递给其他的servlet或服务。

2.5.3 Struts高效吗?

         通常来讲,Struts应当会提交适度设计的Web应用。

Struts不仅thread-safe而且thread-dependant。

ActionForm beans最小化子类代码并缩短了子类继承结构。

Struts标签库提供通用的功能。

Struts组件是可以被应用程序重用的。

Struts的区域化策略减少了重复JSP的需要。

Struts是使用开发的体系结构设计的。

Struts是轻量级的。

Struts是符合标准的。

Struts是开源的,且文档比较充分。

Struts是独立于model的。

2.6 Struts的长处与短处
2.6.1 弱点

第三章    构建一个简单的应用程序

3.1 Strut By Strut
3.1.1 为什么选择一个Logon程序?

         容易理解、简单自包含、很多应用程序都需要。

3.2 总览Logon程序
3.2.1 开始旅程
3.2.2 将要看到的页面

         欢迎页面和Logon页面。

3.2.3 欢迎页面
3.2.4 Logon页面
3.2.5 再看欢迎页面
3.2.6 与欢迎页面说再见
3.2.7 聚集的特性
3.3 深入剖析Logon应用程序
3.3.1 欢迎页面的浏览器代码

Jsessionid键值:为了跟踪用户,使用cookies和URL重写技术。但是不是所有的浏览器客户端都支持cookies,所以第一次请求时,容器都会创建一个jsessionid,如果在接下来的请求中容器发现客户端接受cookies,则可以略过重写URL。

3.3.2 欢迎页面的JSP代码

<%@ taglib uri="/tags/struts-html" prefix="html" %>

<%@ taglib uri="/tags/struts-logic" prefix="logic" %>

是JSP的同等物,用来引入扩展标签供页面的其余部分使用。

         <html:base/>产生一个标准的HTML的base标签,一些引用,如图片,可以使用与最初Jsp页面的相对位置。之所以使用这个标签,是因为对于动态的应用程序,我们访问的地址并不是Jsp页面的地址,可能是Action,java类等的地址。

         Struts的所有逻辑标签都使用this和notThis的形式,不提供else标签。

         可以给一个连接一个逻辑名称,使用逻辑名称来引用(<html:link>)。这种映射在配置文件中配置。这样,如果要修改链接,只需要在配置文件中修改一次。

3.3.3 欢迎页面的配置代码

         配置文件的缺省名称是struts-config.xml。

3.3.4 Logon页面的浏览器代码

         标签库的描述子TLD在web.xml文件中给出。

         <html:form>标签的focus属性,产生javascript代码,使相应的控件获得焦点。

         <html:text>标签产生一个文本域的HTML输入控件。

         <html:password>的redisplay属性可以控制返回时是否设置值。

         <html:submit>产生标准的HTML的submit控件。

         <html:reset>产生标准的HTML的reset控件。

3.3.5 Logon页面的配置代码

         /LogonSubmit:ActionMapping

         app.LogonForm

         app.LogonAction

3.3.6 LogonSubmit代码

         ActionMapping的input属性:如果验证失败,返回input指定的地方。

3.3.7 LogonForm代码

         基类ActionForm包含reset方法,如果mapping的scope设置为request,则不必实现reset方法。

3.3.8 LogonAction代码

         Action的execute方法比perform方法提供了更好的异常处理,其他都一样。

         Debug级别在Web部署描述子web.xml中指定。

3.3.9 LogoffAction代码
3.4 构造一个应用程序
3.4.1 定义需求
3.4.2 规划应用程序

视图

控制器

模型

3.4.3 规划代码树
3.4.4 配置开发工具

         使用ant作为构建工具。

3.4.5 配置build.xml文件
3.4.6 配置web.xml文件

         Java2 Servlet框架使用web.xml文件来配置应用程序。标明使用的servlets和其他一些设置。对于Struts应用,只需要配置一个servlet和一些标签库。

3.4.7 配置struts-config.xml文件

welcome Action

容器要求必需使用一个页面作为welcome页面。通常的解决方式是使用一个index.jsp,来重定向到welcome Action。

3.4.8 测试部署的结果

Struts Blank应用程序可以用来测试环境,它包含了很多系统检查。

3.4.9 构造自己的欢迎页面
3.4.10 构造Logon页面
3.4.11 构造Constants类
3.4.12 构造其他类
3.4.13 创建用户目录
3.4.14 配置ActionErrors

         作为构建的过程,要把要把应用程序资源文档拷贝到classes目录下,以便ActionServlet能够找到。

3.4.15 编译和测试Logon页面
3.4.16 修补欢迎页面
3.4.17 Struts的ActionForward Action

         我们要尽可能链接到Struts的Action,而不是JSP。但是为每一个JSP配置一个Action非常麻烦,可以使用ForwardAction,只要将parameter属性配置为JSP的地址即可。

第四章   配置Struts组件

4.1 三个XML文件和一个Properties文件

         Struts开发者必需维护一些配置文件。

n  web.xml。这个文件是Java Servlet规范需要的,servlet/JSP容器需要此文件加载和启动程序。

n  struts-config.xml。

n  build.xml。ant工具需要的,不是必需的。

n  application.properties。提供消息资源。

4.1.1 其他一些文件

         如果使用其他一些可选的组件如Tiles框架、Struts Validator,还需要配置其他一些XML配置文件。如果您把程序化成多个模块,则每个模块可以使用自己的struts配置文件和消息资源文件。

4.2 Web应用程序部署描述子
4.2.1 web.xml文件

         Struts框架包含两个组件需要由应用程序的部署描述子来配置:ActionServlet和标签库,其中标签库是可选的。

         <load-on-startup>设置为2,允许先加载其他的servlets。这样就支持从ActionServlet继承的情况。

         <taglib-location>提供与标签库描述子的相对位置,标签库描述子TLD是标签库的实际类型(Java类)。

4.2.2 ActionServlet参数

         multipartClass,用来处理文件上传的类。

         validating,是否使用DTD来验证Struts配置文件。

4.3 Struts配置

         Struts配置文件与ActionServlet一起创建应用程序的控制层。

4.3.1 细节,还是细节

         Struts配置文件中的每一个组件都是一个Java对象。

4.3.2 变更管理

         存在一些Struts GUIs,可以维护Struts的XML配置文件。

4.3.3Protected Variation的原则

         Struts配置文件的很大一部分细节是关于表示层的。

4.4 Struts配置元素

         Struts使用Digester及配置文件的DTD来解析Struts配置文件。

         Struts配置元素:

n  data-sources,包含一组DataSource对象(JDBC2.0标准扩展)

n  data-source,指定一个DataSource对象,作为servlet上下文属性

n  set-property,指定一个附加的JavaBean的方法名和初识值

n  global-exceptions,描述一组Action对象可能抛出的异常

n  exceptions,为exception类型注册ExceptionHandler

n  form-beans,描述一组bean描述子

n  form-bean,描述一个FormBean的子类,以便供<action>引用

n  form-properties,描述一个可以用来配置DynaActionForm及其子类的实例的JavaBean属性

n  global-forwards,描述一组ActionForward,可以被所有Action用来作为返回值

n  forward

n  action-mappings

n  action

n  controller,描述ControllerConfig bean,它封装一个应用程序模块的运行时配置

n  message-resources,描述一个MessageResources对象

n  plug-in,指定一个通用的应用程序插件模块的类,可以接受应用启动和关闭事件

Scioworks Camino和Struts Console可以直接管理Struts配置文件。Adalon和ObjectAssembly可以可视化设计产品,并生成初始的Struts配置文件,Java类和JSP

4.4.1 global-exceptions

         Struts框架提供了一个缺省的ExceptionHandler(org.apache.struts.action.ExceptionHandler),它将异常存储为request-scope的属性,为你的exception信息创建一个ActionError对象,并把控制转发到你选择的JSP或其他URI。<html:errors>会自动打印带有地域版本的异常信息。ExceptionHandler可以被继承以添加新的行为。每一个异常都可以指定它自己的handler类。

         为注册异常,需要提供Exception类型,消息资源key,以及response路径,如:

<exception

type="org.apache.struts.webapp.example.ExpiredPasswordException"

key="expired.password"

path="/changePassword.jsp"/>

4.4.2 form-beans

         DynaActionForms在创建的时候,需要额外的属性,我们需要一个地方来存放这些元素。

         ActionFormBean也可以包含property属性来使用DynaActionForm。

 


         <form-bean name="logonForm" type="org.apache.struts.action.DynaActionForm">

<form-property name="username" type="java.lang.String"/>

<form-property name="password" type="java.lang.String"/>

</form-bean>

         使用DynaActionForm不需要使用ActionForm的子类。

4.4.3 global-forwards

         ActionForward将一个逻辑名称和一个URI联系起来。其他组件只需要引用这个逻辑名称。

         ActionForward的主要使用者是Action。

4.4.4 action-mappings

         ActionMappings描述应用程序可以执行什么样的操作和指令。

4.4.5 controller

         Struts允许多个应用程序模块共享一个控制器servlet。每一个模块有自己的Struts配置文件,可以独立于其他模块开发。controller允许每一个模块指定一个独立的ActionServlet的参数。

4.4.6 message-resources
4.4.7 plug-in

         PlugIn接口声明Init和Destroy方法,控制器可以在适当的时候调用。PlugIn Action可以在Struts配置文件中通过<plug-in>注册。

4.4.8 data-sources

         与数据获取层架起一座桥梁。

4.4.9 rolling your own
4.4.10 一个Struts配置文件框架
4.5 应用程序资源文件

         Struts框架为每一个用户维护一个标准的Locale对象(Java.Util.Locale)。应用程序资源文件的缺省名称是通过在web.xml文件中为ActionServlet初始化application参数。这个参数没有缺省值,必需为这个参数赋值才能使用Struts的ResouceBundle。

         使用ant可以将资源文件从源文件树拷贝到二进制类目录下。

4.6 ant build文件
4.7 配置Struts的核心组件
4.7.1 安装Java和Java Servlet容器

         Struts发布版本中包含的文档,有配置各种servlet容器的技术说明。

4.7.2 安装开发环境

         可以使用jEdit和jEdit的ant插件。

4.7.3 安装Struts核心文件

         Struts的发布版本包含了部署Struts的所有文件。

         检查单:

n  下载并解压Struts发布版本

n  将所有的jar包拷贝的/WEB-INF/lib/下

n  将所有的tld文件拷贝到/WEB-INF/下

n  将所有的xml文件拷贝到/WEB-INF/下

n  创建部署描述子

n  创建Struts配置文件

n  创建消息资源bundle

n  创建ant build文件

4.8 配置Tiles框架

         Tiles框架是Struts的可选组件,是强大的页面组装工具。

         Tiles检查单:

n  将struts-tiles.tld和tiles-config.dtd文件从Struts的lib目录拷贝到/WEB-INF/目录

n  将以下片段插入到web.xml文件中

<taglib>

<taglib-uri>/tags/tiles</taglib-uri>

<taglib-location>/WEB-INF/tiles.tld</taglib-location>

</taglib>

n  将空的tiles-defs.xml文件拷贝到/WEB-INF/目录,格式如下:

<!DOCTYPE tiles-definitions PUBLIC

"-//Apache Software Foundation//DTD Tiles Configuration//EN"

"http://jakarta.apache.org/struts/dtds/tiles-config.dtd">

<tiles-definitions>

<!-- skeleton definition

<definition

name="${name}"

path="${path}">

<put

name="${name}"

value="${value}"/>

</definition>

end blank definition -->

</tiles-definitions>

n  在struts-config.xml文件的</struts-config>的结束元素之前加入<plug-in>元素:

<plug-in className="org.apache.struts.tiles.TilesPlugin" >

<set-property

property="definitions-config"

value="/WEB-INF/tiles-defs.xml" />

</plug-in>

4.9 配置StrutsValidator

         Struts Validator也是Struts的一个可选组件。

         配置Validator的检查单:

n  struts-validator.tld和validator-rules.xml文件拷贝到/WEB-INF/目录

n  将以下片段拷贝到web.xml文件:

<taglib>

<taglib-uri>/tags/validator</taglib-uri>

<taglib-location>/WEB-INF/struts-validator.tld</taglib-location>

</taglib>

n  在/WEB-INF/目录下创建空白的validations.xml:

<form-validation>

<formset>

<!-- skeleton form

<form name="${}">

<field

property="${}"

depends="${}">

<arg0 key="${}"/>

</field>

</form>

end skeleton form -->

</formset>

</form-validation>

n  在struts-config.xml文件的</struts-config>元素前添加<plug-in>元素:

<plug-in className="org.apache.struts.validator.ValidatorPlugIn">

<set-property

property="pathnames"

value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>

</plug-in>

4.10 从Struts Blank应用程序开始

         build.xml文件中可能引用了您的机器中没有的文件:

         <property name=" jdbc20ext.jar"

value="/javasoft/lib/jdbc2_0-stdext.jar"/>

<property name="servlet.jar"

value="/javasoft/lib/servlet.jar"/>

<property name="distpath.project"

value="/projects/lib"/>

jdbc2_0-stdext.jar和servlet.jar是创建JavaDocs所需要的。

n  容器中应该包含servlet.jar文件

n  Struts的发布版本中包含jdbc2_0-stdext.jar,很多容器(如Tomcat)中也包含。

4.11 配置模块化应用程序
4.11.1 分治法

         每个模块使用自己的struts-config.xml配置文件

4.11.2 页面前缀
4.11.3 Retrofitting a configuration
4.12 共享Struts的JAR包

         Struts的JAR包可以被容器中的所有Struts应用共享。

第二部分 Raising your framework

第五章   处理ActionForms

5.1 吃进去的是草,挤出来的是奶

         Struts包含了一些JSP标签,可以用来书写动态的HTML控件。如同很多标签库一样,Struts标签也是同JavaBeans一起工作。每一个JSP标签都有一个property属性,提供bean中的一个property的名称。JavaBean的这个property的值用来作为控件的值。

5.1.1 ActionForm需求

         如果要使用ActionForm来验证输入,则必需实现validate方法。

         如果要初始化properties,则必需实现reset方法,用以在获取ActionForm的properties的值之前调用。

5.2 ActionForm的多重功能
5.2.1 ActionForm作为域捕获器

         Struts使用ActionForms来弥补HTML和HTTP的缺点。

5.2.2 ActionForm作为数据缓冲

         ActionForm并不是输入的目的地,只是验证和传输前的缓冲区。

5.2.3 ActionForm作为数据验证器

         ActionForm的validate方法是一个扩展点,在这里你可以调用业务层方法来验证输入。

5.2.4 ActionForm作为类型转换器

         ActionForm的properties只能是String或boolean类型。

5.2.5 ActionForm作为对象传输者
5.2.6 ActionForm作为火墙
5.3 ActionForm设计效果

n  与业务层的bean具有相同的property名称

n  最小化自定义的代码

n  封装helper方法

n  包含其他JavaBeans

5.3.1 ActionForms可能会共享名称
5.3.2 ActionForms可以最小化自定义的代码
5.3.3 ActionForms可以封装helpers
5.3.4 ActionForms可以嵌套其他beans

<html:text property="values.telephoneText" size="14" maxlength="14"/>

等同于

aForm.getValues().getTelephoneText()

浏览器端会这样传输数据:

values.telephoneText=555-1234

自动获取机制会这样取值:

aForm.getValues().setTelephoneText(

(String) request.getAttribute(valueBean.telephoneText);

5.4 ActionForm支持
5.4.1 map-backed ActionForms

         在ActionForm中可以这样调用方法来获取Map中的记录:

         public void setValue(String key, Object value)

public Object getValue(String key)

在JSP中:

<html:text property="value(key)"/>

<bean:write name="formBean" property="value(key)"/>

5.4.2 DynaActionForm

         使用DynaActionForm,可以通过Struts的配置文件指定JavaBean的properties。

5.5 ActionForm的疑问
5.5.1 为什么ActionForm不直接就是一个Map?
5.5.2 为什么ActionForm不设计成普通的JavaBean?
5.5.3 为什么ActionForm不设计成接口?
5.6 对ActionForms的反思
5.6.1 实现一个业务层的接口
5.6.2 嵌套一个mutable的值对象
5.6.3 设置一个immutable的值对象
5.6.4 设置一个mutable的值对象
5.6.5 使用一个工厂方法
5.6.6 传递一个Map

         BeanUtils

5.6.7 通过反射传递值
5.6.8 使用适配器类
5.7 BaseForm

         这个类处理区域化,分派控制,管理自动计算等。

5.7.1 SessionLocale

         缺省情况下,ActionServlet会在每个用户的session对象中自动创建一个locale对象。SessionLocale相关的方法可以用来管理这个对象。

5.7.2 分派
5.7.3 自动计算值

         处理数据转换。可以在ActionForm和Bean之间转换,以及将ActionForm中的值转换成Map。

5.7.4 BaseMapForm

第六章   使用ActionForwards

6.1 ActionForwards做什么?

         理想情况下ActionForwads应该在程序的每一个入口被用到—任何链接到另外一个页面的地方。

6.2 ActionForwards如何工作?

         基类具有四个属性:name,path,redirect,className。

6.2.1 forward与redirect

n  Forward保存request中的所有内容和request上下文。

n  Redirect只是web客户端重新创建一个request。

转发Requests

Java Servlet容器具有一个内置的机制,使request可以传递给另一个组件,叫做转发。

重定向Requests

当ActionForward的redirect属性设置为true时,ActionServlet发送一个HTTP响应,高速浏览器重新提交一个请求给这个path。Request中的原始参数不会保留,request上下文会消失。

6.3 Global和Local Forwards

n  Global ActionForwads对应用程序中的所有Action都是可用的。

n  Local ActionForwards在ActionMapping中定义,只对从这个ActionMapping中调用的Action可用。

Global都应该定义成常量。Scaffold包中定义了一些常用的常量。

6.4 运行时参数

         有两个地方可以改变ActionForwad的查询组件。

6.4.1 在页面中增加参数

         可以在<html:link>标签中增加参数,例如:

         <html:link forward="article" paramId="key" paramProperty="key" name="articleForm">

<bean:write name="articleForm" property="name">

</html:link>

6.4.2 在Action中增加参数

         ConvertUtils提供了addParam方法。

6.5 动态的Forwards

         可以动态创建ActionForward对象,给它设定参数。

6.6 为什么地址栏不改变?

         要改变的话,只能redirect。

6.7 打造自己的ActionForward

         在Struts1.0中,要在web.xml文件中配置,在Struts1.1中,要配置Struts配置文件。

第七章   使用ActionMappings进行设计

7.1 进入ActionMappings
7.1.1 ActionMapping bean

         ActionMappings用来扩展Action对象而不是Action类。

7.1.2 ActionMappings目录

         ActionMappings代表了Struts应用的核心设计。

7.2      ActionMapping属性
7.2.1 path属性

         ActionMapping的虚拟引用。

7.2.2 forward属性

         如果forward属性被指定了,则request不会传递给Action,而是调用RequestDispather.forward。

7.2.3 include属性

         与forward同时使用。这两个属性与type属性是互斥的。

7.2.4 type属性

         一个Action类可以被多个actionMapping使用。

7.2.5 className属性

         指定自定义的ActionMapping子类的qualified名称。

7.2.6 name属性

         Form bean的逻辑名称。

7.2.7 roles属性

         一组逗号分隔的role列表,这些roles可以访问这个ActionMapping对象。

7.2.8 scope属性

         设置ActionForm的范围,缺省是session范围的。

7.2.9 validate属性

         如果validate设置为true,ActionServlet会调用ActionForm的validate方法,如果validate返回false,则request被转发到input指定的资源。

7.2.10 input属性

         Struts1.1中input属性可以指定为一个ActionForward的名称。如果要在input属性使用ActionForward,要为controller属性的inputForward设成true。

7.2.11 parameter属性

         ResourceUtils提供方法来加载一个properties文件。

7.2.12 attribute属性

         在同一个上下文环境中使用两份相同的ActionForm时,可以使用attribute属性命名另外一个。

7.2.13 prefix和suffix属性

         如同attribute,如果前缀是a,Formbean名为bean,则aBean=。。。和bean=。。。一样。

7.2.14 unkown ActionMapping

         处理404。

7.3 嵌套组件
7.3.1 Local Forwards

         先检查local forwards,再检查global forwards,如果都没有,则返回null。

7.3.2 Local exceptions

         可以为ActionMapping指定特定的ExceptionHandler。

7.4 打造自己的ActionMapping

         框架提供了两个基础的ActionMapping类,SessionActionMapping和RequestActionMapping。如果使用SessionActionMapping,则scope默认为session。

第八章   使用Action对象

8.1 准备,就绪,开始

         Actions是Struts框架中最灵活的类。

         Actions的核心职责:

n  访问业务层

n  为表示层准备业务对象

n  处理两个层之间出现的数据错误

8.2 使用Action对象
8.2.1 Actions是什么?

         如同servlet一样,Action是多线程的,一个Action类只有一个对象在应用中被使用。

         Actions是线程安全的,如果要继承Action,在自己的Action类中不能在多个方法中共用属性,所有的值都要通过参数传递来保证线程安全。

8.2.2 Actions什么时候被调用?

         当需要Action时,ActionServlet会通过Action的perform或execute方法来调用。

8.2.3 Actions做什么?

         一个典型的Action的通用职责:

n  验证先决条件或断言

n  调用任何需要的业务层方法

n  检测任何处理错误

n  路由控制到合适的视图

避免把业务逻辑放在Action类中是很重要的。

Struts消息可以接受最多4个参数。

在Struts1.1中可以使用更灵活的消息标签:

<logic:messagesPresent>

<UL>

<html:messages id="error">

<LI><bean:write name="error"/></LI>

</html:messages>

</UL>

</logic:messagesPresent>

在Struts1.1中消息和error可以分别传递,以使用不同的样式,使用方法同error:

saveMessages

ActionMessage

8.2.4 Action是什么样子?
8.3 标准的Actions
8.3.1 标准的bridge Action类

         用来集成Struts和应用程序中的其他Servlets。

         ForwardAction

         ForwardAction只是简单地把控制转发给其他资源,可以是任意具有URI的资源。

         IncludeAction

         当指定的servlet完成后,可以返回控制。

8.3.2 标准的base Action类

         BaseAction(Scaffold)

         DispatchAction

         LookupDispatchAction

         SwitchAction

                  SwitchAction可以切换到另外一个模块,并把控制转发到那个模块的path。

8.4 Chaining Actions
8.4.1 Starting fresh
8.5 Scaffold Actions

         所有的标准的Scaffold Actions都继承自BaseAction。

8.5.1 Forward-only Actions

         这样的Action类只是一个简单的dispatcher。

         SuccessAction

         RelayAction

适应于同一个页面有多个Submit按钮,而且使用不同的ActionMapping的情况,使用的时候要在页面设置一个参数。

         ParameterAction

                   转发的时候还传递参数。

         FindForwardAction

8.5.2 Helper Actions

         BaseHelperAction

         ProcessAction

         ExistsAttributeAction

         RemoveAttributeAction

8.6 Base View Actions

         Struts框架支持Action创建response。你可以创建自己的View Action来产生动态图片,创建PDFs,使用XSL样式表合并XML等。

8.7 Helper Action技术
8.7.1 可选转发技术

         首先检查特定的ActionForward存在,如果不存在,则忽略可选的行为。

8.7.2 Calling ahead
8.7.3 捕获chained异常
8.7.4 灵巧的错误转发
8.7.5 确认success

         ProcessResult类。

8.7.6 切换视图
8.7.7 反射方法
8.7.8 反射类
8.8 使用灵巧的转发

第九章   扩展ActionServlet

9.1 Where is the beef?

         大多数情况下,ActionServlet不需要被继承,直接使用应该可以满足需求。

         ActionServlet的扩展点都是通过plugin的,而不是继承。

9.1.1 Servlet的三人帮

         在所有的可插入的(Pluggable)组件中,RequestProcessor组件是最强大的。

         RequestProcessor处理的一个高层问题是异常处理,Exception类可以注册一个Handler如果是没有注册的Exception,RequestProcessor使用ExceptionHandler处理。

         很多应用程序需要访问自己特殊的资源,为方便在Struts中初始化自定义的资源,可以向Controller注册一个PlugIn Action。控制器会在启动的时候调用这个Action的init方法,关闭的时候调用这个Action的destroy方法。

9.2 RequestProcessor

         当一个request进来的时候,servlet选择应用程序模块,并把request交给RequestProcessor,每一个模块都可以加载自己的RequestProcessor的子类,或者直接使用RequestProcessor。

         RequestProcessor提供了一些可以重写的方法,用来扩展RequestProcessor。

9.2.1 process方法

         可以扩展的方法都是在process方法中调用的,process方法的职责是处理HttpServletRequest和产生相应的HttpServletResponse。

         为创建响应,典型的,processActionForward方法会将request发送给JSP页面或其他资源。

9.2.2 processRoles方法

         RequestProcessor的扩展点中,最有可能被完全重写的方法就是processRoles。processRoles的职责就是检查用户是否被允许访问Action。缺省的行为是使用标准的Java Security API。

         缺省的行为是,通过request的参数,用ActionMapping中指定的role列表和IsUserInRole方法,如果用户属于指定的roles,则验证通过。

         通过重写processRoles,可以容易地将此特性适应于合适的基于应用程序的安全模式。

9.3 ExceptionHandler

         ActionServlet会捕获所有异常,如果捕获了一个异常,它首先检查你是否已经为这个异常注册了handler,先检查local的,再检查global的。

         如果ActionServlet没有找到handler,将重新抛出这个异常。

         ExceptionHandler可以在Struts配置文件中注册,如果<exception>元素的path属性没有指定,则使用ActionMapping的input属性。
         <exception>元素的属性包含handler和className,可以用来指定自定义的ExceptionHandler,也可以为这个handler指定一个自定义的配置bean。
         自定义的handler必需继承自缺省的ExceptionHandler。入口方法是execute。

         ExceptionConfig bean表示从Struts配置文件中读取的原始的<exception>元素。如果需要其他属性,可以继承ExceptionConfig类,在配置文件中通过<set-property>初始化属性。

9.4 PlugIn

         允许一个Action实现PlugIn接口的init和destroy方法。

第二部分 构建自己的页面

第十章   显示动态内容

10.1 Tag-you’re it

         Struts发布版本包含了一组预先写好的JSP标签,可以把Struts框架和JSP标签结合起来。

         JSTL。

10.1.1 JSP标签有什么好处?

服务器端页面

有很多服务器端页面:ActionServer Pages,ColdFusion Pages,PHP,Velocity模板,JSP等。

10.1.2 Struts与JSTL

         JSTL的实现有很多与Struts标签库重叠的地方。JSTL需要容器支持Servlet2.3和JSP1.2,如Tomcat 4,Resin 2。

         JSTL并没有消除自定义标签扩展的需求。

         JSTL表达式语言

         JSTL提供的表达式语言(EL)来替换scriplets。

10.1.3 Struts标签与MVC

         Struts标签提供了所有应用程序需要的来创建MVC式的表示层的所有功能。

10.2 使用标签扩展
10.2.1 怎样书写标签扩展?

         JSP标签是用Java语言使用标签扩展API书写的。这些类解析XML格式的tag,使用tag的属性作为类的方法的参数。

         与JSP的base标签相对应,有一个BaseTag类,BaseTag类扩展了一个API类,BaseSupport,重写了doStartTag方法。

10.2.2 如何安装标签扩展?

1. 安装JAR和TLD文件。

2. 更新web.xml文件。

3. 在页面中引入新的taglib文件。

10.2.3 标签扩展不是什么?

n  标签扩展不能被所有HTML可视化编辑器支持

n  不是所有的scriptlet都能被的标签扩展替换

n  标签扩展不是JavaServer Faces

10.3 Struts标签库

         Struts发布版本包含4个关键的标签库:bean,html,logic和nesting。html中几乎所有的标签都依赖于Struts框架,其他三个库中几乎所有的标签都不依赖于Struts框架。

10.3.1 Struts标签的共同特性

自动定位范围

在寻找对象的时候,Struts标签会自动检查标准上下文—page,request,session和application,使用找到的第一个实例。

共同属性名称

         id,name,property,scope

扩展的语法

         嵌套引用,如:foo.bar.baz

运行时表达式

         标签的属性中可以使用scriptlet。

同用的错误处理

10.3.2 bean标签

         11个bean标签(cookie,define,header,include,message,page,parameter,resource,size,struts,write)可以用来:

n  从HTTP头、request参数,cookie,或者任何范围内存在的对象创建脚本变量

n  从response向另外一个request创建一个新的bean,从应用程序资源或Struts配置对象

n  确定一个Collection或Map的大小

n  自动地从应用程序资源文件为当前用户创建区域或消息

n  书写任何可用的bean的属性

只有message和struts依赖于Struts框架,其他标签可以应用于任何应用程序。

Bean标签最佳实践

最常用的标签<bean:write>和<bean:message>。

10.3.3 html标签

Html标签和scriplet版本的区别:

n  Scriplet要求bean要在jsp中先定义后使用,html标签没有这个要求。

n  缺省情况下,Struts标签在整个form中使用,不需要为每一个控件指定。

共同属性

name:ActionForm或JavaBean的名称

on*:事件处理

accessKey:按下赋给元素的accessKey使元素获得焦点

tabindex

style

StyleClass

10.3.4 logic标签

包含三个逻辑标签:evaluation标签,控制流标签,和重复标签。

Evaluation标签—共同属性

Cookie,header,parameter,name,property

控制流标签

在index.jsp中可以使用:

<%@ taglib uri="/tags/struts-logic" prefix="logic" %>

<logic:forward name="welcome"/>

Repeat标签

<logic:iterate>

10.4 使用Struts的JSP标签
10.4.1 Struts标签团队

         各类标签库联合使用可以达到一些效果。

10.4.2 基础

声明一个Form

<html:form></html:form>

产生html控件元素

使用ActionForm bean的property。

选择radio按钮

         Property相同,value设置好,如果ActionForm与html:radio的property值相同的property的value相同,则checked。

过滤HTML

<bean:write>标签自动过滤特殊字符,如果要取消,则把filter属性设置成false。

清除密码

Redisplay属性设置成false,则密码一直以空的形式出现。

使用事务性标志

解决重复提交问题。

<html:form>自动使用同步标志,在Action端可以通过调用saveToken(request)。

对options使用集合

         从Struts1.1开始,可以使用LabelValueBean。

对checkbox使用数组

         Mutibox控件。

区域化labels

         <bean:message>

区域化options

区域化集合

10.4.3 技巧

使用ImageButtonBean表示ImageButton

使用bean标签创建自定义控件

使用数组捕获重复的参数

使用<bean:size>测试集合的大小

迭代集合的一部分

暴露迭代的下标

使用嵌套的<present>和<notEmpty>测试bean属性

为稳定的option list使用application范围的对象

使用rewrite为样式表,javascripts和其他资产产生URLs

使用JSP标签产生JavaScript

         大部分web开发者都依赖于javascript来创建表示层的核心特性,Struts开发者也不例外。

使用<bean:write>从bean产生javascript

重命名submit按钮来避免javascript冲突

使用无form按钮

使用action作为input属性来重新创建依赖的对象

使用动态的form Actions

使用可选择的message标签

         <logic:messagesPresent>

<UL>

<html:messages id="error">

<LI><bean:write name="error"/></LI>

</html:messages>

</UL>

</logic:messagesPresent>

可以指定某个消息显示在某个控件的旁边。

10.4.4 成功的控制
10.5 可选的视图
10.5.1 Struts与JSP

         Struts本身并不处理JSP,而是容器负责处理。

10.5.2 Servlet上下文

         三个标准的上下文:request,session,application。

10.5.3 超越JSP

         使用Struts可以扩展XSLT和Velocity。

第十一章            使用Tiles开发应用程序

11.1 调整布局

可用性是当今web应用设计的一个主要关注点,而一致性是可用性的一个主要成分。

11.1.1 使用动态模板分层

         将显示与内容分离的一个方法是使用动态的JSP include。JSP规范提供了静态和动态的include。动态include的标准JSP动作是<jsp:include>。

         我们利用动态include的方法是,把服务器端页面分解成多个片段(fragment),每一个片段负责自己的一部分工作。背景模板可以设置缺省格式和布局,可以在运行时包含include来显示内容。动态的include将被包含的页面的输出展开到原始页面。Tiles框架使用jsp动作的一种更高级的形式。在Tiles应用程序中,背景、布局、模板通常定义头部、菜单体、内容和尾部的位置。其他页面被包含进来来填充这些位置。如果头部变化,只需要改变模板文件,这个变化会自动地体现在包含模板的页面。HTML的标准组件,如CSS,可以很好地与动态模板工作。

11.1.2 模板的效果

         每一项技术都有一些折衷,使用模板的效果如下:

n  JSP包含技术已经是良好建立而且可靠,趋向于在大型应用里也表现良好。包含动态模板的技术是核心Java Servlet API的一部分。

n  大部分的容器都为JSP和象servlet include这样特性做了优化。

n  被包含的页面通常输出HTML片段,不能用标准的HTML编辑器维护。

n  大部分的站点都在源代码变化的时候重新编译JSP。模板创建了更多的页面,也创建了更多的变化的可能性。

n  模板实际上重用了代码。

11.1.3 使用模板

         一些术语:

         动态元素(Dynamic element):JSP翻译器识别出的JSP的一部分,包括action,directive,expression,JSP标签或者scriplet。

         模板数据(Template data):没有被JSP翻译器识别出的JSP的一部分,通常是标记和可见的文本。

         模板页(Template page):一个包含另一个页,或被另一个页包含的JSP。

         模板文件(Template file):被一个模板页面包含的静态文件或JSP。

         Tile:Template file的缩写。

         Layout:关于Tiles如何定位于页面的描述。

         Tiles:一个使模板和布局更容易和更强大的框架。

         定义(Definition):一个Tiles特性,它允许一个布局被指定为一个模板页或JavaBean。定义可以用XML文档来描述。

11.1.4 结合模板,Tiles和Struts

         Tiles框架通过使用简单有效的标签库使模板布局的使用更加简单。

         通常情况下,一个JSP模板系统使用一个模板文件作为布局,另一个模板文件作为填充组件。

11.2 构建一个布局模板

         构建任何一个布局的第一步是识别组件的组成部分。对于一个经典的web页面,组成部分有header,menu,body,footer。创建一个这样布局的模板页很简单:

1.       打开一个新的JSP页面。

2.       引入Tiles标签库。

3.       创建一个HTML表格,使其cells与模板页的骨架匹配。

4.       使用一个Tiles JSP标签(<tiles:insert>)为布局的每一个部分命名。

我们每创建一个cell来放置布局组件,我们都放置一个JSP标签(<tiles:insert attribute=”aName”>。这使我们能够不断地使用这样的布局,每一次只要为tiles传递不同的路径即可。

我们的经典布局可以构造成一个完整的独立的模板页,只要再加上HTML标记的其余部分。

11.2.1 说了半天,到底什么是tile?

         严格地说,tile是JSP页面的一个矩形区域。

         Tile对象支持一些重要的特性,如参数和定义。

         参数

         Tile可以在运行时通过参数或属性的形式接受变量信息。Tiles参数通常叫做属性(Attributes),以区别於request的参数。Tile属性在插入tile时定义,而且只对这个tile可见。Tile的attributes可以是字符串或其他类型。

         定义

         定义存储一组attributes,使一个屏幕描述成为一个拥有唯一表示的可辩别的对象。声明一个基类屏幕定义,然后派生这个基类屏幕定义以创建其他屏幕定义。

11.2.2 部署一个Tiles模板

         <tiles:insert>

                   <tiles:put/>

         </tiles:insert>

11.2.3 增加样式表

         使用<html:base>与<html:rewrite>。

11.2.4 模板与MVC

         可以重构既存系统得到一个MVC模板系统。

11.3 Tiles定义
11.3.1 声明定义

         一个定义需要如下信息:

n  基础模板文件的路径

n  传递给模板的0个或多个属性列表

n  定义的一个标识符

仅通过向特性列表中增加identity,会增加一些功能:

n  可以在部署的时候通过额外的或替换的属性来重载定义。

n  可以扩展定义,把一个定义作为另一个的基础。

n  可以重用定义,把定义存储在JSP中或从XML文档加载。

n  定义可以是Struts ActionForward的目标。

11.3.2 JSP声明

         用JSP中使用Tiles定义的过程包括:

n  用JSP声明一个定义

n  部署JSP声明的定义

n  重载定义

n  使用JSPs重用定义

11.3.3 配置文件声明

         每一个定义通过name属性标识。

11.4 Tiles属性

         Tiles存储它的属性在自己的上下文中。

11.4.1 useAttribute

         <tiles:useAttribute name="myAttribute" />或

         <tiles:useAttribute attributeName="anAttribute" name="myAttribute" />

         这样声明之后,可以这样使用:

         <bean:write name="myAttribute" />

11.4.2 importAttribute

         <tiles:importAttribute>将所有tiles属性导入到page上下文。

11.4.3 put

         <tiles:put>将一个值与一个tiles属性关联。

11.4.4 putList与add

         Tiles的属性可以是java.util.List类型。

11.5 将应用程序移植到Tiles

         将应用程序移植到Tiles与重构的“抽取方法”相似。

11.5.1 安装Tiles框架

         首先,备份所有东西。

         Tiles与Struts1.1集成在一起的。

11.5.2 测试缺省配置

         将web.xml文件中debug和detail参数设置成2。查看所有的错误信息。

11.5.3 审查页面

         识别布局。

         识别Tiles

         命名候选组件

11.5.4 使用<tiles:insert>重构页面
11.5.5 抽取<tiles:insert>到定义
11.5.6 规范基础布局
11.5.7 将定义细化到基类和扩展类
11.5.8 开发一个规程

         经过几个页面的重构,应该可以开发一个规程。前几个页面是根据应用程序的流程,到后来就可以根据规程one by one进行重构。

11.5.9 管理移植

第十二章            验证用户输入

12.1 见文知意

         一个健壮的应用程序检查所有的输入,守卫所有可预见的错误。

12.1.1 不能拒绝输入

         缺省情况下,HTML元素接受用户输入的所有内容。可以使用javascript来控制,但是用户可以关闭javascript功能。使用业务层验证数据不合适,特别是对于分布式系统,业务对象可能在远程,使用业务对象来验证成本比较高。

12.1.2 web层验证

         在一个无模型的、分布式环境下,我们需要验证规程做如下事情:

n  要求一些字段必需有值

n  确认给定的值属于预期的模式或范围

n  一次性检查整个form并返回一个message列表

n  比较多个字段的值

n  返回原始的输入用来纠正

n  当需要显示消息时,显示区域化的消息

n  如果javascript被禁用,要执行服务器端的验证

n  松散耦合:验证的规则应该和标记语言或java语言分离。

n  客户端验证:客户端验证是不安全的。虽然不能依赖于客户端验证,但客户端验证仍然是很有用的,因为可以使用户获得即时的反馈。

12.1.3 验证器的效果

         使用Jakarta Commons Validator的效果有:

n  验证器是一个框架组件,可以满足上一节提到的需求。

n  验证器通过XML文件配置,来对form的输入域产生验证规则。

n  验证器定义的规则也是通过XML文件配置。

n  提供了对于基本类型的验证器,如果需要可以创建自己的验证器。

n  正则表达式可以提供基于模式的验证,如邮编和电话号码。

n  支持多页面的和区域化的验证。

使用Jakarta Commons Validator有以下好处:

n  优化资源的使用:提供Javascript验证,只要用户没有禁用,服务器端验证是得到保证的。

n  单点维护:服务器端和客户端验证通过同一个配置产生。

n  可扩展性:自定义验证可以定义为正则表达式或者java代码。

n  可维护性:单独维护,与标记语言或java代码松散耦合。

n  区域化:提供区域化验证。

n  与Struts集成:缺省情况下,验证与Struts共享信息资源文件。

n  服务器端验证部署容易:只要使自己的ActionForm从ValidatorForm或ValidatorActionForm继承。

n  客户端验证部署容易:只要加上一个JSP标签来产生验证脚本和使用这个脚本来提交form。

n  易配置:验证器使用XML文件配置,如同web部署描述子和Struts配置文件一样。

也有一些缺点:

n  无模型的客户端验证:产生的javascript是无模型的。

n  依赖性:页面标记、ActionForm及验证器和Struts配置文件要保持一致。

n  缺乏数据转换:包不提供数据转换。

12.2 Struts验证器总览

         组成Struts验证器的各部分:

         Validators:处理基本的和其他公共的类型。基本的验证包括:required,mask(匹配正则表达式),miniLength,maxLength,基本类型,date,email和creditCard。也可以定义自定义验证器。

         Resource bundle:默认情况下共享Struts的消息。

         XML配置文件:定义form集合和字段的验证。

         JSP标签:为给定的form名或acion路径产生javascript验证。

         ValidatorForm:根据form bean的name自动验证属性。

         ValidatorActionForm:根据Action路径自动验证。

         验证器提供了一些基本的验证,如果满足不了可以打造自己的验证器并插入到包中。应用程序需要的验证器可以在xml文件中配置,通常叫做alidation.xml,验证规则也可以单独放在一个文件中,通常叫做validator-rules.xml。

         Validator-rules文件有一个<form>元素,与Struts的<form-bean>对应,<form>元素有<field>子元素。每一个<field>可以指定它必需通过一个或多个验证器才能成功。如果验证失败,可以返回资源文件的key,可以带参数。如果使用客户端验证,可以在javascript window显示相同的消息。

         为使服务器端验证可用,只需从验证器的基类扩展自己的ActionForm,

12.2.1 Logon实例

Validator-rules.xml

Validator.xml

JSP标签/login.jsp

Validate方法

         要继承ValidatorForm,并移除validate方法。

12.3 基本的验证器

         Struts验证器提供了14种基本的验证器。

         required:

         mask:要验证的字段满足一个mask属性指定的正则表达式。

         range:

         maxLength:

         minLength:

         byte,short,integr,long,float,double

         date:

         creditCard:

         email:

12.4 Resource Bundle
12.4.1 缺省的bundle

         Struts Bundle通过部署描述子来配置。

12.4.2 缺省的验证器消息

         规范是在验证器的name前加errors.前缀,如果required验证器的缺省消息是errors.required。

         # Struts Validator Basic Error Messages

errors.required={0} is required.

errors.minlength={0} cannot be less than {1} characters.

errors.maxlength={0} cannot be greater than {1} characters.

errors.invalid={0} is invalid.

errors.byte={0} must be a byte.

errors.short={0} must be a short.

errors.integer={0} must be an integer.

errors.long={0} must be a long.

errors.float={0} must be a float.

errors.double={0} must be a double.

errors.date={0} is not a date.

errors.range={0} is not in the range {1} through {2}.

errors.creditcard={0} is not a valid credit card number.

errors.email={0} is not a valid e-mail address.

12.4.3 自定义验证器消息
12.5 配置文件

         在Struts1.1中,验证器配置文件的路径在Struts配置文件中指定。

12.6 验证器JSP标签

         <logic:messagePresent>

         <logic:messages>

12.7 ValidatorForm和ValidatorActionForm

         可以先用验证框架验证,再用自己的验证。

12.8 区域化验证

         Validator配置文件包含一个formset元素,formset是一个拥有同一个区域设置的forms的集合。

12.9 可插入的验证器(Pluggable Validator)
12.9.1 创建一个可插入的验证器

         两步:

n  在一个Java类中创建一个方法来处理服务器端验证。

n  为验证器更新validator-rules.xml。如果验证器有客户端验证,将javascript作为rules的一部分。

12.10 技巧
12.10.1 多页验证

         很多开发者喜欢使用向导式表单。一些开发者为每一个使用一个不同的表单,还有一些开发者为这些页使用同一个表单,每次只显示表单的一部分。

         对于使用一个大表单的形式,Struts验证器提供了page属性。

12.10.2 取消按钮

         Struts验证器提供了一个bCancel Javascript变量。

12.10.3 自定义消息

         使用mask验证要提供自定义消息,以显示更具体的提示消息。

12.10.4 关联的字段

         通过定义自己的plug-in验证器。

12.10.5 结合验证器和validate方法

         使用plug-in验证器,最好是这个验证器能够被重用,否则重写validate方法即可。重写的时候要确保调用了父类的validate方法以调用Struts框架的验证器。

12.11 将应用程序移植到Struts验证器
12.11.1 安装验证器框架
12.11.2 测试缺省配置

         将web.xml文件中的debug和detail设置为2级,看看有没有错误消息。

12.11.3 审查验证

         审查validate方法,确定哪些可以有验证框架实现,哪些由自定义验证实现。

12.11.4 扩展ValidatorForm或者Scaffold BaseForm

         确保ActionForm从这两个类中的一个继承。

12.11.5 选择一个验证进行移植
12.11.6 添加formset,form和field元素
12.11.7 在ApplicationResources中添加新的记录
12.11.8 调用Struts验证器

         调用父类ValidatorForm进行验证。

12.11.9 测试和重复进行
12.11.10 移除ActionForm子类

         如果validate方法只调用了父类的方法,可以将form-bean中的ActionForm换成父类。

第十三章            区域化内容

13.1 By any other name

         Struts框架让开发者在单独的文件中定义标签和消息,称作Resource Bundle(java.util.ResourceBundle)。Resource Bundle是Java国际化特性的一部分。Struts框架也是完全支持国际化的。

         Internationalization有时缩写为i18n,因为在第一个字母i和最后一个字母n之间有18个字母。

         Struts在Java平台的标准特性的基础上构建国际化特性。

13.1.1 为什么要区域化?

         除了语言,日期、通货、图像都需要区域化。

13.1.2 Java国际化的工作原理

为实现国际化,应用程序应该能够:

n  区分不同的区域。

n  使用相同的可执行程序为不同的区域显示合适的标签和消息。

n  对新的区域提供支持,而不需要修改可执行程序。

n  自动格式化对区域敏感的元素,如日期、通货等,使其适合于给定的区域和语言。

Java通过三个关键类来满足对国际化的支持:Locale,ResourceBundle和MessageFormat。

         Locale

         Java对国际化支持的绝对核心是Locale对象(java.util.Locale)。这个简单的对象使你可以组合语言、国家和可选的变量进入单个Locale实体。语言和国家由ISO标准定义(ISO-3166,ISO-639)。例如:

         语言代码         描述                   国家代码         描述

         de                       德语                   CN                      中国

         es                        西班牙语         CA                       加拿大

         en                       英语                   DE                       德国

         fr                         法语                   FR                       法国

         ja                         日语                   IN                        印度

         jw                        爪哇语              US                       美利坚合众国

         ko                        韩语                  

         zh                        汉语

        

         可选的变量通常用来表示方言,但是可以是任何对应用程序有用的代码。Struts框架没有使用variant字段。

         为创建Locale对象,向构造函数传递语言和国家的代码,如说法语的加拿大人的locale对象可以这样创建:

         locale = new Locale(“fr”,”CA”);

         通常Locale对象会传递给工具方法,这个工具方法基于Locale对象的设置来格式化输出。

         ResourceBundle

         为支持另外一种Locale,只要为这个Locale在bundle中增加一个资源文件。

         ResourceBundle是一个抽象类,有两个基本的实现:ListResourceBundle和PropertyResourceBundle。

         PropertyResourceBundle类用来处理一组文本消息,在大多数Struts应用中都使用它。消息可以从一个properties文件中加载,通常通过调用一个静态方法:

         message = ResourceBundle.getBundle(“application”,locale);

         如果找不到请求的locale,则使用默认的bundle。

         ListResourceBundle用来加载非String的对象。

         MessageFormat

         MessageFormat用来在运行时合并消息模板和可替换的参数。

13.2 Struts国际化组件
13.2.1 Session的Locale属性

         所有标准的Java国际化的工具都是依赖于Locale对象,所以国际化的基础就是为每一个用户维护一个Locale对象。

         缺省情况下,Struts会为每一个用户在他的session上下文环境中使用已知的key存储一个Locale属性。初识时,这个属性设置为服务器端的缺省区域。

13.2.2 MessageResources

         Struts提供了MessageResources类来获取消息。Struts开发者很少直接调用这个对象,而是通过其他类来返回合适的消息。

         MessageResource的缺省实现是使用PropertyResourceBundle,但是其他实现可以使用XML文件或者SQL数据库。

         典型地,消息通过JSP标签或其他表示层系统来获取。Action也可以通过调用MessageResources来准备区域化的消息。例如:

         Locale locale = (Locale) session.getAttribute(Action.LOCALE_KEY);

MessageResources messages = servlet.getResources();

String message = getMessage(locale,"important.message");

((messageForm) form).setMessage(message);

getMessage被重载了,它可以接受最多四个参数。

13.2.3 缺省的resource bundle

         每一个资源都是在第一次使用的时候从磁盘加载,然后在应用程序的声明周期内一直保留在内存中。

         格式化消息

         由于使用标准的Java库,格式化数字、日期、通货的通用技术可以与Struts消息结合使用。

         显示特殊字符

         Java编译器和其他Java工具只能处理Latin-1(ISO 8859-1)或Unicode编码的字符。为帮助转换不使用Latin-1系列字符的文件,JDK提供了一个工具native2ascii。

         也可以使用Java Internationalization and Localization Toolkit 2.0来做同样的事情。这个工具包包含了很多对大规模翻译文件很有用的工具。

13.2.4 ActionErrors

         每一个message都可以与form上的一个属性关联,这使开发者可以在属性的附近显示消息。

13.2.5 ActionMessages

         ActionMessage标签提供了额外的功能,使开发者不用将标记语言与消息混在一起。

13.2.6 Locale-Sensitive JSP标签

         Struts标签库包含了一些lcoale-sensitive标签:

         bean:message

         bean:write

         html:errors

         html:html

         html:img

         html:image

         html:messages

         html:option

         html:button

         html:cancel

         html:checkbox

         html:file

         html:hidden

         html:mutibox

         html:password

         html:radio

         html:select

         html:submit

         html:text

         html:textarea

         html:form

         html:link

         图像相关的标签提供额外的key属性来提供图像和文本的双重区域化。

         Locale-sensitive标签的通用属性:

         arg0,arg1,arg2,arg4:参数化替换值。[message write]

         bundle:应用程序范围的bean的名称,在这个bean下,包含我们消息的MessageResources存储其中。[message image img write option errors messages]

         key:被请求的消息的消息key在消息资源中必需有一个对应的值。[message write image img option]

         locale:session范围的bean的名称,存储着当前选择的locale对象。

         altKey,titleKey:alt或title文本。[button cancel file hidden image img multibox password radio reset select submit text textarea]

         titleKey:没有alt。[form link]

         pageKey,srcKey:指定图像的的消息资源的key。可以是应用程序相对路径或者URL。[image img]

         formatKey:提供一个格式化字符串的key,从资源总获取消息。[write]

         <bean:message>

         更多地应用于HTML表单中。

         <bean:write>

         具有formatKey属性,可以从resource bundle中读取消息的模板。

         具有locale属性,只是session范围内的bean的名称。

         <html:errors>和<html:messages>

         自动为用户的locale从资源bundle中打印消息。

         <html:html>

         根据用户的locale对象,产生不同的结果,如

         <html:html>à<html lang=”en”>或者

         <html:html>à<html lang=”fr”>

         <html:image>和<html:img>

         在区域化image或image button的时候要考虑三点:

n  二进制图像文件的的源

n  Image的alternate文本

n  元素的advisory title

<html:option>

对text属性,可以指定一个key。

其他属性

bundle,locale

13.3 区域化Struts应用程序
13.3.1 使区域化可用

         有三点:

n  Servlet的locale参数是否设置正确

n  缺省的application resource bundle参数是否设置正确

n  区域化的JSP页面是否使用了<html:html>

设置locale servlet参数

         缺省情况下Struts对每一个用户自动创建一个缺省的local对象,是否会自动创建取决于是否在web.xml文件中设置了ActionServlet的locale参数。

设置应用程序资源servlet参数

         设置ActionServlet的application参数。

13.3.2 使用框架Locale对象

         检查用户的Locale

         Locale locale = request.getSession().getAttribute(Action.LOCALE_KEY);

         如果Action继承自BaseAction,可以直接使用:

         Locale locale = getLocale(request);

         改变用户的Locale

         Locale对象是不可变的(immutable),必需使用一个新对象来替换。

         Locale locale = new Locale(myForm.getLanguage(),myForm.getCountry());

         HttpSession session = request.getSession(true);

         Session.setAttribute(Action.LOCALE_KEY);

         如果Action继承自Scaffold包的BaseAction,则可以使用:

         Locale locale = new Locale(myForm.getLanguage(),myForm.getCountry());

         setLocale(request,locale);

         如果应用程序只对语言区域化,则国家参数可以传递一个空串。

         使用Struts的locale-sensitive组件

         Struts组件会自动获取区域化消息。

13.3.3 在Properties文件中放置标签和消息

         Properties文件中放置key-value对。

13.3.4 创建特定语言的Properties文件

         为每一种locale创建一个文件。

13.3.5 在区域化组件中指定合适的key

         通过key获取locale的标签与消息。

13.3.6 与其他组件结合使用<bean:message>

         对于不提供内置区域化的组件,可以使用<bean:message>来提供区域化的消息。

13.4 区域化其他组件
13.4.1 区域化Struts验证器

         如果需要额外的区域化验证,例如,对邮编或电话号码进行验证,特定区域的form-set元素。

13.4.2 区域化Tiles

         可以为每一个区域创建区域化的tiles配置文件。

13.4.3 区域化集合

         <html:options>

         MessageUtils

         <html:mutibox>

         MessageUtils.getLabelValueBean()

第十四章            在Struts中使用数据服务

14.1 Stepping Out
14.1.1 从模式的视角来看JDBC

         从模式的视角,JDBC驱动是集成层的一部分,而实际的数据库存活在资源层。

         对于开发者来说,驱动和数据库之间的交换是透明的。

         隐藏业务层

         JDBC驱动使用的driver:device或者说是façade模式,是一种你可以在集成任何数据服务时使用的策略。

         设计的目标是提供一个接口(或驱动),应用程序可以使用这个接口而无需知道隐藏在接口后面的数据服务。

14.1.2 引入数据服务

         通过一个实例。

         首先,使用Scaffold包中的StatementUtils和ResultSetUtils类连接JDBC数据库服务。这一步很简单,基准策略是使用反射和元数据将SQL ResultSet转换成JavaBeans。

         接下来,我们走出数据库黑盒,与Lucene连接起来。

         最后,我们表明向应用程序增加服务,如RSS,是多么的容易。

14.2 探索业务层
14.2.1 Struts—引入自己的模型

         业务逻辑bean,即业务对象。

14.2.2 定义业务对象

         为定义业务对象,必需首先隔离核心业务逻辑。

14.2.3 设计业务对象

         理想情况下,业务方法应该只接受和返回通常的Java类型,只抛出自己的一组异常。因此,业务逻辑bean应该:

n  代表程序的核心逻辑—它的API

n  可能的情况下,只接受和返回Java基础类型和类

n  定义自己的异常类

n  对其他类暴露最小的依赖

业务逻辑对象不必遵守JavaBean的规范,但是遵守规范可以花费很少,取得甚多。

为什么要抛出自己的异常?首先,为提供封装。其次,为提供控制。

14.2.4 设计效果

n  降低耦合,提高可维护性

n  引入附加层

n  提供简单统一的接口

n  可能会隐藏低效

14.2.5 将业务对象与Action混合

         如果不使用业务层,会有一些Struts特定的结果:

n  直接在Action中书写业务逻辑,随着程序规模的增长,会变得难以扩展和维护。

n  在Action中实现的逻辑很难在Struts框架就以外使用,或者适当地使用测试工具,如JUnit。

n  数据访问、错误处理和其他资源层代码可能会在Actions之间重复,只能通过复制粘帖来复用。

n  关键元素,如SQL命令会被隐藏起来很难审查。

n  Actions会变成应用程序接口,促使开发者在Actions之间转发请求。

n  当Actions变成API时,需要新的机制,要么是中间查询串,或者用Action检查请求中间的信号量对象。

n  Actions会变得复杂,要从其他客户端和其他Action处理业务逻辑请求。

n  代码会变成意大利面条。

14.2.6 一个简单的例子

看一看Artimus示例应用程序的业务逻辑API。

Artimus—初始业务需求

n  存储一篇文章的标题、作者和内容

n  以降序方式列出最新的文章(从新到旧)

n  通过标题、作者、内容或其他属性来过滤和列出文章

Artimus—初始API

insert

searchLast

searchTitle

14.3 在Struts中使用ProcessBeans和JDBC

         有一些产品提供JavaBean和关系数据库的ORM(Object-Relational Mapping)。ProcessBeans使用了很多这样的技术:

n  封装应用程序的功能性逻辑

n  表示交易的状态,如购物车

n  避免使用web层的类

n  提供execute触发方法,来引入具体行为

此外,一个ProcessBean:

n  使用bulk setter从其他javabean产生自身

n  使用bulk populator向其他javabean拷贝值

ProcessBeans不是ORM的一个实现。并非封装或隐藏SQL,ProcessBean包提供一个结构性的位置,在这里你的查询并得到一个JavaBeans的集合作为返回值。它还从其他beans自动产生你的model beans,并从尽快地将数据从SQL的ResultSet移动到你的JavaBeans。

14.3.1 引入ProcessBeans

         如同ActionForm,ProcessBeans不必是数据库表的直接表示。二者可能有交集,甚至很多属性通常一样,但这只是巧合,而非设计目标。

         更常见的是,ProcessBeans的属性是几个表的连接的列的集合,称作逻辑视图。

         ProcessBeans并不代表库表,而是代表数据库的逻辑视图。哪些属性属于逻辑视图,由业务API决定。

14.3.2 ProcessBeans作为传输对象

         因为ProcessBeans被用来将数据从一个层送往另一个层,可以把ProcessBeans看作是传输对象。一些传输对象是只读的,即immutable,这通常发生在EJB环境下,这种情况下,数据库是远程的,更新的代价很高。

14.3.3 产生ProcessBeans

         ProcessBean实际上是两个接口,定义了两个主要的签名:

         public Object execute() throws Exception;

         public Object execute(Object parameters) throws Exception;

         ProcessBeanBase类提供了execute(Object)方法的一个实现,利用反射来产生子类提供的任何属性。ProcessBeanBase使用了BeanUtils的方法。

14.3.4 执行ProcessBeans

         通常的策略是使用业务模型需要的属性创建一个基类bean。这个基类bean被模型需要的任何一个业务过程扩展。为产生bean的值,可以向execute(Object)传递所需的属性的Map。缺省的实现会产生任何匹配的属性,并触发exectue方法来完成工作。

         Execute方法返回一个对象,通常是ProcessResult对象。ProcessResult对象用来向其他层传输业务操作的结果。ProcessResult可以包含消息、数据或者二者都包含,而且包含可以用来自动处理结果的方法。

         如果业务操作返回数据,数据通常包含在一个ResultList对象中。这是一个集合,具有很多帮助方法供表示层页面方便地使用。ResultList被设计用来取代ResultSet,以便使用非连接的JavaBean。

14.3.5 访问数据服务

         Artimus的ProcessBeans使用一个静态类,Access,来从业务层连接资源层。这不是必需的,只是一个有用的规范。Access类代表着事实上的业务API。ProcessBeans代表着使用API的客户端。

         Access类扮演着数据访问对象的角色。如果需要使用多个实现,Access可以基于一个接口。Scaffold包提供了很多方便的工具来使用SQL语句和准备语句。Access类把合适的SQL语句和运行时bean传递的数据放在一起。

14.3.6 遵循一个典型的流程

n  ActionServlet产生一个ActionForm传递给Action的execute方法

n  Action创建、产生和执行适当的ProcessBean

n  如果发生错误,Action捕获异常,将控制路由到错误或输入页面

n  如果操作成功,Action刷新ActionForm,把ResultList对象传递给请求的上下文

14.3.7 编写一个业务活动的代码

         Struts配置文件中ActionMapping中的parameter属性,指定一个业务逻辑对象,Action会实例化这个对象。

14.3.8 把ProcessBeans用作持久层

         ProcessBeans和其他Scaffold对象形成一个持久层。

14.3.9 使用其他持久层

         Simpler,OJB,Castor,Osage

14.4 使用结果对象

         一旦取得了数据,还需要与表示层通信。可以使用标准的Vector和ArrayList,但一般使用特定的wrapper会更方便。

14.4.1 ResultList的方法

         就是一个wrapper的例子。ResultList类有几个方法特别有用。

         int getSize()

         String getLegend():取得result list的一个描述。

         Iterator getIterator():取得result list的一个迭代子。

14.5 使用其他帮助Actions

         Struts开发者的通常的策略是为几个相关联的操作使用一个Action。这样有助于复用代码和减少代码中的类。Scaffold包中的帮助Actions实现了一株框架Action,可以被应用程序中几乎所有的操作复用。

         帮助Action的策略是将一组业务对象与ActionMapping关联。业务对象被实例化,产生值并调用。Action集中于错误处理和流程控制。

         几个帮助Actions:

         BaseAction

         BaseHelperAction

         ProcessAction

14.6 使用Lucene

         数据库的具有很多局限性,特别是在搜索文本的时候:

         ANSI SQL文本搜索是区分大小写的。

         SQL匹配符将参数当作单个字符串。

         SQL查询只能通过一个字段的内容排序,匹配程度最高的不能被列在前面。

         大多数数据库系统没有对文本搜索做索引。效率可能不高。

         大多数数据库系统没有对布尔查询做优化,使用布尔查询的文本搜索可能会成为系统的瓶颈。

         数据库系统只能搜索存储在表中的数据。

         Lucene解决了以上所有的问题。

14.6.1 searchProperties

         引入Lucene

         Lucene既是一个搜索引擎,又是一个构造搜索引擎的工具。Lucene有五个关键对象。

         Document:

一个逻辑构造体,可能是数据库的一条记录,一个网站的页面或者是其他可以被重新取得的一条信息。

         Field:

                   Field是Document的一部分。每一个Field包含两个部分:name和value。

         Index:

         Query:

         Hits:

         典型的工作流程:

n  通过增加Fields创建Documents

n  创建一个IndexWriter,并使用addDocument的方法增加Document

n  调用QueryParser.parse方法从一个字符串构造一个查询

n  创建一个IndexSearcher,并将Query传递给它的search方法

n  将Hits生成一个list并返回给用户

 

Artimus是如何使用Lucene的?

创建索引。

n  使用IndexWriter创建一个Index

n  创建一个Document对象(2)

n  获取数据源

n  根据数据源向Document增加一个或多个Field

n  向Index增加Document对象(5)

n  对于每一个数据源重复2到5的操作

n  优化和关闭Index

14.7 使用内容聚合

策略很简单:

n  可用的内容综合在一个XML文件中

n  XML文件通过HTTP可用

其他站点可以:

n  获取或缓冲这个文件

n  将这个聚合内容传递给它自己的访问者

使用Struts Digester,创建和获取聚合内容非常简单。

14.7.1 Digesting RSS

         Struts使用Digester从Struts配置文件创建对象。

         一个RSS文件一个叫做channel的items的集合。每一个item具有几个属性,包含对这个item自己的链接,每一个属性通常是站点的某个地方。Channel通常将关联的items放在一起。

14.7.2 获取和产生

         从一个既存的XML文件创建一个Channel对象非常简单。只要传递一个path,剩下的事情交给RSSDigester就行了。

         创建自己的RSS文件也很容易。只要创建一个Channel对象,增加items,使用Writer产生结果就行了。

14.7.3 聚合RSS
14.8 在Struts中使用EJB

         EJB用来表示一个应用的Model层。当创建的应用会分布在多个服务器上时,开发者通常会选择EJB。很多开发者喜欢EJB因为它对事务处理的透明性。

14.8.1 Session Façade

         EJB的session bean组件用来实现Façade接口。

14.8.2 数据传输对象

         ActionForm也是一种DTO。只要是在层与层之间传输的对象都可以教DTO。

14.8.3 实现模式

n  如果需要,重新创建对远程接口的引用

n  优先使用无状态的session EJBs,而不是有状态的session EJBs

n  避免保持对无状态的session EJBs的句柄

n  避免直接与实体交互

n  使用无状态的façade来向Action返回DTO

第四部分 Struts使用实例

第十五章            Artimus:停车站

15.1 框架的框架
15.2 Scaffold—工具集的诞生

         如同Tiles和Validator,Scaffold是使用Struts创建Web应用的一个工具包。

15.3 关于Artimus

         Artimus是一个基于Web的新闻发布应用。授权的用户可以添加、删除、编辑文章。任何访问者可以在线查阅文章,可以使用各种搜索特性,包括通过作者、标题、时间段的全文检索。

         Artimus可以将它的文章发布成RSS Channel。

         Artimus是一个很好的使用Struts的例子,一些技术点:

n  应用程序的设置可以通过web.xml或其他属性文件配置。

n  在Struts1.0版本中,一个帮助Servlet用来加载自定义的资源而不需要从ActionServlet继承,而在Struts1.1中,使用PlugIn Action。

n  连接池适配器允许使用Struts连接池。连接池可以通过web.xml或PlugIn配置来改变。

n  SQL命令存储在外部属性文件中,不需重新编译就可以修改。

n  业务层由一组ProcessBeans表示,使用经典的Command模式来分发。

n  使用标准的Action来分发ProcessBeans,减少了应用程序中自定义Action的使用。

n  应用程序很容易区域化。

n  Tiles框架可以用来布局和组织显示页面。

n  Validator框架可以用来验证输入,服务器端和客户端都可以。

n  Lucene搜索引擎可以用来提供全文检索。

15.3.1 构建Artimus
15.4 部署描述子(web.xml)

         Artimus的web.xml除了包含Struts标准配置,还包含它自己的ArtimusServlet和Declarative Security配置。ArtimusServlet不是用来处理请求的运行时servlet,只是一个资源加载器,用来初始化我们的业务层的类。Declarative Security用来保护编辑命令,使未授权用户不能访问。

15.4.1 配置Artimus

         给Artimus servlet一个引用名称,指定供容器加载的类。

15.4.2 应用程序属性

       使用<default>指定一个应用程序使用的属性文件的路径,这个文件用来存储系统路径和其他一些不随locale改变的设置。

         例如,Lucene需要在服务器上存储一些文件,我们可以把路径存储在属性文件中,需要改变的时候只要修改这个属性文件,而无需重新编译代码。

15.4.3 连接适配器

         Artimus使用JDBC作为缺省的存储系统。

         使用<adaptor>和<adaptor.key>来配置连接适配器,以使用Struts的通用连接池。Struts在应用程序上下文中存储一个对其连接池的引用。因为这是一个通用的方法,Scaffold包提供了一个标准的ServletAdaptor。

15.4.4 启动优先级

         <load-on-startup>:设置成1,让容器先加载资源文件,因为其他servlet可能也会使用加载的资源。

15.4.5 其他配置的设置

         其他的设置同Struts的标准设置。

15.4.6 安全的配置

         Artimus使用标准的Declarative Security模式。容器负责管理这种安全问题。

15.4.7 保护的URLs

         指定URL patterns。

15.4.8 授权用户

         可以为用户分配多个角色,每个角色可以设定各自的资源。

15.4.9 授权策略

         <auth-method>指定授权策略。还有其他更安全的模式,但不是所有的浏览器都支持。

15.5 ArtimusServlet

         ArtimusServlet用来初始化一些应用程序的自定义的资源。使用自己的资源加载器的好处有:

n  可以提取大部分的子类来做大部分的工作

n  限制绑定到Struts的自定义代码的数量

n  将代码从可能发生在ActionServlet或PlugIn中的变化中保护起来

Artimus需要加载三个属性文件和初始化两个内部服务:

n  Artimus系统属性文件

n  两个SQL属性文件

n  连接适配器

n  Lucene搜索引擎

资源加载器从标准的Scaffold包中的类继承。

15.5.1 我们的子类

         ArtimusServlet从ConnectionServlet类继承,一个标准的Scaffold类。ConnectionServlet自动地初始化连接适配器。

         ConnectionServlet从ResourceServlet继承,ResourceServlet自动地加载缺省的资源文件。ResourceServlet也提供方法来加载其他属性文件。我们将使用这个工具方法来加载SQL命令。

15.5.2 String tokens

         作为一种编码风格,所用字符串常量,都使用静态的常量。

15.5.3 我们的扩展点

         ResourceServlet提供了initCustom方法作为扩展点,子类可以添加自己的初始化代码。ArtimusServlet重写了initCustom方法来加载SQL命令属性和设置Lucene索引文件的路径。

         获取SQL命令

         每一个SQL属性文件都是使用ResourceServlet提供的loadProperties方法加载。这个方法在web.xml中检查自定义的设置,如果没有找到则使用提供的缺省值。

         为使用loadProperties,我们需要传递:

n  初始化参数的名称

n  如果没有指定,则使用缺省值

n  可选地传递应用程序上下文的属性名称

如果传递了属性名称,loadProperties将在应用程序上下文中保存属性文件的一个引用。

初始化Lucene索引路径

15.6 应用程序和SQL属性文件

         使用标准的name-value格式。

15.7 index.jsp
15.8 全局的Forwards
15.9 /find/Recent

         业务逻辑对象FindByLast类。

15.9.1 继承Bean

         在大型应用中,每个包可能都需要自己的基类bean,由不同的开发组成员来管理。

         Bean类从ProcessBeanBase类继承,这是一个轻量级的类,提供了两个方便的属性,和一个标准的入口方法来调用Bean。

         标准的入口方法,使得其他过程,如Struts的Action类以相同的方式调用每一个对象(控制反转技术IOC)。Scaffold包定义了Executable接口来提供ProcessBean和其他Artimus Beans的入口方法。

15.9.2 super.execute

         通过execute方法进入我们的FindByLast类业务Bean。ProcessBeanBase的execute方法的缺省行为是通过反射将parameters对象转换成Map。

15.9.3 getArticles

         需要一个参数:要返回的文章的数目。

15.9.4 Access.findByLast和ResultList

         ResultList

15.9.5 ProcessResult

         ProcessResult接口定义一个传输对象,这个传输对象可以用来描述几种可能的结果。ProcessResultBase实现了ProcessResult接口。

15.9.6 ProcessAction

         所有的查找Action都调用ProcessAction,ProcessAction对象又调用业务层的bean(在parameter中指定bean的类型)。

15.10 tiles.xml和Article.jsp
15.10.1 useAttribute

         Tiles使用自己的上下文。当Tiles的Definitions对一个值使用put时,其实是把值放在了Tiles的上下文环境中。<userAttribute>标签使值在标准的上下文环境中可用,缺省的上下文环境是page范围的。

15.10.2 baseStyle

         为使容易地改变样式表,将样式表的路径维护成ActionForward。Rewrite标签从Struts配置文件返回样式表的路径。

15.10.3 title

         <bean:message>

15.10.4 Tiles
15.11 result.jsp
15.11.1 legend
15.11.2 isResult?

         如果结果数目为0,则不打印表头。

15.11.3 RESULT

         <html:link>

         <html:link>首先从全局的forward article获取path属性,即/do/view/Article。paramProperty和paramId属性指定使用article查询字符串参数的名称,row.getArticle()作为值。

         contributedDisplay

         对于字符串的显示的格式的需求可能各种各样。使用帮助方法。

15.12 Article Actions
15.13 view.jsp
15.13.1 headline

         样式表在layout页面定义。

15.13.2 content

         <bean:writer>的filter属性设成false,允许向页面输出HTML。Filter的缺省值是true。

15.13.3 contributor
15.14 edit.jsp
15.14.1 Article的内容
15.14.2 contributed/contributor
15.14.3 Article ID

         添加和编辑使用同一个页面,是通过存不存在ID来区别的。

15.14.4 Validation

         服务器端验证

         客户端验证

15.15 /do/Menu
15.15.1 logon

         在使用/admin下的URI之前,容器会保证用户已经登录。

15.15.2 menu
15.15.3 控件

         Option list。

15.15.4 saveResult

         创建一个新的ProcessResult的list,并放在application范围的上下文环境中。

15.15.5 结果
15.16 menu.jsp
15.16.1 /find/Hours
15.16.2 /menu/Find
15.16.3 /find/Last
15.16.4 /menu/Contributor
15.16.5 /menu/Manager

第十六章            移植到Struts1.1

16.1 下一站—Struts1.1

         在Struts1.1中,有一些包从Struts包中提到Jakarta Commons包中。使用这些包的类需要引入这些包:

n  BeanUtils包,代替BeanUtils包,ConvertUtils包,PropertyUtils包。

n  Collections包,代替ArrayStack,FastArrayList,FastHashMap,FastTreeMap

n  Digester包,代替原来的Digester包

如果使用了Struts1.0的Tiles和Validator,还需要:

n  改变对Validator包的引用

n  改变对Tiles的引用

n  将对Tiles和Validator的引用从web.xml中移除

n  在Struts配置文件中添加集成版本的Tiles和Validator的引用

16.1.1 Struts1.1的新特性

n  多个消息资源Message Resources

n  模块化应用程序

n  Dynamic ActionForms

n  Actions的Roles属性

n  Messages和Errors的分离的队列

n  LookupDispatchAction

n  SwitchAction

n  声明式的异常处理

n  RequestProcessor

n  PlugIn Actions

n  通用的日志接口

n  LabelValueBean

n  嵌套的标签库

n  新的Empty/notEmpty标签

n  新的frame标签

n  新的OptionsCollections标签

n  新的radio标签的idName属性

n  新的indexed标签属性

n  新的JavascriptValidator标签

n  Tiles框架

n  Struts Validator

16.1.2 我们可以使用的特性

         DynaActionForm和基于Action的安全。

16.2 基线变更
16.2.1 Struts1.1中的Tiles

         Tiles通过监视引用Definitions的ActionForwards。

16.2.2 Struts1.1中的Validator

         可能需要调整一些页面。

16.2.3 Struts1.1中的ReloadAction

         删除了ReloadAction。

16.2.4 其他一些对web.xml和struts-config.xml的基线变更
16.2.5 message.jsp(1.1)

         <validator:messagesExist>变为<logic:messagesExist>。

16.2.6 form.jsp(1.1)
16.2.7 MenuCreate(1.1)
16.3 Discretionay Changes

n  配置DynaActionForm

n  添加roles,实现基于Actions的安全

n  添加新的配置元素来加载缺省的消息资源

第十七章            Velocity:替换JSPs

17.1 移向Velocity模板

         变化是计算机科学的核心。

17.2 变化成就框架

         应用程序的一大部分成本花费在维护上。Struts通过封装最有可能变化的细节来使维护变得容易。这些细节中最主要的一部分是被Action引用的页面。

         Velocity特别对于那些不是Java工程师或JSP狂热者的页面设计师很重要。

         对于Struts应用,最主要的变化是在Struts配置文件中。Struts配置文件被设计出来,是为了集中实现细节,例如表示层页面或模板的名称。如果web应用的所有超链接都使用ActionForwards,那么只需要改变Struts配置文件就可以改变链接引用的页面。

17.3 我们为什么需要Velocity?

         既然有了JSP,为什么需要Velocity?

17.3.1 Velocity是轻量的、快速的、多功能的

         Velocity模块需要更少的代码,产生的更快。Velocity模板可以用在任何需要在运行时创建定制化输出Java应用程序中。Velocity可以用来从模板产生SQL,PostScript,e-mail,或XML。

17.3.2 Velocity能与其他工具很好地协作

         Velocity代码可以在可视化HTML编辑器中很好地显示,因此页面设计者通常会发现Velocity模板比JSP页面更容易使用。

17.3.3 Velocity简单而且强大

         Velocity模板语言(VTL)。

n  #set:建立一个引用的值

n  #if/#elseif/#else:提供条件输出

n  #foreach:对列表循环处理

n  #include:产生不被Velocity解析的本地文件

n  #parse:产生一个被Velocity解析的本地模板

n  #stop:停止模板引擎

n  #macro:定义一个VelociMacro(VM),VTL模板的一个重复的片段

n  ##:指定一个单行的注释

n  #*…*#:指定一个多行的注释

n  ${variable}:提供一个变量的引用

n  ${purchase.Total}:引用一个属性,如purchase.Total或purchase.getTotal()

n  ${purchase.setTitle(“value”):引用一个方法

17.4 在web应用中使用Velocity

         在Velocity中,在实际运行时使用模板来创建响应。在web环境下,Velocity servlet返回结果作为HTTP请求的响应。

         在处理模板的时候,Velocity Template Engine被给予一个运行时环境,包含了变量信息。Velocity提供了自己的上下文对象,所以同样的模板引擎可以用在web环境中,也可以用在一般的Java应用中。

         在web应用中,Velocity可以把标准的servlet上下文环境用作自己的上下文。当Velocity采用上下文环境时,它使用与JSP标签相同的策略。

         当引擎产生一个模板时,它查找Velocity语句和引用。由出现在行首的#和关键字标识。引用是对上下文中的变量的引用。引用又一个$和紧跟的一个名称来标识。任何一个Java对象都可以放在上下文中作为一个引用。引用可以访问Java类的任何public方法。

17.4.1 将Velocity与servlet资源一起使用

         Web应用中的很多组件间的通信都与都与servlet提供的四个标准的资源有关:application上下文,session,request,respons。Applicatin上下文让组件共享数据和服务。Session对象为每一个用户提供数据和服务。Response与request一起工作来完成HTTP请求—响应周期。

         Velocity提供了一个标准的VelocityViewServlet使Velocity与应用程序中的任何servlet的继承更加容易。

         例子:对于使用<request>标签检查用户的安全角色,可以这样书写:

         <request:isUserInRole role=”contributor”>

         <%--…%>

         </request:isUserInRole>

         同样的检查使用Velocity可以这样做:

         #if $request.isUserInRole(“contributor”)

         #...

         #endif

17.4.2 在Velocity中使用上下文属性

         <P>Username: ${session.getAttribute("username")}</P>

17.4.3 Velocity如何与Struts工作

         与Struts绑定的JSP标签使用一个叫做RequestUtils的类来访问Struts配置对象。

         实际上,VelocityStruts工具和它的查看工具可以做与RequestUtils相同的事情。

17.4.4 VelocityStruts工具

         VelocityViewServlet与Struts的ActionServlet一起加载到应用程序中。Velocity servlet被配置来匹配一些URL模式,通常是*.vm。一旦Velocity servlet被加载,我们可以向转发到JSP文件一样转发到VM文件。

17.4.5 Struts View工具

         $msg:MessageTool,提供对Struts消息资源的访问

         $errors:ErrorsTool,提供检查和输入Struts错误消息

         $link:LinkTool,提供方法与URI工作

         $form,FormTool,提供方法与Struts应用程序中的form和form bean工作。

17.5 我们的Logon模板
17.6 设置VelocityViewServlet
17.6.1 安装VelocityViewServlet

         Velocity-tools-view.jar

         Velocity-tools-library.jar

         Velocity-tools-struts.jar

         Dom4j.jar

         Jakarta-commons-collections.jar

         Toolbox.xml

17.6.2 部署Velocity Servlet

         如同配置其他servlet一样,在web.xml中配置。

         Toolbox参数

         用来指定工具配置文件。

         Properties属性

         Velocity提供了很多配置选项,放在了Properties文件中。

17.6.3 toolbox配置文件
17.7      设置struts-config文件

A设计模式

         Struts本身实现了很多经典的模式,首先就是MVC模式。

A.1 设计模式的简要历史

         可以说Struts是“站在巨人的肩膀上”。这里的巨人叫做设计模式。

A.1.1 四人帮

         23个有用的模式。

A.1.2 J2EE Blueprints

         J2EE Blueprints是一组指南、设计模式和示例代码,都是用来体现J2EE最佳实践的。

A.1.3 核心J2EE模式

         建立在四人帮的《设计模式》的基础上。

A.2 为什么模式重要?

         经验证的解决方案、便于交流、优缺点都列出来了。。。

A.3 模式不能做什么?

         模式帮助我们确定做什么和怎么做,而不能告诉我们为什么做和什么时候做。

A.4 Struts-A who’s who of design patterns

         Struts是一个利用模式的很好的例子。

         Struts实现的一些核心J2EE模式:

n  Service to Worker

n  Command,Command and Controller,Front Controller,Singleton,Service Locator

n  Dispatcher,Navigator

n  View Helper,Session Façade,Singleton

n  Transfer Objects,Value Object Assembler

n  View Helper

n  Composite View,Value ObjectAssembler

n  Synchronizer Token

n  Decorator

A.4.1 Service to Worker模式

         这是一个宏观的模式,使用其他两个模式。

         Front Controller模式

         ActionServlet提供了一个请求处理的中心访问点,这叫做Front Controller模式。

         Command/Command and Controller模式

         ActionServlet调用Action类已知的方法,并传递请求的一些细节。这叫做Command and Controller模式,是基于Command模式的。

Service Locator模式

Struts开发者可以切换JDBC驱动,连接池等等,只需要改变注册的Datasource的逻辑名称。

View Helper模式

使用JavaBean来将业务数据传递给view组件,这种模式叫做View Helper模式。

A.4.2 Singleton模式

         Action使用单例模式,但把书写线程安全的Actions的责任交给了开发者。

A.4.3 Session Façade模式

         消息资源组件使用此模式,隐藏了选择用户locale的复杂性,只需要通过key来获取message。

A.4.4 Value Object/Value Object Assembler模式

         把很多值放在一个对象中传输。

A.4.5 Composite View模式

         模板标签。

A.4.6 Synchronizer Token模式

         防止重复提交。

A.4.7 Decorator模式

         ActionMapping类用来扩展Action对象而不是Action类。

B Struts-config API

B.1 <struts-config>

         <struts-config>是配置文件的根节点,它包含了所有其他配置设置的嵌套元素。其他元素有:

n  set-property:指定一个方法名和另外的JavaBean的配置属性的初始值。

n  data-sources:指定一组data-source对象。

n  global-exceptions:描述一组可能被Actions对象抛出的异常。

n  exception:为一个异常类型注册一个ExceptionHandler。

n  form-beans:为应用程序模块描述一组form bean描述子。

n  form-bean:指定一个可以被Action引用的ActionForm的子类。

n  form-property:指定一个JavaBean的属性,用来配置DynaActionForm及其子类。

n  global-forwards:描述一组ActionForwards对象,可以作为所有Action的返回值。

n  forward:描述一个ActionForward对象,可以作为一个Action的返回值。

n  action-mappings:描述一组ActionMappings,可以用来处理匹配我们的ActionServlet在容器中注册的URL模式的请求。

n  action:描述一个ActionMapping对象,用来处理特定的模块相关的URI的请求。

n  controller:描述ControllerConfig bean,用来封装应用程序模块的运行时配置。

n  message-resources:描述一个MessageResource对象。

n  plug-in:指定一个plugIn的类名,用来接受应用程序启动和关闭事件的通知。 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值