关于本书3 前提下扩展程序的功能。Struts2使用插件架构来实现这个功能。如果你熟悉Firefox或者Eclipse 可能早就领路过插件架构的魅力了。这一章探究了这些技术细节,并且告诉你如何从零开始创建 一个插件。 第13章讲解实际开发中的最佳实践和常用技巧,内容涵盖优化开发环境,使用通配符映射注 册Web特性等。当然,你会发现很多技巧都可以相互配合使用。 第14章是一个迁移手册,用来帮助你把Struts1的应用程序迁移到Struts2。这一章也指出了 Struts1和Struts2之间的相同点与不同点。 第15章讲解了一些“四两拨千斤”的技术,通过这些技术可以最大限度地挖掘出Sus2开发 框架的潜力。这一章包含了一些高级概念。在开发大型的Struts2应用之前,你应该反复阅读几 遍这章内容。将来某一天,当你翻看自己编写的代码时,一定会非常庆幸使用了这些技术。 代码约定 本书印刷将遵循以下约定: 口代码清单使用Courier字体 口正文中的代码也使用Courier字体 口需要强调的内容和新术语使用楷体 口代码注解取代了程序行内的注释,这些注解强调了重要的概念或者代码中的重要位置。 有些带有像①这样数字编号的注解,会在正文中进一步引用并说明。 代码下载 在Manning网站这本书的主页上有下载本书中示例代码的链接,链接为www,manning.com Struts.2 inAction或者www.manning.com/dbrown,下载得到-一个名为SampleApplication,.zip的压缩文 件。压缩文件中包含了一系列的Java Web应用程序包(也就是WAR文件),也包含一些源代码的 说明文档,其中有一个README文件,说明了如何安装这些Wb应用程序。 这些代码有几.点需要注意,本书中所有的代吗都在Snts2 InAction.war应用程字中。这个应用 程序使用模块化的方式来组织所有的子应用程序,每一章的代码都在一个子应用程序(模块)中。 本书自始至终在构建Sus2公文包示例应用程序,这是一个全面展现Suts2特性的示例程序, 我们逐章地增加这个示例程序的功能。这意味着Struts2:InAction.war这个程序包含了这个示例程序 的很多版本,功能一个比一个强大。这些版本按章号分块组织。 对于一个新手来说,要成功部署Struts2 nAction..war这样一个复杂的应用程序肯定会面临很多 的棘手问题。因此我们也提供了一个简单的HelloWorld.war应用程序,这个程序只保留了这个复 杂程序中的Hello World机能。使用这个程序可以很快地建立和运行Struts2程序,而不需要关注诸 如数据库连接等复杂的问题。 作者在线 购买了本书的读者可以免费访问Manning出版社的一个内部论坛,你可以对这本书发表评
4第1章Struts2:现代Web框架 Wb应用程序必须要处理这个差异。 对于Web应用程序而言,需要跨越HTTP协议的两个障碍 —无状态和基于文本。无状态的 协议不记录收到的多个请求之间的关系。每一个请求都会被当做服务器接收到的唯一的请求处 理。HTTP服务器没有保存用来追踪和逻辑上连接来源于一个给定客户的多个请求的记录。服务 器有客户端的地址,但是这个地址只用来返回当前请求的文档。如果一个客户回来请求其他文档, 服务器不知道这是同一个客户的重复访问。 但是如果我们想构造一个含有更复杂用例的复杂应用程序,这就行不通了。以最简单、最常 见的安全的Wb应用程序为例, 一个安全的Wb应用程序需要对它的用户进行身份验证。要做到 这点,客户发送用户名和密码的请求,必须能够通过某种方式与这个会话期间来源于该客户的其 他请求关联起来。不能记录不同请求之间的关系,连现代Wb应用程序的入门功能都不能实现。 每一个现代Web应用程序都必须解决这个问题。 同样麻烦的是,HTTP还是基于文本的。将基于文本的技术与强类型的技术(例如Java)匹 配起来引发了大量的数据绑定工作。在一个HTP请求中,所有的数据都以文本方式表示。在处 理过程的某个地方,这些编码的数据必须被映射到Java数据类型。而且,这个转换在请求处理过 程的两端都要发生。输入请求参数必须被迁移到Java环境,发出的响应必须将数据从Java带回到 基于文本的HTTP响应。虽然不是什么高深的技术,但它却为Wb应用程序带来了成堆的烦琐工 作,这些任务既容易出错又浪费时间。 2.Java Servlet API Java Servlet API帮助缓解了-一些痛苦.这个重要的技术将HTTP公开给Java平台.这意味着Java 开发人员可以依据HTTP客户/服务器通信以直观的面向对象的抽象方式编写HTTP服务器代码。 Servlet API中的核心对象是Servlet.请求(request)和响应(response),Servlet是一个单例(singleton) 的Java对象,它全部的用途是接收请求,以及在任意的后端处理之后返回响应。请求对象封装了 各种各样的请求细节,包括通过表单字段提交的请求参与,以及查询字符串参数。响应对象包含 如响应首部、生成响应文本的输出流等一些关键项目。总之,Servlet接受请求对象,检查其中的 数据,执行适当的后台逻辑,之后向客户返回响应。 基础你应该知道Sun公司和Servlet规范.如果你不熟悉Sun公司的做事方式,这里是一个简单 知识的介绍.Sun公司提供技术规范,例如Servlet API。这个规范是在社区中产生的,其中包 括感兴趣的各方,Su公司本身并不是很重要.规范详细描述了这个API必须遵守的职责 和契约,真正的实现由第三方厂商提供.以Servlet规范为例,其实现是Servlet容器(Servlet container)。这些容器可以是独立的实现,例如非常流行的Apache Tomcat,,也可以被集成 到其他更大的应用程序服务器中,这些容器既有开源软件又有完全商业化的产品,如果 你不熟悉Servlet规范,我们建议你阅读一下,它简明扼要,读起来也很流畅」 在部署Servlet之前,必须按照标准把它们打包。Servlet打包的基本单元被称为Web应用程序 (web application)。虽然Web应用程序听起来好像是一个笼统的术语,但是它是Servlet术语中的一
1.1Web应用程序:快速学习5 个具体事物。Servlet规范把Web应用程序定义为“Servlet、.HTML页面、类以及其他资源的集合”。 通常情况下,一个Web应用程序需要几个Servlet米处理客户发送的请求。一个wcb应用程序的 Servlet和资源文件按照特定的目录结构被打包在一起,并且被压缩为一个以.war结尾的档案文件 WAR文件是Java JAR文件的特殊版本,WAR代表了Web Application Archive.第2章讨论HelloWorld 应用程序时,会准确地查看如何根据这些标准安排一个Stus2应用程序。 打包Web应用程序之后,就需要部署它。Web应用程序被部署在Servlet容器中。Servlet是 种特殊的应用程序,被称为托管生命周期的应用程序(managed life cycle application)。这意味着 你不直接执行Servlet,把Servlet部署在一个容器内,容器通过调用不同的Servlet生命周期方法来 管理它的执行。当Servlet?容器收到请求的时候,容器首先决定它管理的哪个Servlet来处理这个请 求。在容器判断了哪个Servlet应该处理这个请求之后,它会调用Servlet的service()方法,并且 移交给这个方法一个请求对象和一个响应对象。还有其他生命周期方法,但是service()方法负 责完成实际的工作 图1-2展示了Servlet API中的关键角色Servlet、web应用程序和Servlet容器之间的关系。 应用程序 应用程序 A B Web 应用程序 Servlet容器 http://localhost:8080/WebAppC/ServletB Servlet A Servlet C Web应用程序C 图l-2 Servlet API的组织:Servlet、Web应用程序和Servlet容器 如你所见,一个Servlet容器内可以包含一个或者多个Web应用程序。在图l-2中,3个web应
6第1章Struts2:现代Web框架 用程序被部署到一个容器中。所有的请求,不管最终指向哪个Wb应用程序,首先必须被容器处 理,它是服务器。Servlet?容器通常监听8080端口上所有的请求。当一个请求到达这个端口的时候, 容器通过解析请求的命名空间来发现指向的应用程序。从URL的命名空间中既能判断Wb应用程 序,又能判断其中指向的独立的S©vlct。解析过程这里就不详细说明了,但是图1-2给出了URL 如何映射到具体Servlet的最基本示例,我们假设Servlet容器正在监听1 ocalhost网络接口上的请 求。 除了将HTTP公开给Java语言,Servlet APIi还提供了其他重要的高级功能,例如会话机制,它 使得我们可以关联来自于一个给定客户的请求组。正如我们前面解释的那样,HTTP没有提供感 知一系列请求状态的机制,不管这些请求是否来自于同一个客户。就高级功能而言,这也许是我 们从Servlet中获得的最重要的好处。如果没有这个功能,我们只能自己处理Cookie,并且解析嵌 入查询字符串中的会话关键字。 除了会话机制,Servlet API没有提供太多高级功能。Servlet APIi通过一套面向对象的抽象直 接封装客户/服务器交互的细节。这意味着我们不必自己解析传入的HTTP请求,而是收到一个 整洁的、已经在Java中包装好的请求对象。我们说这些是为了指出在现代Web应用程序领域中 Servlet API是一个底层的技术。作为基础设施,Servlet提供了可靠的基本功能,在其上可以构建 健壮的Web应用程序。提到Web应用程序的日常需要,Servlet API则没有提供这方面的解决方案。 现在我们知道了Servlet能做什么,让我们看看它们不能做什么。这些领域内的日常任务需要像 Struts2这样的web应用程序框架来处理。 1.1.3深入研究 在Servlet API解决了低层客户/服务器问题之后,现在主要关注应用程序级别的问题。有很 多日常任务是所有Wb应用程序处理请求时都必须要解决的,其中包括: 口请求参数到Java类型的数据绑定: 口验证数据: 口访问业务逻辑: 口访问数据层: 口呈现表示层(HTML等): 口提供国际化和本地化的支持 接下来,我们会逐一简要地讨论这些问题。 1.请求参数数据绑定和数据验证 作为基于文本的协议,HTTP必须以文本编码的方式表示它的请求参数。当这些参数进入应 用程序时,它们必须被转换为合适的本地数据类型。Servlet API并没有提供这个功能。从请求对 象中取出的请求参数仍然以字符串的形式表示。将这些字符串转换为Jva数据类型很容易,但都 很费时间,而且容易出错。转换为简单类型非常乏味,转换为更加复杂类型不仅复杂而且乏味 另外,数据在进入系统之前必须经过验证。注意,有两个层次的验证。首先,字符串必须是想转 换到的Java类型的合法表示,例如,邮政编码中应该不包含任何字母
1.2web应用程序框架7 其次,在这个值被成功地绑定到Jav类型之后,数据必须被高级的逻辑验证,例如这个邮政 1 编码是否有效。应用程序必须能够根据业务规则判断数据是否在可接受的范围之内。除了检查邮 政编码的有效性,可能还需要核对邮件地址是否具有有效的格式。花费太多的时间写这样的代码 无疑会让Java开发人员感到枯燥无趣。 2.访问业务逻辑和数据层 在应用程序内部,大部分请求都需要访问业务逻辑和数据层。虽然这些访问细节在不同的应 用程序之间会有所变化,但是还可以概括出两点。第一,尽管这些调用细节有所不同,但它们形 成了一个一致的工作流模式。这个工作流模式的核心是每个请求的处理包含一系列必须要完成的 工作。这些工作就是面向动作的框架(action--oriented framework)中的动作(action)。第二,这 些工作的逻辑和功能代表了Web相关领域之外的一个明确的步骤。如果回顾-一下Wb应用程序在 处理请求时必须要处理的日常任务,就会发现这些对业务逻辑和数据层的访问是唯一没有明确涉 及这是一个Wb应用程序而非一个桌面应用程序的事实。如果应用程序设计良好,那么业务逻辑 和数据层不会在意它们是被Wb应用程序调用,还是被桌面应用程序调用。因此,虽然所有的 Wcb应用程序都必须做这些调用,但是值得注意的是,它们独立于Wb应用程序的特定工作流。 3.呈现表示层和国际化 可以说Web应用程序的表示层只是一个HTML文档。但是,越来越多的复杂的JavaScript、功 能完备的CSS以及其他嵌入式技术己经使这种说法变得不再准确。同时,前端用户界面技术变得 越来越复杂,越来越多的应用程序需要国际化。国际化允许我们构建单一的Wb应用程序,它可 以发现每个用户所在的地域,并且提供与地域相关的语言、日期格式、时间格式以及货币格式。 不管应用程序返回的是一个静态文本的简单页面,还是像Gmail/风格的超级客户,表示层的呈现 都是所有Wb应用程序的核心任务。 我们已经列出了所有Wb应用程序应该处理的任务。然后呢?由于这些任务在处理几乎每个 到达Wb应用程序的请求时都很相似,所以它们是重用的最佳选择。我们一定愿意Wb应用程序 框架能够为这些常见任务提供可重用的解决方案。让我们看看框架如何帮助我们。 1.2Neb应用程序框架 既然谈到了Wb应用程序运行的内容,下面我们就来讨论如何利用框架减少构建它们的] 作。为了构建功能强大的wb应用程序,大部分开发人员需要他们能够得到的所有帮助。除非你 想花费大量的时间手动解决前一节列出的任务,否则你必须使用一个框架,并且有很多框架可供 选择。让我们从一个基本问题开始。 1.2.1什么是框架 框架是一种结构化的软件。之所以说结构化(structural)是因为,相对于任何具体的功能需 求,结构化或许是框架更重要的目标。框架尽量将特定领域的日常任务和具体问题的处理流程抽 象化,然后提供一个平台,基于这个平台可以更快地构建Wb应用程序。框架主要在两个方面帮