Web应用是Web服务的一种动态扩展。Web应用可分为两类:
- 面向表示的Web应用。在响应请求时,面向表示的Web应用产生动态的Web页面,这种页面包含了各种不同的标记语言(如HTML,
XML, 等等)。
- 面向服务的Web应用。面向服务的Web应用实现细粒度Web服务的端点。面向服务Web应用通常为面向表示应用所调用。
在Java2平台上,Web组件为Web
服务器提供了动态扩展能力。Web组件可以是Java
Servlets或者JSP页面。Servlets是Java编程语言中用于动态地处理请求和建立响应的一种类。JSP页面是基于文本的文档,它像
servlets一样执行,但是允许使用更自然的方法来创建静态内容。尽管servlet和JSP页面可以交替地使用,但是它们各有千秋。
Servlets最适合于面向服务的Web应用,同时还擅长于管理面向表示的Web服务的控制功能,例如发送请求和处理非原文的数据。而JSP页面则更适
合于产生基于文本的标记,例如:HTML、SVG、WML以及XML等。
Web组件以一个名为Web容器
的运行时平台中的服务作为支撑。在Java Web服务开发包(Java Web Services Developer
Pack, Java WSDP)中的Web组件在Tomcat Web容器内运行。Web容器提供了一些服务,例如请求发送、安全、并发以及生命周期管理。它还使得Web组件可以访问多种API,
例如命名、事务处理以及e-mail等方面的API。
本章里描述了Web应用的组织、配置以及安装和部署过程。第11章和第12章中讲述如何开发面向服务的Web应用的Web组件。第14章和第15章讲述如何开发面向表示Web的应用的Web组件。JSP技术的许多特征是由Java
Servlet技术决定的,因此即使你不打算编写servlet,也应该熟悉这方面的知识。
大多数Web应用都使用HTTP协议,而且对HTTP的支持也正是Web组件的一个主要方面。对于HTTP协议特征的简要总结,参见HTTP概述。
Web应用的生命周期
Web应用由Web组件、静态资源文件(如图像)、帮助类和库组成。Java
WSDP提供许多支持服务,用于增强Web组件的性能并使得它们更易于开发。不过,由于要充分考虑这些支持服务,所以Web应用在创建和运行过程上与传统的stand-alone式的Java类有所不同。
在Web应用被部署以后,就可以对其行为的某些方面进行配置。配置信息通过Web应用部署描述文件来维护,该文件是一种XML格式的文本文件。部署描述文件必须遵从Java
Servlet规范中描述的模式。
创建、部署和执行Web应用的过程可以总结为以下几步:
1.开发Web组件代码(可能还包括部署描述文件)。
2.建立Web应用组件连同所有静态资源(例如图像)和组件要引用到的帮助类。
3.将应用安装或部署到Web容器中。
4.访问指向该Web应用的URL。
开
发Web组件代码这方面的知识将在以后的章节中讲述。接下来的几节将对步骤2到步骤4作出详细的讲解,并给出一个Hello,World式的面向表示的应
用的例子。该应用允许用户输入名字到HTML表单中(见图4-1),并且在名字提交之后显示一条问候信息(见图4―2)。
图4-1 问候表单
图4-2
响应
这个Hello应用包含了两个Web组件,用于产生问候信息和响应。在本指南中,该应用有两个版本:一个是servlet版,名为Hello1,它的组件通过两个servlet类(GreetingServlet.java和ResponseServlet.java)来实现。另一个是JSP版,名为Hello2,它的组件通过两个JSP页面(greeting.jsp 和 response.jsp)来实现。这两个版本的例子展示了一个包含Web组件的应用在大包、部署和运行时所涉及到的任务。如果你是在线浏览本指南,请务必下载本指南的捆绑包,以获得这个示例的源代码。
Web应用归档文件
如果要发布一个Web应用,你可以将其打包到一个Web应用归档文件(Web
application archive,WAR)中,WAR与JAR类似,都是用作Java类库的包。除了应用的Web组件外,Web应用的归档文件还包含其他的一些文件,包括:
· 服务器端的实用工具类(如数据库bean、购物车等等)。这些类通常与JavaBeans组件的结构一致。
· 静态Web表示内容(如HTML,图像和声音文件等)
· 客户端类(applet和实用工具类)
Web组件和静态Web内容文件叫做Web资源。
Web应用的运行可以通过一个WAR文件,或者通过一个同为WAR格式的解包目录。
WAR目录结构
WAR的顶级目录是该应用的文档根目录。这个文档根目录下存放着JSP页面、客户端类和归档文件,以及静态Web资源。
文档根目录下含有一个名为WEB-INF的子目录,其中包含了以下文件和目录:
· web.xml
—— Web应用的部署描述文件。
· 标签库描述文件。
· classes
—— 一个子目录,包含了服务器端类:servlets,实用工具类和JavaBeans组件。
· lib
—— 一个子目录,包含了库(标签库和所有作为服务器端类的实用工具类)
还可以创建应用专用(application-specific)的子目录(即包目录),可以在文档根目录下创建,或者在WEB-INF/classes
目录下创建。
指南示例的目录结构
为了便于迭代开发并且将Web应用的源代码与已编译的文件分开,实例的源代码存储在每个应用目录mywebapp
下,其结构如下:
· build.xml
—— Ant生成文件
· context.xml
——可选应用配置文件
· src
—— servler和Javabeans组件的Java源代码。
· web
—— JSP页面和HTML页面、图像。
随示例一起发布的Ant
build文件(build.xml)中包含了一些目标 (target),用以在mywebapp
的build
子目录中创建解包的WAR结构,将文件拷贝和编译到那个目录中,并且通过专门的Ant任务调用manager
命令,来安装、重新装载、移除、部署和解部署应用。该指南示例的Ant目标是:
· prepare
(准备) —— 创建build目录和WAR子目录。
· build
(编译) —— 编译和拷贝mywebapp
Web应用文件到build目录下。
· install
(安装)—— 使用Ant install
任务通知Tomcat安装应用(见安装Web应用)。
· reload
(重新装载)—— 使用Ant reload
任务通知Tomcat重新装载应用(见更新Web应用)。
· deploy
(部署) —— 使用Ant deploy任务通知Tomcat部署应用(见部署Web应用)。
· undeploy
(解除部署)——使用Ant undeploy任务通知Tomcat解除部署应用(见解除部署Web应用)
· remove
(移除) —— 使用 Ant remove
任务通知Tomcat移除应用(见移除Web应用)
创建WAR
手工的创建WAR文件有两种方法:
· 使用随J2SE SDK一起发布的JAR工具。只需简单地在指南示例的build目录下执行如下命令:
jar cvf mywebapp
.war
.
· 使用Ant war
任务
这两种方法都要求有创建好的Web应用部署描述文件。
配置Web应用
Web
应用的配置是通过包含在Web应用部署描述文件中的元素的设置来实现的。你可以使用文本编辑器来手工创建这些描述文件。接下来的章节将对你想配置的Web
应用特征作一个简要的介绍。其中,许多的安全参数都可以在配置时指定,这些内容在第18章可以看到。如果你想得到这些特征的完整列表和描述,参见Java
Servlet规范。
在接下来的几节中,将给出一些示例来演示Hello,World应用的配置过程。如果Hello,World没有使用指定的配置特征,那么本节将给出其他的示例来展示部署描述文件的元素并描述指定这种特征的一般过程。
注
意:描述符元素必须在部署描述文件中按照下列顺序出现:icon,display,description,distributable,context
-param,filter,filter-mapping,listener,servlet,servlet-mapping,session-config,mime-mapping,welcome-file-list,error-page,taglib,resource-env-ref,resource-ref,security-contraint,login-config,seurity-role,env-entry.
序言
既然部署描述文件是一种XML文档,它就需要一个序言。Web应用的部署描述文件的序言如下所示:
别名路径
当Tomcat收到一个请求时,它必须决定使用哪个Web组件来处理请求。这一步是通过将包含在请求中的URL路径映像到一个Web组件来实现的。URL路径包含上下文根目录(参见Installing
Web Application,http://java.sun.com/webservices/docs/1.1/tutorial/doc/WebApp5.html#wp75667)和一个别名路径。
http://<host>:8080/context_root
/alias_path
http://<host>:8080/context_root
/alias_path
在servlet
可以被访问前,Web容器必须最少有一个该组件的别名路径。别名路径必须以一个“/”开始,以一个字符串或者一个带扩展名的通配符(例如:*.jsp)结
束。既然Web容器自动地映像到以*.jsp结束的别名路径,你无需为JSP页面指定别名路径,除非你想通过一个名称,而不是其文件名来引用JSP页面。
在更新Web应用中讨论的实例中,问候页面有一个别名response.jsp,但它仍然是通过其文件名来引用的。
在Web
部署描述文件中设置servlet版的Hello应用的映像,必须添加下列servlet和servlet-mapping元素到Web应用部署描述文件
中。为了定义JSP页面的别名,必须替换在servlet元素中的servlet-class子元素和jsp-file子元素。
greeting
greeting
no description
GreetingServlet
response
response
no description
ResponseServlet
greeting
/greeting
response
/response
上下文和初始化参数
同
一个WAR中的各Web组件共享一个表示它们的应用上下文的对象(见访问Web上下文)。你可以传递参数到上下文或者Web组件。要实现这一点,你必须添
加一个context-param或init-param元素到Web应用部署描述文件中。context-param是顶级web-app元素的子元
素。init-param是servlet元素的子元素。下面的元素用于声明一个上下文参数,该参数设置在第17章中讨论的示例的资源束:
javax.servlet.jsp.jstl.fmt.localizationContext
messages.BookstoreMessages
...
事件监听器
要添加事件监听器类,必须添加一个listener元素到Web应用部署描述文件中。下面的元素描述了在第14章和第17章用到的监听器类)。
listeners.ContextListener
过滤器映像
Web
容器使用过滤器映像声明来决定应用于某个请求的过滤器,并且决定这些过滤器的顺序。正如在别名路径中描述的那样,该容器将请求URL与一个servlet
相匹配。要决定引用哪个过滤器,容器通过servlet名或者URL模式来匹配过滤器映像声明。过滤器被调用的顺序就是过滤器映像声明在过滤器映像列表中
出现的顺序,过滤器映像声明将请求URI与一个servlet匹配起来。
要指定过滤器映像,必须添加一个filter和filter-mapping元素到Web应用部署描述文件中。下面的元素用于声明有序的过滤器,并将其映像到在第14章讨论过的Receipt
servlet:
OrderFilter
filters.OrderFilter
OrderFilter
/receipt
错误映像
可
以指定状态代码与Web资源之间的映像,其中的状态代码可以是一个HTTP响应中返回的,也可以是由任何Web组件返回的一个Java编程语言异常中返回
的。要设置映像,必须添加一个元素到部署描述文件中。下面的元素用于将OederException映像到第14章
中使用的页面errorpage.html。
exception.OrderException
/errorpage.html
注意:你也可以为包含在WAR内的JSP页面定义错误页面。如果错误页面是同时为WAR和JSP页面而定义的,则JSP页面的错误页面居先。
指向环境条目、资源环境条目或资源的引用
如
果Web组件需要引用环境条目,资源环境条目或资源(如数据库),必须通过在Web应用部署描述文件中的,<
resource-env-ref>或元素来声明引用。下面的元素用于声明一个指向某个数据源的引用,该
数据源在本指南关于Web技术的几章中要用到。
jdbc/BookDB
javax.sql.DataSource
Container
安装Web应用
上下文(context)是映射到一个Web应用的名称。例如,Hello1应用的上下文是/hello1。为了将应用安装到Tomcat,需要通知Tomcat有一个新的可用上下文。
可以使用Ant
install任务来通知Tomcat有一个新的上下文。注意,在Tomcat重新启动之后,安装好的应用还不能使用。要永久地部署应用,参见部署Web应用。
Ant
install任务告诉由url属性指定的在本地运行的管理器安装一个应用,其上下文由path属性指定,其安装位置包含了由war属性指定的该Web应用的文件。war属性的值可以是一个WAR文件,如:
jar:file:/path/to/bar.war!/
或者是一个解包目录:
file:/path/to/foo。
username="username"
password="password" />
username和password属性将在Tomcat Web应用管理程序中讨论。
这里无需提供一个war属性,你可以使用config属性来指定配置信息:
path="mywebapp"
config="file:build/context.xml"
username="username"
password="password"/>
config属性指出一个配置文件包含上下文条目的格式
docBase="../docs/tutorial/examples/web/bookstore1/build"
debug="0">
注意,这个上下文条目通过它的docBase属性隐式地指定了Web应用文件的位置。
本指南示例build文件包含一个Ant
install target,它将调用Ant install 任务:
description="Install
web application" depends="build">
config="file:build/context.xml"
username="${username}"
password="${password}"/>
Ant
install任务要求Web应用部署描述文件(web.xml)是可用的。所有的指南示例应用都是随一个部署描述文件一起发布的。
To
install the Hello1 application described in Web
Application Life Cycle:
要安装Web应用生命周期中描述的Hello1应用,需按下列步骤:
1. 在终端窗口中,转到<JWSDP_HOME>/docs/tutorial/examples/web/hello1.
2.确认Tomcat已启动
3.执行ant install。install target通知Tomcat新的上下文是可用的。
部署Web应用
如果Tomcat正在运行,就可以使用Ant
deploy任务永久地将一个上下文部署到Tomcat。
war="file:/path/to/mywebapp.war"
username="username"
password="password" />
不同于install任务,install任务可以引用一个解包目录,deploy任务需要一个WAR。该任务加载WAR到Tomcat并且启动应用。也可以通过这个任务将其部署到一个远程服务器上。
下面是其他一些可用的部署方法,但是它们要求重新启动Tomcat:
· 将Web应用目录或WAR拷贝到/webapps。
·
将包含了上下文条目的名为mywebapp.xml的配置文件拷贝到/webapps。上下文条目的格式在<
JWSDP_HOME>/docs/tomcat/config/context.html中的
Server Configuration Reference里有描述。注意,上下文条目通过docBase属性隐式地指定了Web应用文件的位置。例如,下面是在第14章中讨论的应用的上下文条目:
docBase="../docs/tutorial/examples/web/
bookstore1/build" debug="0">
一些实例build文件包含一个像Ant
deploy 任务一样调用的Ant deploy 目标。
列出已安装和部署的Web应用
如果想列出当前在Tomcat内可使用所有Web应用,你可以使用Ant
list任务:
指南示例build文件包含一个像调用Ant
list 任务一样调用的Ant list 目标。
还可以通过运行Manager
Application来查看列出的应用:
http://
:8080/manager/list
运行Web应用
Web应用是在Web浏览器引用映像到组件的URL时执行的。一旦安装了或者部署了Hello1应用,便可通过将浏览器指向
http://
:8080/hello1/greeting
来运行Web应用。
用运行Tomcat的主机名替代。如果浏览器运行在与Tomcat相同的主机上,就可以用localhost替代。
更新Web应用
在开发期间,经常需要对Web应用进行修改。在修改servlet之后,必须:
1.重新编译servlet类。
2.更新服务器上的应用。
3.重新在客户端装载URL。
更新JSP页面时,无需重新编译或重新装载应用,因为Tomcat会自动完成这些事情。
为了尝试这一特征,修改Hello应用的servlet版本。例如,你可以将GreetingServlet
返回的问候信息修改为:
Hi, my name is Duke. What's yours?
更新文件的过程为:
1. 编辑在源码目录/docs/tutorial/examples/web/hello1/src中的GreetingServlet.java文件。
2. 运行ant build任务。该任务将servlet重新编译到build目录中。
更新服务器中的应用这一过程取决于你是否使用Ant
install任务来安装或者使用Ant deploy任务来部署这个应用。
重新装载Web应用
如果你已经使用Ant
install命令安装了应用,就可以使用Ant reload任务来更新服务器中的应用:
username="username
" password="password
" />
示例build文件包含一个
Ant remove目标,该目标调用 Ant remove任务。从而更新服务器中的Hello1应用,执行ant
reload。为了观察经过更新的应用,重新装载客户端的Hello1的URL。注意,reload
任务只改变Java类,而不会改变Web.xml文件。为了重新装载web.xml,需要将应用删除
(参见移除Web应用)并重新安装。
在浏览器上你可以看到如图4-3所示的屏幕:
图4-3 新的问候信息
为了在该实例的JSP版本上尝试这一特性,首先建立和部署JSP版的Hello应用:
1.
在终端窗口中,转到
<JWSDP_HOME>/docs/tutorial/examples/web/hello2.
2. 运行ant build
。build
目标将产生所有必需的编译并且拷贝文件到
<JWSDP_HOME>/docs/tutorial/examples/web/hello2/build
目录。
3. 运行ant install
。install
目标将build目录拷贝到/webappsbuild并通知Tomcat有新的应用。
修改某一个JSP文件。然后运行ant
build
将经过修改的文件拷贝到docs/tutorial/examples/web/hello2/build。记住,这里无需重新装载服务器中的应用,因为当某个JSP文件被修改时,Tomcat会自动检测到这一情况。要查看经过修改的应用,
需重新装载客户端的Hello2的URL。
重新部署Web应用
如果已经通过使用Ant
deploy任务部署了应用,就可以通过接连使用Ant undeploy
任务(见解除部署Web应用)和Ant
deploy
任务来更新这个应用。
移除Web应用
如果想从服务中移除已安装的Web应用,可以调用
Ant remove
任务:
username="username
" password="password
" />
示例build文件包含一个
Ant remove目标,该目标调用 Ant remove任务。
解除部署Web应用
如果想移除一个已部署的Web应用,可以使用Ant
undeploy任务:
username="username
" password="password
" />
一些实例build文件包含一个Ant
undeploy目标,该目标调用Ant undeploy任务。
Web应用的国际化和本地化
所谓的国际化是指使得应用能够支持各种语言和数据格式的过程。所谓本地化,是指使得一个国际化的应用能够支持某种特定的或者本地的语言的过程。虽然所有客户端用户接口都应该被国际化和本地化,但是国际化和本地化对于Web应用来说尤其重要,因为Web本身就是无所不及的。如果想要很好地鸟瞰一下国际化与本地化问题,参见
http://java.sun.com/docs/books/tutorial/i18n/index.html
有两种方法可以用于对Web应用进行国际化:
·
在每个目标位置中提供一个JSP页面,并且使用一个控制器servlet来发送请求到适当的页面上(取决于被请求的位置)。如果需要对一个页面或者一个完
整的Web应用的数据进行国际化,这种方法比较有用。
· 将页面上所有的本地敏感的数据 (例如错误信息,串字符或按钮标签)
分离到资源束内,然后访问这些数据,来获取响应的翻译过来的信息并将其插入到页面当中。这样一来,就不是在代码中直接创建字符串,而是创建一个包含了翻译
过来的信息的资源束,然后使用相应的关键字从该资源束中读出翻译过来的信息。资源束可以由一个文本文件(属性资源束)或一个包含了映像的类(列表资源束)
来支持。
在
下面的关于Web技术的几章中,Duke's
Bookstore实例被分别国际化和本地化成英语和西班牙语。关键字-值对包含在名为message.BookMessage_*.class的列表资
源束。为了了解在资源束中的关键字-值对是怎样的,请看在文件messages.BookMessages.java中添加的几行:
{"TitleCashier",
"Cashier"},
{"TitleBookDescription",
"Book Description"},
{"Visitor",
"You are visitor number "},
{"What",
"What We"re Reading"},
{"Talk",
" talks about how Web components can transform the
way
you develop applications
for the Web. This is a must read for
any self respecting
Web developer!"},
{"Start",
"Start Shopping"},
为了获得对应于某个给定用户的正确字符串,Web组件从请求中获取位置(由浏览器的语言首选项设定),为那个位置打开资源束,然后将该资源束作为会话属性保存:
ResourceBundle messages
= (ResourceBundle)session.
getAttribute("messages");
if (messages
== null) {
Locale
locale=request.getLocale();
messages
= ResourceBundle.getBundle("WebMessages",
locale);
session.setAttribute("messages",
messages);
}
Web组件从会话中获取资源束:
ResourceBundle messages
=
(ResourceBundle)session.getAttribute("messages");
然后用下面的语句查找与关键字TitleCashier相关的字符串:
messages.getString("TitleCashier");
上面对国际化Web应用的介绍非常简要。如果要了解更多该主题的相关信息,参见Java
BluePrints:
http://java.sun.com/blueprints