贯通Tomcat开发
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

第1篇 基础入门篇

第1章 认识Tomcat

【本章导读】

Tomcat服务器是一个免费的开放源代码的Web应用服务器。它是Apache软件基金会(Apache Software Foundation)的Jakarta项目中的一个核心项目,由Apache、Sun和其他公司及个人共同开发而成。由于有了Sun的参与和支持,最新的Servlet和JSP规范总是能在Tomcat中及时地得到体现,Tomcat 6支持最新的Servlet 2.5和JSP 2.1规范。因为Tomcat技术先进、性能稳定且免费,所以深受Java爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web应用服务器。

本章作为本书的第1章,简要回顾了Java Web应用的历史、技术发展概况,以及Tomcat如何融入到这个技术发展过程中。通过本章的学习,读者能够了解Tomcat的体系结构、Tomcat新的版本特征,以及Tomcat与其他Web服务器、应用服务器的区别。

本章主要内容包括动态页面技术的基本知识、Tomcat有哪些新的特性、Tomcat的体系结构,以及如何区分Tomcat与Web服务器、应用服务器的关系。

1.1 Java Web应用简介

在Sun的Java Servlet规范中,对Java Web应用做了这样的定义:“Java Web应用由一组Servlet、HTML页面、类,以及其他可以被绑定的资源构成。它可以在第三方供应商提供的实现Servlet规范的Web应用容器中运行。”Java Web应用的主要特征之一就是与ServletContext的关联。每个Web应用都有且只有一个ServletContext。当Java Web应用运行时,Servlet容器为每个Web应用创建唯一的ServletContext对象,使得它能被同一个Web应用中的所有组件共享。Servlet容器(例如Tomcat)控制这种关联,并且保证在ServletContext中存储对象时,不会发生冲突。在Java Web应用中可以包含如下内容:

● Servlet

● JSP

● 实用类

● 静态文档,如HTML、图片等

● 客户端类

● 描述Web应用的信息(Web.xml)

在生成一个Web应用时,第一步要做的工作就是生成Web应用的目录结构。表1-1中通过一个名为example的例子,描述了Web应用应该包含的目录结构。这些目录都应该放在Servlet容器的<SERVER_ROOT>目录下,比如在Tomcat中就是%CATALINA_HOME%/webapps。

表1-1 Web应用目录结构

从目录结构中可以看到,对于一个Web应用来说,classes既可以放置在/WEB-INF/classes目录下,也可以放置在/WEB-INF/lib目录下。对于类加载器来说,将首先从/classes目录里加载类,然后再从/lib目录加载。如果在这两个目录中放置了同样的类文件,则/classes目录里面的类被加载使用。

所有Web应用的核心就是它的部署描述符。部署描述符是一个XML文件,命名为web.xml,存放在/<SERVER-ROOT>/applicationname/WEB-INF/目录下。它描述整个Web应用的配置信息。针对上面的案例来说,web.xml存放在/<SERVER-ROOT>/example/WEB-INF目录下。部署描述符主要包含以下描述信息:

● ServletContext初始化参数

● 本地目录

● 会话配置

● Servlet/JSP定义

● Servlet/JSP映射

● MIME类型映射

● 欢迎文件列表

● 错误页面

● 安全

1.1.1 Java API

Tomcat作为Servlet容器,是Java 2企业版平台(J2EE)中的关键组件。J2EE定义了一组基于Java的API,满足生成企业级的Web应用。无论企业的大小,都可以使用J2EE技术,但是J2EE的目标是为了解决大的软件系统带来的问题。J2EE建立在Java 2标准版之上(J2SE),J2SE包含了Java二进制代码(例如JVM和字节码编译器),以及核心的Java代码库。J2EE依赖J2SE的功能。J2EE和J2SE都包含在http://Java.sun.com,且都作为应用程序能够基于的平台选择种类。

正如上面所述,J2EE是Java API的标准集合。应用程序接口(API)用于软件开发人员描述服务商所提供的服务接口。在Java中,API用于描述Java虚拟机(JVM)及其代码库所能提供的服务接口。Java中的API都由Java标准制定组织Java Community Process(JCP)来维护。JCP是一个开放的国际组织,主要由Java开发者,以及被授权者组成,职能是发展和更新Java技术规范、参考实现(RI)、技术兼容包(TCK)。Java技术和JCP两者的原创者都是Sun计算机公司。然而,JCP已经由Sun于1995年创造Java的非正式程序,演进到如今有数百名来自世界各地Java代表成员一同监督Java发展的正式程序。

JCP维护的规范包括J2ME,J2SE,JavaEE,XML,OSS和JAIN等。组织成员可以提交JCR(Java Specification Requests),通过特定程序以后,进入到下一版本的规范里面。

所有声称符合JavaEE规范的JavaEE类产品(应用服务器、应用软件、开发工具等),必须通过该组织提供的TCK兼容性测试(需要购买测试包),通过该测试后,需要缴纳JavaEE商标使用费。完成了前述的两项工作即是通过了JavaEE认证(Authorized Java Licensees of JavaEE)。

1.1.2 J2EE API

1.J2EE 1.4简介

J2EE 1.4平台包含了众多的API,Servlet和JSP API仅仅是其中的两个。表1-2中描述了其他的J2EE API。

表1-2 J2EE包含的其他API

除了J2EE制定的API,J2EE应用也在很大程度上依赖J2SE API。近年来,J2EE API有多个已经移植到J2SE平台。一个是Java命名目录接口(JNDI),另外一个是XML处理Java API(JAXP)。J2EE和J2SE构成了企业软件开发的平台。近年来,虽然微软的.NET平台声称作为J2EE平台的替代品,然而对于.NET来说未来的路还很遥远。

2.J2EE 5简介

J2EE 5不是间接地由J2EE改名而来的,Sun对其做了重大修改,算是一种新的技术。从提交公开审查的规范草案J2EE 5来看,J2EE 5的关注重点是简化应用开发,尤其是大量采用元数据标注(annotation)和POJO(普通Java对象)驱动的开发方式,对平台进行了重新定义。对比此前的J2EE规范,J2EE 5最重要的新增特性就是Java持久化API(即EJB 3 entity bean)、JSF、JSTL等。

从整个EJB规法的角度来说,EJB 3相对于EJB 2.0的最大变更在于Entity Bean持久化API上。在EJB 3中,Entity Bean持久化已经单独作为一个Persistence API规范和其他的EJB部分分离开来。EJB 2.0模型存在一些缺陷:

(1)EJB 2.0模型要求创建多个组件接口,并实现多个不必要的回调方法。

(2)组件接口要求实现EJBObject或EJBLocalObject,以及处理许多不必要的异常。

(3)基于XML的EJB 2.0部署描述符比较复杂且容易出错。

(4)基于EJB模型的容器管理持久性在开发和管理方面过于复杂,并且失去了几个基本特性——如使用数据库序列定义主键的标准方法。

(5)EJBQL语法非常有限,而且是静态的,无法做到运行期间的动态查询。

(6)EJB 2.0组件并非是真正面向对象的,因为它们在继承和多态性方面有使用限制。

(7)查找和调用EJB 2.0是一项复杂的任务,即使是在应用程序中使用最基本的EJB也需要对JNDI有一个详细的了解。

(8)对容器的依赖使得EJB 2.0只能用于服务器组件的开发,无法实现一次编写,来进行四处运行的面向构件的开发。

所有这些复杂性和缺陷,都导致EJB 2.0的采用无法真正简化开发并提高生产力。EJB3.0旨在解决以往EJB2.0模型的复杂性和提高灵活性,具体体现在:

(1)去除了不必要的接口Remote,Home,EJB,以及回调方法实现。

(2)实体Bean采用了POJO模型,一个简单的Java bean就可以是一个Entity Bean。无需依赖容器运行和测试。

(3)全面采用O/R Mapping技术来实现数据库操作。

(4)实体Bean可以运行在所有需要持久化的应用,不管是客户端还是服务器端。从而真正实现面向构件的开发。

(5)实体Bean现在支持继承和多态性。

(6)灵活丰富的EJB3查询语言。

(7)SQL支持。

(8)使用元数据批注代替部署描述符,减少复杂性。

Java EE5作为J2EE平台诞生6年后的第4代规范,重点关注的是目前Java开发的几个热点:开发效率、运行效率和企业应用整合。目标也是让J2EE开发简单、简单再简单。J2EE 5作为新一代Java架构的规范,已经越来越受到开发者的重视。

1.1.3 CGI

Web页面并不仅仅只由静态页面组成,显示同样的页面给每个用户。许多页面内容的产生依赖于不同的浏览者。静态页面在Web应用中占有重要的位置,但是如果没有动态页面参与,很多重要的页面站点将不能良好的运行,来满足其功能需求。

通用网关接口(Common Gateway Interface CGI)是最初的动态内容机制,它在Web服务器上执行,允许网站管理员定制他们的页面。CGI模型描述如下:

(1)客户端发送请求给服务端,比如超文本链接标示语言(HTML)页面;

(2)服务器接受用户请求并交给CGI程序处理;

(3)CGI程序将处理结果传送给服务器;

(4)服务器将结果作为HTTP响应返回给用户。

CGI可以使用多种编程语言来实现,例如Perl。但是CGI不是非常有高效,每次服务端接受到请求,它都必须启动新的CGI进程来处理。在用户量不大的情况下,这个问题还不至于太明显。但是如果用户请求量较大,每次都启动新的CGI进程处理,相对服务器资源代价就会较高。

由于CGI本身的缺陷,因此许多替代方案应运而生。一般来说,在这些方案中如果提供环境存在于已经存在的服务器中或者作为服务器的功能组件的话,它将获得更大的成功。由于Apache良好的模块应用程序接口(API),许多CGI的替代品都建立在Apache服务器(www.apache.org)之上。开发者可以通过API扩展Apache的功能,而不用更改服务器本身代码。对于程序员来说,生成动态内容,不失为一个好的策略。当Apache开始传输HTTP请求给模块时,Apache加载模块到它的内存;然后只要模块处理完请求,Apache把响应返回给客户端。由于模块已经加载在服务端的内存中,因此加载解释器的开销几乎可以忽略不计,使得脚本(Scipts)执行得更快。

目前很少有开发者有能力开发类似的模块,因此许多第三方模块提供了其基本的功能,甚至比通常的CGI更加强大。以下是一些例子:

● Mod_perl:内嵌在服务器中的Perl解释器,减少了每次请求加载Perl解释器的开销。

● Mod_php4:与上面mod_perl一样,提高PHP的执行效率。

● Mod_fastcgi:驻留在内存,提高CGI的响应速度。

微软也提供了Internet信息服务(IIS)Web服务器接口,称为Internet服务应用程序接口(ISAPI)。由于IIS作为Windows操作系统的组成部分,因此IIS目前被广泛地使用。在第19章中,将会详细讲述Tomcat与IIS如何集成,如何整合利用它们最好的性能特征。

微软也开发了动态服务器主页(ASP)技术,使得用户能够嵌入Scripts脚本,比如嵌入VBScript到标准的HTML页面中。事实证明这个技术非常有效,而且对于Java Web技术起到了推进作用。

1.1.4 Servlet

Servlet是一种独立于平台和协议的服务器端的Java应用程序,可以生成动态的Web页面。Servlet是位于Web服务器内部的服务器端的Java应用程序,与传统的从命令行启动的Java应用程序相同,Servlet由Web服务器进行加载,该Web服务器必须包含支持Servlet的Java虚拟机。

现将Java Servlet与Applet技术做如下的比较:

1.相似之处

● 它们都不是独立的应用程序,没有main()方法。

● 它们都不是由用户或程序员调用,而是由另外一个应用程序(容器)调用。

● 它们都有一个生存周期,包含init()和destroy()方法。

2.不同之处

● Applet具有很好的图形界面(AWT),与浏览器一起,在客户端运行。

● Servlet则没有图形界面,运行在服务器端。

与传统的CGI和许多其他类似CGI的技术相比,Java Servlet具有更高的效率,更容易使用,功能更强大,具有更好的可移植性,更节省投资。在未来的技术发展过程中,Servlet有可能彻底取代CGI,这是因为Java Servlet相对CGI具有如下的优点:

(1)高效

在传统的CGI中,每个请求都要启动一个新的进程。如果CGI程序本身的执行时间较短,那么启动进程所需要的时间很可能超过实际执行时间。而在Servlet中,每个请求由一个轻量级的Java线程处理(而不是重量级的操作系统进程)。

在传统CGI中,如果有N个并发的对同一CGI程序的请求,则该CGI程序的代码在内存中就会重新装载了N次;而对于Servlet,处理请求的是N个线程,只需要一份Servlet类代码。在性能优化方面,Servlet也比CGI有着更多的选择。

(2)方便

Servlet提供了大量的实用工具例程,例如,自动地解析和解码HTML表单数据、读取和设置HTTP头、处理Cookie、跟踪会话状态等。

(3)功能强大

在Servlet中,许多使用传统CGI程序很难完成的任务都可以轻松地完成。例如,Servlet能够直接和Web服务器交互。而普通的CGI程序不能。Servlet还能够在各个程序之间共享数据,使得数据库链接池之类的功能很容易实现。

(4)可移植性好

Servlet用Java编写,Servlet API具有完善的标准。因此,为IPlanet Enterprise Server写的Servlet无须任何实质上的改动即可移植到Apache、Microsoft IIS或者WebStar,几乎所有主流服务器都直接或通过插件支持Servlet。

(5)节省投资

不仅有许多廉价甚至免费的Web服务器可供个人或小规模网站使用,而且对于现有的服务器,如果它不支持Servlet的话,要加上这部分功能也往往是免费的(或只需要极少的投资)。

Java Server Pages(JSP)是一种实现普通静态HTML和动态HTML混合编码的技术,JSP并没有增加任何本质上不能用Servlet实现的功能。但是,在JSP中编写静态HTML更加方便,不必再用println语句来输出每一行HTML代码。更重要的是,借助内容和外观的分离,页面制作中不同性质的任务可以方便地分开:比如,由页面设计者进行HTML设计,同时留出供Servlet程序员插入动态内容的空间。

如果对于写过Applet程序的人来说,相信写Servlet程序并不难,甚至更为简单。因为Servlet没有图形界面,写起来与传统的文字界面程序一样简单。与Applet一样,在Servlet中一样定义了一个生命周期:

(6)初始化时期

与Applet相似,在Servlet中,也有一个Init()方法

Public void init(ServletConfig config) throws ServletException
{
    Super.init();//做一些初始化动作
}

当Servlet被Servlet引擎加载后,接下来就会执行init()方法,因此我们可以重载init()方法,用于完成一些所需要的初始化动作。比如打开文件,读取设定的默认值,以及建立一个链接池(Connection Pool)等。但是不要忘记,自己的Init()执行完后,要记得调用super.init(),以免有些系统的初始化被不小心省略掉了。

(7)执行时期

提供了一些与HTTP协议对应的有关方法。因为它是抽象类别,所以必须继承它,然后重载该方法。执行时期分为数类,分别是对应HTTP方法中的Get,Post等方法,例如doGet()对应到Get或doPost()对应到Post方法。以doGet()为例,如果浏览器传过来的是Get请求模式,那么就会执行doGet()方法。同样地,doPost()方法也就是在HTML Form传过来的Post请求时执行。如果对HTTP协议不是很了解,那么请参阅相关书籍和资料。

(8)结束时期

在Init()方法中,开启了某些资源。当网页服务器系统要重新启动,或是要回收资源时,就会调用destroy()这个方法,执行这个最后的部分。但是同样也要记得调用super.destroy()方法。

(9)执行架构

Servlet属多线程执行方式,同一时间会有多个线程处理对应的客户端的请求,因此它的service()方法会被同时调用。从图1-1中可以看到,其中的Init()与destroy()方法永远只会执行一次,因为即使是多线程方式执行,Servlet的实体还是只有一个,故初始化与结束仅需一次即可。这是Servlet引擎管理的,Servlet引擎会保证这样的执行结果。

图1-1 Servlet执行架构

2005年9月26日,Sun公司和JSR154的专家组发布了Servlet API的一个新的版本。在一般情况下,一个JSR的新版本仅仅就是对以前少数有名无实的规范进行去除更新。但这次,新版本中增加了新的特征,它们对Servlets的产生了重要影响,使得Servlet的版本升到了2.5。

Servlet 2.5的一些变化,包括它基于最新的J2SE 5.0开发的;支持annotations;Web.xml中的配置更加方便;去除了少数的限制;优化了一些实例等等。

从一开始,Servlet 2.5规范就列出J2SE 5.0(JDK 1.5)作为它最小的平台要求。它使得Servlet 2.5只能适用基于J2SE 5.0开发的平台,这个变动意味着所有J2SE5.0的新特性都可以保证对Servlet 2.5程序员有用。

在传统意义上,Servlet和J2EE版本一直与JDK的版本保持同步发展。但是,这次Servlet的版本跳过了1.4版本。专家组认为版本的加速增长是正常的,因为J2SE 5.0提出了一个引人注目的、Servlet和JEE规范都要利用的特征——Annotations。

Annotations是作为JSR175的一部分(一种为Java语言设计提供便利的Metadata)提出的一种新的语言特色。它是利用Metadata为Java编码结构(类、方法、域等)装饰的一种机制。它不能像代码那样执行,但是可以用于标记代码。这个过程是基于Metadata信息的代码处理机,通过更新它们的事件行为来实现的。

Annotations可以凭借不同的技巧来注释类和方法,例如连续地标记接口或者是@deprecated Javadoc评论。这种新式的Metadata可以便利地提供一种标准的机制来实现注释功能,以及通过库来创建用户自己的注释类型的变量。

下面是一个简单的Web service注释例子:

import Javax.jws.WebService;
import Javax.jws.WebMethod;
@WebService
public class HelloWorldService {
@WebMethod
public String helloWorld() {
  return "Hello World!";
 }
}

@WebService和@WebMethod这两个注释类型,在JSR181(为Java平台提供的Web ServicesMetadata)有详细说明,可以像类一样的引用,标记这个类作为一个Web service并且标记它的helloWorld()方法作为一个Web service方法。对于它们本身来说,注释只是写在那里并没有什么作用,好像在岗位上做记录一样。但是,一个容器一旦加载这个类并对那些注释进行二进制编码,就可以把这个类连到Web service上。

注释可以接受属性/值这些参数。它保存着参数的信息并且可以利用这些参数来更改被请求的事件行为。例如下面更高级的注释例子:

@WebService(
 name = "PingService",
  targetNamespace=http://acme.com/ping
)
@SOAPBinding(
  style=SOAPBinding.Style.RPC,
  use=SOAPBinding.Use.LITERAL
)
public class Ping {
  @WebMethod(operationName = "Foo")
  public void foo() { }
}

一旦加载了这个类,一个正确配置的容器就会识别出注释及其参数,并将此作为一个PingService,然后将它通过利用remote-procedure-call/literal的编码方式与一个Foo operation相连。实际上,注释就是指明了类和类的容器之间的联系。

不论使用注释与否,即使在不使用时——它对于理解服务器上程序的执行依然有着重要意义。为了让服务器识别类中的注释,它必须加载这些类,这就意味着服务器必须是启动着的。服务器通过WEB-INF/classes目录下和WEB-INF/lib目录下的所有类文件来查找注释。(在任何规范下,服务器都只需查找这两个目录。)可以通过下面的方法指明<Web-app>根的属性而不必使用任何注释:

<Web-app xmlns=http://Java.sun.com/xml/ns/Javaee
          version="2.5" full="true">
</Web-app>

Servlet 2.5还为Web.xml引入了几个小的变动,使得它更加方便。

首先,当写<filter-mapping>,可以在<Servlet-name>标签中使用*号来代表所有的Servlets。而以前,必须一次把一个Servlet绑定到过滤器上,像这样:

<filter-mapping>
  <filter-name>Image Filter</filter-name>
<Servlet-name>ImageServlet</Servlet-name>
</filter-mapping>

现在就可以一次绑定所有的Servlets:

<filter-mapping>
  <filter-name>Image Filter</filter-name>
  <Servlet-name>*</Servlet-name> <!-- 新特征 -->
</filter-mapping>

这有很大的用途,例如:

<filter-mapping>
  <filter-name>Dispatch Filter</filter-name>
  <Servlet-name>*</Servlet-name>
  <dispatcher>FORWARD</dispatcher>
</filter-mapping>

其次,当写<Servlet-mapping> 或者 <filter-mapping>时,可以在同一标签中采用复合匹配的标准。以前一个<Servlet-mapping>只支持一个<url-pattern>元素,现在它可以支持更多个元素,例如:

<Servlet-mapping>
  <Servlet-name>color</Servlet-name>
  <url-pattern>/color/*</url-pattern>
  <url-pattern>/colour/*</url-pattern>
</Servlet-mapping>

同样地,以前<filter-mapping>也是只支持一个<url-pattern> 或者一个 <Servlet-name>,现在它都可以支持任意多个元素:

<filter-mapping>
  <filter-name>Multipe Mappings Filter</filter-name>
  <url-pattern>/foo/*</url-pattern>
  <Servlet-name>Servlet1</Servlet-name>
  <Servlet-name>Servlet2</Servlet-name>
  <url-pattern>/bar/*</url-pattern>
</filter-mapping>

Servlet 2.5还可以将合法的HTTP/1.1方法名放进<http-method>元素中。当使用这些方法时,<http-method>将指明<security-constraint>标记里的方法应该被应用。从以前来看,它仅限于HTTP/1.1的7个标准方法:GET,POST,PUT,DELETE,HEAD,OPTIONS和TRACE。现在,HTTP/1.1允许对方法进行扩展,WebDAV(Web-based Distributed Authoring and Versioning)就是用于这种扩展的普遍技术。在Servlet 2.5中,你可以安全地约束任何可能的HTTP方法名、标准及扩展,包括WebDAV方法,例如LOCK,UNLOCK,COPY及MOVE。

当需要写一个WebDAV的Servlet时,不再必须使用doLock()和doCopy()方法,而只需写自己的service()方法及分派request.getMethod()方法。正是由于这种变化,工作人员不必再考虑系统的安全性。

Servlet 2.5去除了关于错误处理和回话跟踪的一些限制。对于错误处理,在Servlet 2.5之前,配置在<error-page>中的错误处理页面不能通过调用setStatus()方法来修改触发它们的错误代码。这一规范是基于这样的观点,即错误页面的工作是指出每个错误而不是修改错误。但是,在实际使用中,错误页面不能只是用于指出错误,而是还能做更多的事情,甚至可以代替在线帮助来帮助用户解决问题。于是,Servlet 2.5减弱了这一规范,这一规范也将不再限制错误页面所产生的反馈信息。

对于会话跟踪,在Servlet 2.5之前,调用RequestDispatcher.include()的Servlet不能设置响应的标题头,而又是Servlet 2.5减弱了这一规范。原规范的目的是使内部的Servlets限制在自己的页面空间中,不可以影响外部的页面。现在这个规范已经被减弱,就允许在内部的Servlet中使用request.getSession()命令,这样这个命令就可以悄悄地创建一个会话跟踪Cookie的标题头。虽然在逻辑上要求限制内部的资源,但在逻辑上也要求这些限制不应该取消其启动Session的功能。这个变动对于Portlet规范来说显得尤其重要。其作用是:如果响应已经有效,则getSession()命令就会抛出一个IllegalStateException9(异常)。而在此之前,就没有这个功能。

Servlet 2.4规范规定响应在这几种情况下应该是有效的,在响应的setContentLength方法中内容已经明确说明,以及内容已经写进了响应中。这种情况只有您的代码像下面这样才可以使响应重新定向:

response.setHeader("Host", "localhost");
response.setHeader("Pragma", "no-cache");
response.setHeader("Content-Length", "0");
response.setHeader("Location", "http://www.apache.org");

Servlet技术忽略特定区域的标题头,因为内容满足0字节长度,响应就会立即生效。而在它开始之前,响应就已失效了!Servlet容器通常拒绝执行这种行为,而Servlet 2.5版本增加了“长度必须大于0”的这个原则。

Servlet 2.4规范规定必须在调用request.getReader()方法之前调用request.setCharacterEncoding()方法。但是,如果你忽略这个原则而在其之后去调用request.setCharacterEncoding()方法,那么会产生什么样的后果,这个问题在规范里并没有说明。为了简便起见,现在排除这种情况!

Cross-context sessions(不同上下文目录间的会话)

最近,关于Cross-context会话处理的规则已经明确说明。当Servlets指派从一个上下文到其他上下文的请求时,这个规则就发挥了作用——在目标调用过程中,包括哪些会话。这个版本的出现使得一个上下文目录主页里的Portlets可以通过几种内部的命令来对别的上下文目录里的Portlets起作用。Servlet 2.5明确指出一个上下文目录里的资源可以访问其他上下文目录的Session(会话),而不用考虑这个请求从哪里开始的。这意味着Portlets可以脱离主页的范围而在自己的范围里运行,而且这个规范还会应用在不兼容的Serlvet容器中。

由于Servlet 2.5版本保持了一些原来的性质,几个大的概念不得不延后到下一个阶段。它们包括:

● 新的输入/输出(NIO)支持:使Servlets进行客户端通信成为可能。

● 过滤器wrap-under或wrap-over语义:有时用过滤器包装请求,或者响应对象去修改方法行为或者启用新的方法。当把这种包装和服务器对请求和响应的包装结合起来时,又应该怎么包装在一起呢?

● 用于欢迎的Servlets文件:作为索引应该充当欢迎作用的文件吗?在此之前,这个回答是肯定的。但是规范没有明确地说明如何使用这个功能,尤其在没有索引的情况下。

● 用于欢迎的文件的分派规则:如何分派欢迎文件,这个细节并没有完全说明,而是遗留了一些开放的缺口来应对不兼容问题。

● 登录后选择默认页面:如果用户通过他们的书签访问Servlet的登录页面,那么在成功登录后页面应该转向哪里呢?这个问题至今尚未明确说明。

● 用户的主题日志:在通过网站正确地注册之后,不通过传统地登录方式没有办法使Servlet信任用户。

如果抛开注释来看Servlet 2.5的变化,可见在配置文件Web.xml中去除了一些限制,同时又优化了实例行为,使其更适合、更便于开发Web系统(网页)。

Servlet 2.5中注释的作用也有所变化。Servlets本身并不能声明注释类型的变量,甚至性能弱的Servlet容器都不支持注释。然而在J2EE5环境下的Servlets编写者可以看到,通过公共的注释及EJB3.0和JAX-WS2.0规范而引入的注释类型会对代码产生很大变化,并且这也将对Servlet如何管理外部资源、对象的持久化及EJB的构成产生重大影响。

Servlet尽管在性能和服务端负载方面超越了CGI,但是它仍然有自己的缺点:

● 在复杂的HTML网页中加入动态部分,如果用Servlet来处理的话,编写代码的工作量将相当之大。

● 由于在程序中的硬编码,使得应用程序维护性极差。因为如果在HTML中修改文本内容,则Servlet必须重新编译。

● Servlet要求页面设计人员必须对Java有足够的了解。

正是由于Servlet存在上面的问题,才导致了JSP技术的出现。

1.1.5 JSP

JSP(Java Server Pages)是由Sun公司倡导、许多公司参与一起建立的一种动态网页技术标准,实现了普通静态HTML和动态HTML混合编码的技术。JSP是在服务器端建立的动态网页,更明确地说,JSP是能在Web服务器端整个Java语言至HTML网页的环境中,利用HTML网页内含的Java程序代码取代原有的CGI、ISAPI或者IDC的程序,以便执行原有CGI/WinCGI、ISAPI的功能。许多由CGI程序生成的页面大部分仍旧是静态HTML,动态内容只在页面中有限的几个部分出现。但是包括Servlet在内的大多数CGI技术及其变种,总是通过程序生成整个页面,JSP技术可以分别创建这两个部分。

现将JSP与ASP、PHP技术相比较,应会发现有如下的优点。

● 将内容的生成和显示进行分离

使用JSP技术,Web页面开发人员可以使用HTML或者XML标识来设计和格式化最终页面。使用JSP标识或者小脚本来生成页面上的动态内容,其生成的内容的逻辑被封装在标识和JavaBeans组件中,并且捆绑在小脚本中,所有的脚本在服务器端运行。因为核心逻辑被封装在标识和Beans中,所以其他人,如Web管理人员和页面设计者,能够编辑和使用JSP页面,而不影响内容的生成。在服务器端,JSP引擎解释JSP标识和小脚本,生成所请求的内容(例如:通过访问JavaBeans组件、使用JDBC技术访问数据库等),并且将结果以HTML(或者XML)页面的形式发送至浏览器。这有助于开发者既保护自己的代码,又保证任何基于HTML的Web浏览器的完全可用性。

● 强调可重用的组件

绝大多数的JSP页面依赖于可重用的、跨平台的组件(JavaBeans或者Enterprise JavaBean组件)来执行应用程序所要求的更为复杂的操作。开发人员能够共享和交换执行普通操作的组件,使得这些组件为更多的使用者或者客户团体所使用。基于组件的方法加速了总体开发过程,使得各种组织在他们现有的技能和优化结果的开发努力中得到平衡。

● 采用标签简化页面开发

Web页面开发人员不会都是熟悉脚本语言的编程人员。JSP技术封装了许多功能,这些功能是在生成易用的、与JSP相关的XML标识的动态内容时所需要的。标准的JSP标识能够访问和实例化JavaBeans组件、设置或者检索组件属性、下载Applet,以及执行用其他方法更难于编码和耗时的功能。

通过开发定制标签库,JSP技术是可以扩展的。今后第三方开发人员和其他人员可以为常用功能创建自己的标签库。这使得Web页面开发人员能够使用如同标签一样的工具来执行特定功能。

● 健壮性与安全性

由于JSP页面的内置脚本语言是基于Java编程语言的,而且所有的JSP页面都被编译为Java Servlet,JSP页面就具有Java技术的所有好处,包括健壮的存储管理和安全性。

● 良好的移植性

作为Java平台的一部分,JSP拥有Java编程语言“一次编写,各处运行”的特点。随着越来越多的供应商将JSP支持添加到他们的产品中,可以使用自己所选择的服务器和工具,而且更改工具和服务器并不影响当前的应用。

● 企业级的扩展性和性能

当与Java 2平台、企业版(J2EE)和Enterprise JavaBeans技术整合时,JSP页面将具有更好的扩展性和性能。

JSP并没有增加任何本质上不能用Servlet实现的功能。但是,在JSP中编写静态HTML更加方便,不必再用Println语句来输出每一行HTML代码。更重要的是,借助内容和外观的分离,页面制作中不同性质的任务可以方便地分开。比如,由页面设计专家进行HTML设计,同时留出供Servlet程序员插入动态内容的空间。

SSI是一种受到广泛支持的在静态HTML中引入外部代码的技术。JSP在这方面的支持更为完善,因为它可以用Servlet而不是独立的程序来生成动态内容。另外,SSI实际上只用于简单的包含,而不是面向那些能够处理表单数据、访问数据库的“真正的”程序。

JavaScript能够在客户端动态地生成HTML。虽然JavaScript很有用,但它只能处理以客户端环境为基础的动态信息。除了Cookie之外,HTTP状态和表单提交数据对JavaScript来说都是不可用的。另外,由于是在客户端运行,JavaScript不能访问服务器端资源,比如数据库、目录信息等。

2006年Sun发布了JSP和JSF新技术规范,其中最重要的一点是两者将表达式语言(Expression Language,EL)部分合二为一。在不久的将来,这两种技术有可能更进一步地彼此融合,成为一种统一的表现层技术。JSP 2.1把Expression Language(EL)输出到它自己各自分离的文档中,在技术上,这些文档是JSP规范的子文档。这些统一的EL规范定义了一个更高层的Java包——Javax.el。这个包与使用它的技术之间完全独立,并且允许此技术将自身插入EL处理过程。更改的JSP规范遵从使用标准化EL的规范。对于前面提到的JSR-252,这个规范并没什么新特性。Faces 1.2支持新的标准化EL,还包含一些Bug修复的相关规范。

Faces和JSP在JSRs下的结盟带来了一些新功能,也为将来的发展打下了坚实的基础。例如,在同时使用Faces和JSP的Web应用中,网页仅使用JSP(不包含任何Faces内容)来访问Managed Beans成为可能。在JSP规范的附录E中和Faces规范的前言中都可以看到更改内容的细节。

1.1.6 JSP标签库

JSP技术中,actions是一系列元素的集合,包括生成、访问程序语言对象,影响输出流。JSP规范中定义了6个标准actions,除了这些标准actions,JSP技术也支持可重用组件,称为自定义actions。在JSP页面中,actions通过自定义标签来触发。一个标签库是自定义标签的集合,是一种通过JavaBean生成基于XML的脚本的方法。从概念上讲,标签就是很简单而且可重用的代码结构。下面的JSP文件是引入了标签库后的代码:

<% @ page language =”Java ” %>
<html>
<head>
    <title>Hello World</title>
</head>
<body>
    <app: HelloWorld/>
</body>
</html>

相对于没有采用标签库的JSP文件代码:

<% @ page language =”Java ” %>
<html>
<head>
    <title>Hello World</title>
</head>
<body>
<%
String message = request.getAttribute(“message”);
if (message == null || message.equals (“”))
{
message = “Hello World”;
}
%><%=message%>
</body>
</html>

可以看到一些改进。一个类似HTML标签封装了整个功能。实际上,越复杂的应用程序,采用JSP标签越能提高程序的可读性。每个标签都有一个相对应的包含代码的Java类。标签都是成对出现,一个开始标签紧接着就是一个结束标签。例如:

<aTag> Something here </aTag>

标签生命周期包含:当遇到开始标签时,称为doStartTag()方法和一个doEngTag()方法,以及一个为下一次请求做准备,重设所有状态的方法。

自定义标签库封装了可重用的任务,因此它们在多个应用中被使用。精通Java语言的开发者生成JSP标签库,Web应用设计人员使用标签库,专注于表示层的显示,而不需要关注具体的细节。

标签库的特征如下:

● 能通过调用的页面传递的属性来定制。

● 能访问JSP页面中所允许的所有对象。

● 能修改调用页面的响应。

● 能相互通信。

● 能相互嵌套,支持复杂的JSP页面交互。

1.1.7 JSP EL

JSP EL(Exression Language)表达式语言,是包含在JSTL(JavaServer Page Standard Library)1.0的一个简单的资料存取与运算的语言。自从JSP2.0后,则纳入了JSP正式标准,称为JSP所支持的特性之一。JSP Exression Language定义了变量存取、运算、函数等内容,配合JSTL其他标签或流程控制标签,就可以实现更好的逻辑视图分离之目的。例如:下面是一个JSP网页利用Exression Language来计算使用者所请求的两个数字相加结果:

<html>
    <head><title>EL Test</title>
    </head>
    <body>
          简单的EL运算
          <H1>${param.a}+${param.b}=${param.a+param.b}</H1>
    </body>
</html>

如果使用表单或直接在网址上传入a与b的值,例如:http://localhost:8080/myjsp/elTest.jsp?a=10&b =14则会取得下面的结果:

<html>
<head><title>EL Test</title></head>
<body>
          简单的EL运算:
          <H1> 10 + 14 = 24 </H2>
</body>
</html>

在这个简单的例子中,可以看到Expression Language是使用 ${ 与 } 来包括所要存取的隐含对象、变量与其进行运算,param是Expression Language的隐含对象,表示使用者的请求参数,param.a表示取得使用者请求参数a的值。大致而言,Expression Language中的每一个隐含对象,其访问的数据与作用范围对应于JSP隐含对象。至于+则是Expression Language中定义的操作符,EL操作符同一般的程式语言一样,提供有算术运算、逻辑运算、关系运算等运算符。

1.1.8 Servlet容器介绍

Servlet容器也叫做Servlet引擎,是Web服务器或应用程序服务器的一部分,用于在发送的请求和响应之上提供网络服务,解码基于MIME的请求,格式化基于MIME的响应。Servlet容器在Servlet的生命周期内包容和管理Servlet。

根据Servlet容器工作模式的不同,可以将Servlet容器分为以下3类。

(1)独立的Servlet容器

当使用基于Java技术的Web服务器时,Servlet容器作为构成Web服务器的一部分而存在。然而大多数的Web服务器并非基于Java,因此,就有了下面两种容器的工作模式。

(2)进程内的Servlet容器

Servlet容器由Web服务器插件和Java容器两部分的实现组成。Web服务器插件在某个Web服务器内部地址空间中打开一个JVM(Java虚拟机),使得Java容器可以在此JVM中加载并运行Servlet。如有客户端调用Servlet的请求到来,插件取得对此请求的控制并将它传递(使用JNI技术)给Java容器,然后由Java容器将此请求交由Servlet进行处理。进程内的Servlet容器对于单进程、多线程的服务器非常适合,提供了较高的运行速度,但伸缩性有所不足。

(3)进程外的Servlet容器

Servlet容器运行于Web服务器之外的地址空间,它也是由Web服务器插件和Java容器两部分的实现组成的。Web服务器插件和Java容器(在外部JVM中运行)使用IPC机制(通常是TCP/IP)进行通信。当一个调用Servlet的请求到达时,插件取得对此请求的控制并将其传递(使用IPC机制)给Java容器。进程外Servlet容器对客户请求的响应速度不如进程内的Servlet容器,但进程外容器具有更好的伸缩性和稳定性。

Tomcat作为一个免费的开源Web服务器,它是Apache软件基金会(Apache Software Foundation)的Jakarta项目中的一个核心项目,由Apache、Sun和其他公司及个人共同开发而成。由于有了Sun的参与和支持,最新的Servlet和JSP规范总是能在Tomcat中得到及时地体现。因为Tomcat技术先进、性能稳定,并且免费,所以深受Java爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web服务器。

1.1.9 选用合适的Web技术

JSP作为J2EE的一部分,既可以用于开发小型的Web站点,也可以用来开发大型的、企业级的应用程序。到底如何选用合适的Web技术来开发自己的站点,本节着重讲述对于不同规模的Web系统,使用JSP进行开发的不同方式。

1.直接使用JSP

对于最小型的Web站点来说,可以直接使用JSP来构建动态网页。这种站点最为简单,所需要的也是简单的留言板、动态日期等基本的功能。对于这种开发模式,一般可以将所有的动态处理部分都放置在JSP的Scriptlet中。

这种结构的优点就是编程简单,成本很低。允许页面的设计者根据资源的状态、动态来生成页面的内容。但是当系统规模增大的时候,这样的结构不适合多个客户同时访问资源,因为同时会有大量的请求需要服务端来处理。每个请求都会建立一个链接,消耗一定的资源。这样,就需要让这些链接共享一些资源。其中最明显的例子就是用JDBC链接数据库中用到的链接池(Connection pools)。另外,该结构也会导致JSP中出现大量的JAVA代码。这虽然对Java程序设计人员来说不会有什么问题,可是大量的代码分散在JSP中,不利于维护和修改。

2.JSP+JavaBeans(Model 1)

中型站点面对的是数据库查询、用户管理和小量的商业业务逻辑。对于这种站点,不能将所有的东西全部交给JSP页面来处理。在单纯的JSP中加入JavaBeans技术,将有助于这种中型网站的开发。利用JavaBeans将很容易完成如数据库链接、用户登录与注销、商业业务逻辑封装的任务。例如:将常用的数据库链接写成一个JavaBeans,既方便了使用,又可以使JSP文件简单而清晰。通过封装,还可以防止一般开发人员直接获得访问数据库的权限。

3.JSP+JavaBeans+Servlet

无论用ASP还是PHP开发动态网站,长期以来都有一个比较重要的问题,就是网站的逻辑关系和网站的显示页面不容易分开。这使得代码的可读性和可维护性不高。另一方面,动态Web的开发人员也在抱怨,将网站美工设计的静态页面和动态程序合并过程是一个异常痛苦的过程。

如何解决这个问题呢?JSP问世后,有些人认为Servlet已经完全可以被JSP代替。然而,事实是在Servlet不再担负动态页面生成的任务以后,开始担负起决定整个网站逻辑流程的任务。在逻辑关系异常复杂的网站中,借助于Servlet与JSP良好的交互关系和JavaBeans的协助,完全可以将网站的整个逻辑结构放在Servlet中,而将动态页面的输入放在JSP页面中来完成。在这种开发方式中,一个网站可以有一个或几个核心的Servlet来处理网站的逻辑,通过调用JSP页面来完成客户端的请求。读者在后面将可以看到,在J2EE模型中,Servlet的这项功能可以被EJB等取代。

4.MVC开发模型

在MVC开发模型中,整个系统可以分为三个主要的部分:

(1)视图

视图就是用户界面部分,在Web应用程序中也就是HTML、XML、JSP页面。这个部分主要处理用户能看到的东西,动态的JSP部分处理了用户可以看见的动态网页,而静态网页则由HTML、XML输出。

(2)控制器

控制器负责网站的整个逻辑。它用于管理用户与视图发生的交互。读者可以将控制器想象成处在视图和数据之间,对视图与模型交互进行管理的部分。通过使视图完全独立于控制器和模型,就可以轻松替换前端客户程序,也就是说,网页制作人员可以独立自由改变Web页面而不用担心影响这个基于Web应用程序的功能。

在J2EE中,控制器的功能一般是由Servlet、JavaBeans、Enterprise JavaBeans中的SessionBeans来担当。

图1-2 MVC体系结构

MVC的优点表现在以下几个方面:

● 可以为一个模型在运行时同时建立和使用多个视图。变化-传播机制可以确保所有相关的视图得到及时的模型数据变化,从而使所有关联的视图和控制器做到行为同步。

● 视图与控制器的可接插性,允许更换视图和控制器对象,而且可以根据需求动态地打开或关闭、甚至在运行期间进行对象替换。

● 模型的可移植性。因为模型是独立于视图的,所以可以把一个模型独立地移植到新的平台工作。需要做的只是在新平台上对视图和控制器进行新的修改。

● 潜在的框架结构。可以基于此模型建立应用程序框架,不仅仅是用在设计界面的设计中。

MVC的不足之处表现在以下几个方面:

● 增加了系统结构和实现的复杂性。对于简单的界面,严格遵循MVC,使模型、视图与控制器分离,会增加结构的复杂性,并可能产生过多的更新操作,降低运行效率。

● 视图与控制器间的过于紧密的链接。视图与控制器是相互分离,但确实联系紧密的部件。视图没有控制器的存在,其应用是很有限的,反之亦然。这样就妨碍了它们的独立重用。

● 视图对模型数据的低效率访问。依据模型操作接口的不同,视图可能需要多次调用才能获得足够的显示数据。对未变化数据的不必要的频繁访问,也将损害操作性能。

1.2 Tomcat体系结构介绍

Tomcat目前最新的版本是6.0,支持Servlet 2.5和JSP2.1规范。它由一系列嵌套的组件组成。

● 顶层组件:位于整个配置文件的顶层。

● 链接器:链接代表了介于客户与服务之间的通信接口,负责将客户的请求发送给服务器,并将服务器的响应结果传递给客户。

● 容器组件:包含了其他组件的集合。

● 嵌套组件:可以加入到容器中的组件,但不能包含其他组件。

图1-3描述了Tomcat配置的结构。

图1-3 Tomcat配置体系结构图

当配置Tomcat时,可以移除一些不需要的对象,但并不会影响服务。一般来说,如果使用Web服务器集成的话,如Apache,则引擎和主机组件是不必要的。Tomcat的组件都是可以在server.xml文件中进行配置的,每个Tomcat组件在Server.xml文件中对应一种配置元素。在第三章中,将会详细讲述Servel.xml文件配置,现在主要对Tomcat的基本组件进行介绍。

1.顶层组件

顶层组件包含Server组件和Service组件。Server组件是Tomcat服务器的实例,可以在Java虚拟机(JVM)中生成唯一的服务器实例。它还可以在一个服务器中,为不同的端口设置单独的服务配置。这样,既方便单独地重启应用程序,又可以在某特定的JVM崩溃时,确保其他实例上的应用程序是安全的。Service组件用来访问请求,把请求转发给合适的Web应用程序,然后返回请求的处理结果;与它的链接器组成引擎组件。引擎也就是Servlet引擎,是请求处理的组件。引擎检查HTTP头,然后决定传送给哪个主机或者应用程序。每个Service都被命名,方便管理员能够通过日志记录每个Service的信息。

2.链接器组件

链接器链接Web应用程序和客户端,代表和客户端实际交互的组件。它负责接受来自客户端的请求,以及向客户返回响应结果。Tomcat的默认端口是8080,为了避免与其他的Web服务器标准端口(80)相冲突。比较常见的链接器是HTTP connector和Apache JServ Protocl(AJP)connector。

3.容器组件

容器组件负责接受来自顶层组件的请求,然后处理这些请求,并把处理结果返回给上层组件。容器组件包括引擎组件(Engine Component)、主机组件(Host Component)和上下文组件(Context Component)。引擎组件负责接受和处理来自它所属的Service中的所有Connector的请求。每个Service组件只能包含一个引擎组件。主机组件定义了一个虚拟主机,它允许在同一台物理机器上,配置多个Web应用;多个主机组件可以包含在引擎组件中。上下文组件是使用最为频繁的组件,每个上下文组件代表了允许在虚拟主机上的每个Web应用。一个虚拟主机能够运行多个Context,它们通过各自的Context Path进行相互区分。

4.嵌套组件

嵌套组件嵌套在容器内,为管理人员提供管理服务。包括全局资源组件(The Global Resources Component)、加载器组件(Loader Component)、日志组件(Logger Component)、管理器组件(Manager Component)、域组件(Realm Component)、资源组件(Resources Component)和阀组件(Valve Component)。

全局资源组件只能嵌套在Server组件中,用于配置server中其他组件所用到的全局JNDI资源。加载器组件只能嵌套在上下文组件中,用于指定一个Web应用程序的类加载器,并将该应用程序的类和资源加载到内存中。一般来说,Tomcat中默认的类加载器就能满足大部分的需求,因此开发人员没有必要定制自己的类加载器。日志组件能借助Log4J来实现记录日志。

管理器组件也只能在Context中有效。管理器组件是会话管理器,负责会话的创建和维护。域组件是一个包含用户名、密码和用户角色的数据库。角色与Unix的group类似。域的不同实现允许将Catalina集成到认证信息已经被创建和维护的环境中,然后利用这些信息来实现容器管理的安全性。在任何组件中(如引擎、主机或者上下文组件)都可以嵌套域组件。另外,引擎或者主机的域会自动被低层次的容器集成,除非被明确覆盖。资源组件只在上下文组件中支持,它代表的是Web应用程序中的静态资源,以及它们被允许存放的格式,例如压缩文件等。

阀组件用于在请求在被到达目的之前,截取该请求,并处理它。有点类似于Servlet规范中定义的过滤器。它是Tomcat专有的、目前还不能用于其他的Servlet/JS容器。阀组件可以嵌入到其他组件中,如引擎、主机和上下文组件。阀组件通常用于记录请求、客户端IP地址,以及服务器端利用率信息,这种技术被称为请求转储(Request Dumping)。一个请求转储阀记录HTTP头的信息和Cookies信息。响应转储阀记录响应HTTP头和Cookies信息。阀是可重用的组件,能按照用户的需求增删。

1.3 Tomcat与应用Web服务器

1.3.1 Tomcat与应用服务器

到目前为止,Tomcat一直被认为是Servlet/JSP API的执行器,也就所谓的Servlet容器。然而,Tomcat并不仅仅如此,它还提供了JNDI和JMX API的实现机制。尽管如此,Tomcat仍然还不能算是应用服务器,因为它不提供大多数J2EE API的支持。

很有意思的是,目前许多的应用服务器通常把Tomcat作为它们Servlet和JSP API的容器。由于Tomcat允许开发者只需通过加入一行致谢,就可以把Tomcat嵌入到它们的应用中。遗憾的是,许多商业应用服务器并没有遵守此规则。

对于开发者来说,如果是为了寻找利用Servlet、JSP、JNDI和JMX技术来生成Java Web应用的话,选择Tomcat是一个优秀的解决方案;但是为了寻找支持其他的J2EE API,那么寻找一个应用服务器或者把Tomcat作为应用服务器的辅助,将是一个不错的解决方案;第三种方式是找到独立的J2EE API实现,然后把它们跟Tomcat结合起来使用。虽然整合会带来相关的问题,但是这种方式是最为有效的。

1.3.2 Tomcat与Web服务器

Tomcat是提供一个支持Servlet和JSP运行的容器。Servlet和JSP能根据实时需要,产生动态网页内容。而对于Web服务器来说,Apache仅仅支持静态网页,对于支持动态网页就会显得无能为力;Tomcat则既能为动态网页服务,同时也能为静态网页提供支持。尽管它没有通常的Web服务器快、功能也不如Web服务器丰富,但是Tomcat逐渐为支持静态内容不断扩充。大多数的Web服务器都是用底层语言编写如C,利用了相应平台的特征,因此用纯Java编写的Tomcat执行速度不可能与它们相提并论。

一般来说,大的站点都是将Tomcat与Apache的结合,Apache负责接受所有来自客户端的HTTP请求,然后将Servlets和JSP的请求转发给Tomcat来处理。Tomcat完成处理后,将响应传回给Apache,最后Apache将响应返回给客户端。

1.3.3 Tomcat 6新特征

Tomcat 6有着许多的新特征,例如支持Java 5的泛型(Generic)。相对于Tomcat 5来说,Tomcat 6支持最新的JSP 2.1规范(JSR 245)和Java Servlet 2.5规范(JSR 154)。除了支持JSP2.1外,Tomcat 6完全支持统一表达式语言(Unified EL)2.1。同时,Tomcat 6也是最先支持Java Server Faces 1.2规范的Web服务器。此外,Tomcat 6优化了内存使用,提升了IO能力,重构了集群。

1.4 小结

本章简要地回顾了Java Web的历史、技术发展状况,介绍了动态Web页面的各种类型。对于不同规模的Web系统来说,有多个开发框架可供选择:直接使用JSP、JSP+JavaBeans+Servlet、MVC模型等开发方式。

Tomcat 6作为Tomcat目前的最新版本,支持最新的Servlet 2.5和JSP 2.1规范。Tomcat由于仅仅只提供了Servlet/Jsp支持,因此它不能称为应用服务器;Tomcat既能提供静态网页支持,也能为动态网页服务,但是处理静态页面的效率没有其他的Web服务器快、功能完善。因此通常的解决方案是将Tomcat与其他J2EE应用服务器或其他的Web服务器结合起来使用。

第2章 安装Tomcat

【本章导读】

在本章中,读者将学会如何在不同操作系统上进行Tomcat的安装,以及Tomcat源码安装。同时,通过本章的学习,读者将能掌握Tomcat的安装目录结构,以及Web应用程序的目录结构。

本章主要内容有:如何在Windows和Linux中安装Tomcat,如何安装JDK,Tomcat的安装目录结构,以及Tomcat安装过程出现的问题和解决的办法。

2.1 安装JDK

Tomcat跟其他基于Java的应用程序一样,都需要Java虚拟机(JVM)的支持。Sun公司发布了免费的、针对Windows、Linux和Solaris的不同JVM版本。

2.1.1 在Windows上安装JDK

从Sun公司的网站(http://java.sun.com/javase/downloads/index.jsp)上下载最新的版本Tomcat 6。Tomcat 6虽然需要运行在JSE5.0或更高版本之上,但是它仅需要Java运行环境就可,不再像以前的版本需要完全的Java开发包。目前JDK的最新版本为JDK 6,因此下载最新的JDK 6 Update3就可以了。JDK 6 Update 3包含了Java运行环境和命令行开发工具。如图2-1所示。

图2-1 SunJDK下载页面

【例2-1】在Windows上安装JDK

在Windows上Java安装包是一个标准的Windows安装包,操作简单方便。双击jdk-6u3-windows-i586-p.exe,出现对话框,如图2-2所示。

图2-2 JDK安装许可证界面

选择【接受(A)】按钮,就会出现自定义安装对话框,如图2-3所示。

图2-3 JDK自定义安装界面

选择Java安装的目录,本书将Java安装目录改为:C:\JDK1.6。修改完后,单击【下一步】按钮,出现安装进度条,进入安装过程,安装完后会提示JDK安装完毕。然后出现JRE自定义安装对话框,如图2-4所示。

图2-4 JRE自定义安装

同样更改安装目录为c:\JRE1.6,当然用户可以根据自己的需要更改安装目录。单击【下一步】按钮,出现安装进度条,进入安装过程,安装完后会提示JRE安装完毕。如图2-5所示。

图2-5 JRE安装完成

此时Java安装完毕,下一步设置环境变量。选择Windows开始菜单栏上“开始→设置→控制面板”,然后选择“系统”选项。如图2-6所示。

图2-6 系统属性

选择“高级”标签,单击【环境变量】按钮。这时出现如图2-7所示。

图2-7 环境变量

单击系统变量【新建】按钮,输入JAVA_HOME作为变量名,然后输入Java刚刚安装的目录路径。如图2-8所示。

图2-8 添加JAVA_HOME新的环境变量

然后修改%PATH%变量,增加%JAVA_HOME%\bin路径。增加该路径,是为了使得Java能够在命令行中可以执行。如图2-9所示。

图2-9 修改PATH环境变量

验证变量是否修改成功,可以打开命令行,输入:

> java –version

应该可以看到结果,如图2-10所示。

图2-10 Java版本显示结果

至此,在Windows上Java安装完成。

2.1.2 在Linux上安装JDK

从Sun网站下载合适的Linux版本,如图2-11所示。

图2-11 Sun下载Linux版本页面

Sun提供Linux平台上JDK的两个版本Linux RPM in self-extracting file和Linux self-extracting file。这两个版本的区别在于:前者把RPM安装包封装在压缩包的二进制格式,适合低级用户安装;后者则适合高级用户,相当于一个“绿色”的zip版本JDK,没有安装程序,安装完后可能需要做一些链接。

【例2-2】在Linux上安装JDK

使用self-extracting binary安装Java,首先必须设置它的执行权限,在命令行中输入如下命令:

# chmod +x jdk-6u3-linux-i586.bin

【提示】

用self-extracting binary在Linux上安装Java时,不必设置成Root权限,因为该二进制包不会覆盖任何系统文件。

然后改变目录到需要安装的目录下(本书安装目录是/usr/java/jdk1.6),执行二进制文件,输入如下命令:

# ./ jdk-6u3-linux-i586.bin

之后会出现licence对话框,单击【agree】按钮,开始Java安装。跟Windows安装一样,必须设置$JAVA_HOME环境变量,指明JDK的安装目录。一种是修改用户所对应的~/.bashrc文件,在该文件中增加:

JAVA_HOME=/usr/java/jdk1.6/
export CLASSPATH=.
export PATH = $JAVA_HOME/bin:$PATH

另外一种是设置Linux的全局环境变量(这个需要Root权限),在/etc/profile文件增加如下几行:

JAVA_HOME=/usr/java/jdk1.6/
export JAVA_HOME
PATH=$JAVA_HOME/bin:$PATH
CLASSPATH=.:$JAVA_HOME/lin/tools.jar:$JAVA_HOME/lib/dt.jar
export PATH JAVA_HOME CLASSPATH

然后保存文件,注销当前用户。重新登录后,在控制台下输入java –version,如果出现版本信息,表明安装成功。

使用RPM包安装Java。首先必须确定是Root用户,然后在命令行中输入如下命令:

# chmod a+x jdk-6u3-linux-i586-rpm.bin
# ./ jdk-6u3-linux-i586-rpm.bin
# rpm –iv jdk-6u3-linux-i586-rpm.bin

之后,按照之前所述的修改系统环境变量,测试安装是否成功。

2.2 安装Tomcat

前面讲述了JDK的安装,现在可以开始Tomcat的安装了。本节先讲述Windows下的Tomcat安装,然后是Linux下的Tomcat安装。

2.2.1 在Windows上安装Tomcat

从Apache网站上(http://Tomcat.apache.org/download-60.cgi)下载最新的Tomcat版本,目前Apache发布的最新Tomcat版本是6.014。如图2-12所示。

图2-12 Apache网站Tomcat下载页面

在“Binary Distribution”栏的Core子栏下提供了三种Tomcat 6的方式:zip、tar.gz、Windows Service Installer。zip方式下载后得到的是一个zip文件,无须安装,解压缩后即可使用。tar.gz方式下载后得到一个tar.gz文件,是在GNU操作系统(一种类似于Unix的操作系统,其源码是可以被复制、修改和重新发布的)中用tar命令打包而成的,因此必须在与GNU相兼容的操作系统中解包,Solaris和Mac OS X操作系统中不能使用。“Windows Service Installer”方式下载后得到的是一个exe文件(如图2-12所示的版本为apache-Tomcat-6.0.14.exe)。Tomcat 6是在Windows操作系统下的安装程序,这种方式安装的Tomcat 6可以通过Windows的服务来控制启动、停止。

【例2-3】在Windows上安装Tomcat

双击下载apache-Tomcat-6.0.14.exe文件,出现安装Licence Agreement对话框,如图2-13所示。

图2-13 Tomcat安装页面License对话框

单击【I Agree】按钮,进入到Choose Component对话框,如图2-14所示。

图2-14 Tomcat自定义安装对话框

一般默认Normal即可,单击【Next】按钮进入到选择安装路径选项,如图2-15所示。

图2-15 Tomcat安装目录修改

修改安装的目录,本书Tomcat的安装目录为C:\Tomcat 6。单击选择【Next】按钮,进入到配置对话框,如图2-16所示。

图2-16 Tomcat安装配置对话框

可以修改Connector端口和管理员用户名、密码。本书使用的默认值为8080端口,管理员用户名是admin,密码为空。单击【Next】按钮,进入JVM路径选择对话框,如图2-17所示。

图2-17 Tomcat安装选择JRE安装目录

选择JDK安装的路径后,单击【Install】按钮,开始Tomcat安装,完成后会提示安装完成。

接下来设置环境变量。同JDK设置环境变量一样,在系统变量中增加一项为%CATALINA_HOME%,它表明Tomcat在本机上安装的路径。修改后如图2-18所示。

图2-18 Tomcat环境变量设置

为了测试Tomcat安装是否成功,必须运行Tomcat服务器,选择“开始→Apache Tomcat 6.0→Monitor Tomcat”,出现Tomat控制台,如图2-19所示。

图2-19 Tomcat控制台对话框

单击【Start】按钮,开始Tomcat服务。成功启动后,控制台服务状态会变成Started,如图2-20所示。

图2-20 Tomcat启动成功后对话框

Tomcat启动后,打开浏览器,输入http://localhost:8080,如果能够看到Tomcat的默认页面(如图2-21所示),则表明安装成功。

图2-21 Tomcat默认页面

2.2.2 在Linux或Mac OS上安装Tomcat

在Linux或者Mac系统上安装Tomcat也是非常简便的。基本流程为:

● 从Apache网站上(http://Tomcat.apache.org/download-60.cgi)下载Tomcat的zip格式或者gzip tar格式文件。

● 解压文件到硬盘,例如/usr/java/Tomcat 6。

● 输出$CATALINA_HOME变量,使用下列Shell命令

# CATALINA_HOME=/usr/java/Tomcat 6
# export CATALINA_HOME

类似与JDK的安装,可以把这些命令加到~/.bashrc或者/etc/profiles文件里面。

● 最后使用上面Shell命令启动Tomcat。

● 打开浏览器,输入http://localhost:8080/,查看Tomcat是否安装成功。也可以选择Tomcat中左边菜单栏的JSP例子,运行其中一个,确保Tomcat运行没有任何错误信息。

至此,Tomcat在Linux或者MAC系统上安装完毕。

2.2.3 Tomcat端口配置

Tomcat一般用8080端口作为默认端口。如果用户需要修改Tomcat的端口配置,打开%CATALINA_HOME%\conf目录下的server.xml文件,找到下面文本:

<!-- A "Connector" represents an endpoint by which requests are received
        and responses are returned. Documentation at :
        Java HTTP Connector: /docs/config/http.html (blocking & non-blocking)
        Java AJP  Connector: /docs/config/ajp.html
        APR (HTTP/AJP) Connector: /docs/apr.html
        Define a non-SSL HTTP/1.1 Connector on port 8080
    -->
    <Connector port="8080" protocol="HTTP/1.1"
              connectionTimeout="20000"
              redirectPort="8443" />

可以看到端口一项写的是8080,修改这个设置为用户定制的端口。比如将端口修改为port="80",那么重新启动Tomcat后,打开浏览器,只需输入http://localhost就可看到Tomcat的默认页面,不再像以前后面还需加上冒号和端口号。

2.2.4 安装Ant

Ant工具是Apache的一个开源项目,它是一个优秀的软件工程管理工具。Ant类似于Make工具,但克服了传统的Make工具的缺点。传统的Make往往只能在某一平台上使用,Ant本身用Java语言实现,并且使用XML格式的配置文件来构建成,可以很方便地实现多平台编译,非常适合管理大型工程。

从Ant官方网站(http://ant.apache.org/bindownload.cgi)下载最新的二进制版本。目前最新的版本为1.7.0,如图2-22所示。

图2-22 Ant下载页面

【例2-4】安装Ant

将下载的apache-ant-1.7.0-bin.zip文件解压,设置如下环境变量:

● ANT_HOME ant的安装目录(本书默认安装目录为C:\ant1.7)如图2-23所示。

图2-23 Ant安装目录变量设置

● PATH把%ANT_HOME%/bin目录添加到PATH变量中,便于命令行能直接运行Ant。如图2-24所示。

图2-24 Path变量设置

测试Ant是否安装成功,打开命令行,输入ant –version,如果能看到Ant信息,如图2-25所示,则表明Ant安装成功。

图2-25 Ant版本信息

至此,Ant安装完毕。下一节讲述如何使用Ant来安装Tomcat。

2.2.5 安装Tomcat源码

从Apache网站上(http://Tomcat.apache.org/download-60.cgi)下载最新的Tomcat源码版本,目前最新的版本为apache-Tomcat-6.0.14-src。然后执行下面操作:

● 进入到Tomcat解压目录(本书默认为c:\ apache-Tomcat-6.0.14-src)。

● 确定JDK和ANT已经安装。

● 在源码目录下新建一个build.properties文件,输入以下代码:

# ----- Proxy setup -----
  # Uncomment if using a proxy server
  #proxy.host=proxy.domain
  #proxy.port=8080
  #proxy.use=on
  # ----- Default Base Path for Dependent Packages -----
  # Replace this path with the directory path where dependencies binaries
  # should be downloaded
  base.path=/usr/share/java

● 在命令行输入命令Ant。

● 构建的过程大概会持续几分钟,最后构建好的项目存放在${Tomcat.source}\output\build目录下。当然也可以在用户指定的目录下新建目录,将编译好的Tomcat二进制代码移植过来,环境变量的设置同上。

如果用户想更新源码,并重新编译,需输入以下命令:

> ant checkout
> ant build

至此,Tomcat源码安装完毕。

2.3 Tomcat安装目录

前面介绍了Tomcat在不同平台上的安装流程,包括使用二进制版本和源码版本。现在介绍一下Tomcat的安装目录。在本节中,可以了解到Tomcat的主要配置文件,以及目录结构。Tomcat安装目录结构如图2-26所示。

图2-26 Tomcat安装目录结构

1.Bin目录

Bin目录存放着Windows平台,以及Linux平台上启动和关闭Tomcat的脚本文件。Tomcat的早期版本,有多个不同的启动和关闭脚本。Tomcat 6将这些统一到下列执行脚本中:

● Tomcat 6 Windows可执行文件

如果Tomcat安装作为NT服务的话,可以使用Tomcat 6.exe可执行文件启动服务器。

● Tomcat 6w Windows可执行文件

如果Tomcat安装作为服务的话,可以使用Tomcat 6w.exe可执行文件来启动服务器。它将调用Tomcat的控制台,可以手动启动或关闭Tomcat服务。在上节Tomcat安装中有详细介绍。

2.Conf目录

Conf目录存放在Tomcat服务器的各种配置文件,其中包括:

● Catalina.policy:为Catalina运行在安全管理的上下文中,设置必要的权限。

● Catalina.properties:设置不同类加载器目录的位置。默认的是Common目录和它的子目录。设置的目的是为了区分哪些类可以被Tomcat使用,哪些类可以被Web应用使用。

● Context.xml:设置默认的Web应用上下文。

● Logging.properties:管理默认的日志等级。

● Server.xml:是Tomcat的最为主要的配置文件。可以配置任何元素,包括日志、过滤器、端口、主机等,详细的讨论在第三章。

● Tomcat-user.xml:默认的用户数据库,用于容器认证管理。

● Web.xml:默认的Web应用程序部署描述符。

3.Logs目录

Logs目录是Tomcat的日志文件默认的存放位置。

4.Lib目录

Lib目录存放Tomcat服务器所需的各种JAR文件。

5.Temp目录

Temp目录存放Tomcat使用的临时文件。

6.Webapps目录

Webapps目录是当发布Web应用时,在默认情况下把Web应用文件放于此目录下。

7.Work目录

Work目录是Tomcat把由JSP生成的Servlet的文件存放的位置。

2.4 Web应用目录结构介绍

Web应用程序是一些Web资源的集合,包括JSP页面、HTML页面、Servlets和配置文件。它们按照Servlet规范中所描述的那样,分层次地组织起来(表2-1)。它们可以通过两种途径构建Web应用程序:一是打包,另外一个是不打包。打包的被称为Web档案(War)文件,未打包的是存放文件系统的目录结构。

表2-1 Web应用程序描述

未打包的格式对于Web应用开发人员来说非常便利,可以允许他们在开发和调试期中,随时、方便地更新单独的文件。然后在部署环境中,提供一个单独的文件自动部署,可能更为便利。这是因为减少了部署过程中放置文件和设置系统变量的步骤。

2.4.1 Web应用上下文

从上一章Tomcat的体系结构介绍可以知道,上下文组件表示的每个Web的应用。因此每个Web应用对应于一个上下文组件,它可以为每个Web应用分配一个上下文路径。默认的上下文组件是Root,可以通过输入http://localhost:8080地址,访问到默认的应用程序。用户通过向服务器请求一个Web应用的上下文,可以访问到该Web应用程序。例如,用户可以输入URL:http://localhost:8080/manager来访问Tomcat的Web管理应用程序。

如果把Web应用程序放置在Webapps目录下,那么访问该Web应用的URL为:http://localhost:8080/xxx(xxx为Web应用目录名称)。例如Tomcat的Webapps中默认自带了jsp例子,它放置在Webapps的目录名称为example,这样通过输入http://localhost:8080/examples/jsp/来访问该应用程序,如图2-27所示。

图2-27 JSP例子

如果在ROOT目录下放置的子目录与Web应用程序的目录名一致,则会出现混淆,例如:

webapps/
          ROOT/
                shop/
                    index.html
          shop/
                    index.html

从上面的目录结构中可以看出,在ROOT目录里面放置了跟Shop同名的目录和文件,通过http://localhost:8080/shop可能映射到ROOT目录和Webapps下Shop目录里的文件,这样就造成了混淆。当然Tomcat的处理机制是它会忽视ROOT目录里与Web应用重名的文件,直接显示来自Shop应用程序里面的文件。如果开发人员的出发点是想用户访问Root目录里的Web应用程序,那么就必须特别注意了。

2.4.2 WEB-INF目录

Servlet规范里面陈述了Web应用中公用和私用区域的划分。存放私用资源的目录称为WEB-INF,它处于Web应用的根目录下。在WEB-INF目录中可以存放所有的Web应用的配置文件、应用类文件等。用户要访问的话,只能通过间接的方式访问。例如通过Servlet映射。

WEB-INF包含许多特别的子目录,例如标签文件和标签库描述符(TLDs)。下面是一个Web应用的例子:

WebAppX/
          WEB-INF/
                  classes/
                  lib/
                  tags/

WEB-INF详细配置见第4章。

2.4.3 META-INF目录

META-INF放置在Web应用程序的根目录下,作为WAR文件部署。在META-INF目录下存放TLDs和标签文件,通过URI来访问。

2.5 常见问题与解决办法

1.Tomcat窗口消失

有时,启动Tomcat后,Tomcat窗口显示了一下,然后就会立刻消失。这个问题主要是由于某些错误造成了Tomcat的崩溃。错误信息本身是可以显示的,但是由于窗口消失得太快,以至于错误信息不能被用户看到。可按以下方式解决。

在Linux输入:

# $CATALINA_HOME/bin/catalina.sh run

或者在Windows里面输入:

> %CATALINA_HOME/bin/catalina run

输入上述命令后,将使得Tomcat正常启动,任何错误信息都将被显示。错误信息也可以通过stdout.log文件看到。

2.端口被占用

可能会出现选定的端口被占用的情况,类似于下面的错误信息:

LifecycleException: Protocol handler initialization failed:
Java.net.BindException: Address already in use: JVM_Bind:8080

Tomcat默认使用8080端口,在Windows或Linux中,可以通过输入netstat命令来查看谁使用了那个端口,可以看到谁跟Tomcat引起了冲突。解决该问题的方式有两种:一是关闭占用Tomcat端口的进程,一个是改变Tomcat的默认端口配置。

3.类版本错误

Tomcat 6需要Java SE 5或后期更为高级的版本,如果使用了早期Tomcat版本,在Tomcat启动时,将会出现下列错误:

Exception in thread “main”
java.lang.UnsupportedClassVersionError:
org/apache/catalina/startup/Bootstrap (Unsupported
major.minor version 49.0)

解决方法:检查JAVA_HOME环境变量设置是否指向了Java SE 5的安装目录。

2.6 小结

本章讲述了Java、Tomcat和Ant在不同平台上、不同形式的安装,包括Binary和源码。同时,本章还重点讲述了Tomcat安装目录结构,以及Web应用目录结构。读者通过本章学习,需要掌握以下几点:

在大多数情况下,Tomcat的安装是非常简单、直接的过程,主要是因为Tomcat的二进制安装文件可以在通用的平台下运行。

Tomcat的安装目录结构主要包括7个重要的目录。

安装过程中可能出现的问题,例如端口占用、类版本错误等等,读者需要通过实际安装,来逐步掌握处理这些问题的方法。

第3章 配置Tomcat

【本章导读】

在本章中,通过查看CATALINA_HOME/conf目录下的文件,主要介绍Tomcat的基本配置。在启动时,Tomcat默认安装使用这些文件配置服务器,它们对于用户了解默认的配置将做些什么和用户能够修改什么有至关重要的作用。

本章还介绍了主要的配置文件——server.xml和Tomcat的其他配置文件。在第一章中,曾经看到Tomcat使用基于组件、层次似的结构。该模型在很大程度上简化了复杂的服务器配置。最后还讲述了Tomcat的认证配置和Web应用配置,用户可以根据自己的需要加以修改。

3.1 Tomcat 6配置元素

Tomcat 6服务器启动后,读取一系列的XML配置文件。为了配置Tomcat 6,用户必须修改这些XML文件。Tomcat的配置文件位于CATALINA_HOME/conf目录下,它包含以下配置文件:

Tomcat 6在指定的配置目录中搜寻这些配置文件。配置目录由环境变量指定。Tomcat 6首先检查$CATALINA_BASE(%CATALINA_BASE%在Windows)环境变量,如果这个环境变量已经定义了,则Tomcat 6搜寻该环境变量指定目录下的conf子目录。对于在同一台机器上配置多个并发的Tomcat也非常直接和方便,分别为每个Tomcat实例设置不同的$CATALINA_BASE目录即可,也可以使用不同的shell脚本和batch文件来设置$CATALINA_BASE变量和启动各自实例。

如果$CATALINA_BASE没有被指定,则Tomcat使用$CATALINA_HOME(%CATALINA_HOME%在Windows)环境变量来代替。$CATALINA_HOME环境变量指定了Tomcat 6的安装目录。Tomcat 6会在$CATALINA_HOME指定的conf子目录中搜寻配置文件。在后续的章节中,会重点讲述配置文件的基本配置。

3.2 访问控制配置

由于在第11章中会详细讲述Tomcat 6的安全,因此本节只是大概地讲述一下catalina.policy文件配置,了解它通过内嵌的Java安全模型,如何提供给Tomcat服务器管理员合适粒度的访问控制。任何对系统资源的访问,在没有明确允许的情况下,都是被禁止的。因此,如果用户想访问所有的资源,必须有明确的被授予权限。默认的Tomcat运行是不带安全启动的。为了使得Tomcat带安全启动,需要使用security:

> $CATALINA_HOME/bin/startup security

当在安全管理的状态下,Tomcat只能读、处理和执行catalina.policy文件。通常策略的写法是:

grant <security principal> {permission list…};

在这里,<security principal>是可信代码的实体。关于权限详细介绍,可以参阅http://java.sun.com/j2se/1.5.0/docs/guide/security/permissions.html

【例3-1】访问控制配置示例

下面是一个catalina.policy的例子:

//应用权限到javac
grant codebase “file:${java.home}/lib/-”{
    permission java.security.AllPermission;
};
//应用权限到所有共享系统扩展文件
grant codebase “file:${java.home}/jre/lib/ext/-”{
permission java.security.AllPermission;
};
//当${java.home}指向$JAVA_HOME/jre时,应用权限到javac
grant codebase “file:${java.home}/../lib/-”{
permission java.security.AllPermission;
};
//当${java.home}指向$JAVA_HOME/jre时,应用权限到所有共享系统扩展文件
grant codebase “file”${java.home}/lib/ext/-”{
    permission java.security.AllPermission;
};

下面的例子是在catalina.policy文件中授权Catalina服务器和API库能够访问所有资源。

//应用权限到daemon code
    grant codebase “file”${catalina.home}/bin/commons-daemon.jar”{
    permission java.security.AllPermission;
};
//应用权限到logging API
    grant codebase “file”${catalina.home}/bin/Tomcat-juli.jar”{
    permission java.security.AllPermission;
};
//应用权限到服务器启动代码
    grant codebase “file”${catalina.home}/bin/bootstrap.jar”{
    permission java.security.AllPermission;
};
//应用权限到servlet API类和所有类加载器都能共享访问到的类
    grant codebase “file”${catalina.home}/bin/commons-daemon.jar”{
    permission java.security.AllPermission;
};

当然,用户必须保证目录本身的安全性,避免攻击者在目录中放置恶意代码。因为目录授予的权限是能够访问系统中的所有资源。

下面一个例子描述的是catalina.policy文件中包含了Web应用的权限。它们的限制性更为严格,也就是说,不可能跟上面例子一样,授予java.security.AllPermission这种超级权限。

例子中的第一部分授权访问系统属性:包括访问JNDI和JDBC。

grant {
// Required for JNDI lookup of named JDBC DataSource's and
// javamail named MimePart DataSource used to send mail
permission java.util.PropertyPermission "java.home", "read";
permission java.util.PropertyPermission "java.naming.*", "read";
permission java.util.PropertyPermission "javax.sql.*", "read";

第二部分授权只读访问操作系统描述属性:Tomcat运行的操作系统类型以及操作系统针对文件使用什么分离文件扩展名。

// OS-specific properties to allow read access
permission java.util.PropertyPermission "os.name", "read";
permission java.util.PropertyPermission "os.version", "read";
permission java.util.PropertyPermission "os.arch", "read";
permission java.util.PropertyPermission "file.separator", "read";
permission java.util.PropertyPermission "path.separator", "read";
permission java.util.PropertyPermission "line.separator", "read";

第三部分授权只读访问JVM属性:

// JVM properties to allow read access
permission java.util.PropertyPermission "java.version", "read";
permission java.util.PropertyPermission "java.vendor", "read";
permission java.util.PropertyPermission "java.vendor.url", "read";
permission java.util.PropertyPermission "java.class.version", "read";
permission java.util.PropertyPermission "java.specification.version", "read";
permission java.util.PropertyPermission "java.specification.vendor", "read";
permission java.util.PropertyPermission "java.specification.name", "read";
permission java.util.PropertyPermission "java.vm.specification.version", "read";
permission java.util.PropertyPermission "java.vm.specification.vendor", "read";
permission java.util.PropertyPermission "java.vm.specification.name", "read";
permission java.util.PropertyPermission "java.vm.version", "read";
permission java.util.PropertyPermission "java.vm.vendor", "read";
permission java.util.PropertyPermission "java.vm.name", "read";

后续的两部分分别授权给JavaBean getAttribute方法和XML parser debugger。

// Required for OpenJMX
permission java.lang.RuntimePermission "getAttribute";
// Allow read of JAXP-compliant XML parser debug
permission java.util.PropertyPermission "jaxp.debug", "read";

最后的部分是授权给Jasper运行类能预编译的JSP页面。

// Precompiled JSPs need access to this package.
permission java.lang.RuntimePermission
"accessClassInPackage.org.apache.jasper.runtime";
permission java.lang.RuntimePermission
"accessClassInPackage.org.apache.jasper.runtime.*";
};

下面的例子是默认给Web应用最小的权限设置:

// The permissions granted to the context root directory apply to JSP pages.
// grant codeBase "file:${catalina.home}/webapps/examples/-" {
// permission java.net.SocketPermission
"dbhost.mycompany.com:5432", "connect";
// permission java.net.SocketPermission "*.noaa.gov:80", "connect";
// };
//
// The permissions granted to the context WEB-INF/classes directory
// grant codeBase "file:${catalina.home}/webapps/examples/WEB-INF/classes/-" {
// };
//
// The permission granted to your JDBC driver
// grant codeBase "jar:file:${catalina.home}
/webapps/examples/WEB-INF/lib/driver.jar!/-" {
// permission java.net.SocketPermission
"dbhost.mycompany.com:5432", "connect";
// };
// The permission granted to the scrape taglib
// grant codeBase "jar:file:${catalina.home}
/webapps/examples/WEB-INF/lib/scrape.jar!/-" {
// permission java.net.SocketPermission "*.noaa.gov:80", "connect";
// };

3.3 Tomcat类加载器配置

类加载器的配置主要通过catalina.properties文件来实现。它能决定在服务端不同部分加载哪个类。前面章节中,讲叙了三个目录:common,server和shared,这三个目录作为类加载器的默认路径,当然也可以通过catalina.properties文件来实现默认路径的修改。在catalina.properties文件可以变更Web应用所需要的类。当类加载器试图加载一个禁止的类时,java.servurity.AccessControlException异常会抛出。这些设置仅仅是Tomcat在安全模式启动下才可应用。

【例3-2】类加载器配置示例

下面的例子列出了被禁止的包。从默认来说,Tomcat不允许Web应用去加载任何Tomcat的内部类。

# List of comma-separated packages that start with or equal this string
# will cause a security exception to be thrown when
# passed to checkPackageAccess unless the
# corresponding RuntimePermission ("accessClassInPackage."+package) has
# been granted.
package.access=sun.,org.apache.catalina.,org.apache.coyote.,
org.apache.Tomcat.,org.apache.jasper.,sun.beans.

如果Web应用试图访问内部类,例如org.apache.Tomcat.util.IntrospectionUtils,那么必须在catalina.policy中增加下列代码:

// Permission for org.apache.Tomcat. package
permission java.lang.RuntimePermission
    “accessClassInPackage.org.apache.Tomcat.util”;

下面的例子描述了不允许用户在某些受限制的包中定义类:

# List of comma-separated packages that start with or equal this string
# will cause a security exception to be thrown when
# passed to checkPackageDefinition unless the
# corresponding RuntimePermission ("defineClassInPackage."+package) has
# been granted.
#
# by default, no packages are restricted for definition, and none of
# the class loaders supplied with the JDK call checkPackageDefinition.
#
package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,org.apache.Tomcat.,org.apache.jasper.

下面的例子定义了Tomcat的common类加载器,它与common目录及其子目录相对应。

# List of comma-separated paths defining the contents of the "common"
# class loader. Prefixes should be used to define what is the repository type.
# Path may be relative to the CATALINA_HOME path or absolute. If left as blank,
# the JVM system loader will be used as Catalina's "common" loader.
# Examples:
# "foo": Add this folder as a class repository
# "foo/*.jar": Add all the JARs of the specified folder as class
# repositories
# "foo/bar.jar": Add bar.jar as a class repository
common.loader=${catalina.home}/lib,${catalina.home}/lib/*.jar

任何放置在这些目录中的类都能被加载,被Tomcat内部类和Web应用所使用。

下面的例子定义了Tomcat的server类加载器,它与server目录及其子目录相对应。

# List of comma-separated paths defining the contents of the "server"
# class loader. Prefixes should be used to define what is the repository type.
# Path may be relative to the CATALINA_HOME path or absolute. If left as blank,
# the "common" loader will be used as Catalina's "server" loader.
# Examples:
# "foo": Add this folder as a class repository
# "foo/*.jar": Add all the JARs of the specified folder as class
# repositories
# "foo/bar.jar": Add bar.jar as a class repository
server.loader=

放置在这些目录下的类只能被Tomcat内部类所使用。

下面的例子定义了Tomcat的shared类加载器,它与shared目录及其子目录相对应。如果shared类加载器配置忽略,则系统使用common类加载器。

# List of comma-separated paths defining the contents of the "shared"
# class loader. Prefixes should be used to define what is the repository type.
# Path may be relative to the CATALINA_BASE path or absolute. If left as blank,
# the "common" loader will be used as Catalina's "shared" loader.
# Examples:
# "foo": Add this folder as a class repository
# "foo/*.jar": Add all the JARs of the specified folder as class
# repositories
# "foo/bar.jar": Add bar.jar as a class repository
Shared.loader

放置在这些目录下的类只能被Web应用程序所使用,而不能被Tomcat内部类使用。

3.4 Tomcat Server配置

Tomcat基于组件的体系结构很大程度上简化了配置。任何外层组件设置的属性都会被内层组件所继承。例如:一个配置在引擎内监听器能够应用在嵌套的主机组件中。

当然,用户需要对底层组件作特定配置,这时可以覆盖外层组件的配置。例如,用户需要在上下文组件设置域用以覆盖引擎中已经配置好的域。这就意味着,Web应用运行的上下文中使用的是最新定义的域,而不是外层配置的域。

由于XML层次等级的特性,因此比较适合通过XML配置基于组件的模型。在XML文件中,每个元素代表一个组件,这样使得从服务器中根据是否合适插入或删除组件。在Tomcat中承担这项工作的文件为server.xml,Tomcat在启动时读取它。

3.4.1 配置服务器

现在讲述一下server.xml文件,看看如何配置服务器。从第一章中可以知道,服务端组件是顶层组件,任何Tomcat实例只能有一个服务端组件,因此在server.xml文件中,<Server>元素在顶层位置。例如:

<Server port=”8005” shutdown=”SHUTDOWN”>

<Server>元素描述了java虚拟机和监听shutdown命令端口,这样为管理员关闭Tomcat服务器实例提供了一种很好的途径。

表3-2列出了<Server>元素的属性描述。

表3-2 <Server>元素的属性

表3-3列出了<Server>元素的子元素。

表3-3 <Server>元素的子元素

3.4.2 配置全局命名资源

JNDI是通过命名目录服务来搜寻信息的API。它是平台独立性的,可以工作在任何兼容命名目录服务的平台上,而不需要考虑本地API接口。通过JNDI可以存储和访问到以下资源:

● 用户名和密码

● 访问控制策略,例如Tomcat的用户和角色机制

● 目录组织

● 服务器、数据库等

● 打印机

● Java对象,例如EJB等

JNDI避免了特定平台上本地接口程序规划问题,简化了处理机制。JNDI位于本地接口上层,担当Java类和命名服务的翻译器的角色,呈现出Tomcat统一的命名和目录服务界面,而不管所运行的是何种平台。

一般来说,许多Java应用程序不借助潜在的命名服务,而使用JNDI来定位资源。这意味着Java应用程序不需要了解资源的位置处于何处,就可访问资源。例如,使用数据库的JDNI名来访问数据库引用,不管数据库是何种类型或驱动是什么。这使得程序更为耦合。图3-1描述了JNDI作为目录服务和作为Java查询机制。

图3-1 JNDI作为目录服务和作为Java查询机制

应用程序一旦有了数据库的引用,它就可以通过JDBC直接访问到数据库。常量里面存储着能被所有运行在服务器上的Web应用所能访问到的JNDI资源。在Tomcat中使用JNDI资源查询机制更为广泛。可以使用<GlobalNamingResources>元素来配置服务器的全局JNDI资源。表3-4描述了<GlobalNamingResources>的子元素。

表3-4 <GlobalNamingResources>子元素

1.配置Environment

Environment是属于服务端变量,可能是原始封装类型中的一个。例如:

<Environment name=”simpleValue” type=”java.lang.Integer” value=”30” />

环境入口称为simpleValue,是java.lang.Integer类型,值为30。可以使用java:comp/env/simpleValue字符串来查询。表3-5描述了<Environment>的属性。

表3-5 <Environment>属性

2.配置全局资源

全局资源包括JDBC数据源、企业级JavaBean(EJB)引用和用户认证数据库。可以在/WEB-INF/web.xml中定义资源的特性。使用JNDI查找<resource-ref>和<resource-env-ref>元素时,这些特性被返回。对同一资源名称,还必须定义资源参数(见下面“配置资源参数”小节),这些参数用来配置对象工厂(object factory)以及对象工厂的属性。例如:

<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved">
</Resource>

表3-6描述了<Reousrce>元素的属性。

表3-6 <Reousrce>元素的属性

3.配置资源参数

Tomcat 6中不再使用Tomcat 5和早期版本使用的<ResourceParams>元素。代替的是使用<Resource>元素属性提供信息。例如:

<Resource name="UserDatabase" auth="Container"
          type="org.apache.catalina.UserDatabase"
          description="User database that can be updated and saved"
          factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
          pathname="conf/Tomcat-users.xml" />

4.配置JDBC数据源

运行在服务器上的Web应用程序可以通过JDBC数据源来访问通用的数据库,这给管理员带来了方便,他可以改变潜在的数据库,而不用修改Web应用程序。

数据源另外一个优点是Tomcat使用连接池,连接池使得当数据库连接使用完成后,会被再次回收,如此反复,使得性能提高。Tomcat使用Jakarta通用数据库连接池机制(Commons Database Connection Pool),支持JDBC2.0和JDBC3.0。该部分位于CATALINA_HOME/lib/Tomcat-dbcp.jar。

对于数据源配置,第一步把所需的JDBC驱动放置在CATALINA_HOME/lib目录下,或者也可以放在classpath路径中的其他目录下。这样使得Tomcat能够查找并使用驱动。

从上面可以了解到,可以通过使用<Resource>元素来配置JNDI资源工厂(resource factory)。

【例3-3】数据源配置示例

本例描述了服务器中MySQL数据源的配置,该数据库可以被运行在服务器上的其他Web应用程序所能共享的访问中。

<Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="javauser"
password="javadude"
driverClassName="com.mysql.jdbc.Driver"
url= "jdbc:mysql://localhost:3306/javatest?autoReconnect=true"
/>

这个例子定义了名称为jdbc/ TestDB的数据源,并且设置它的驱动和连接URL。它显示了在不用改动Web程序的情况下如何改变数据库配置。表3-7描述了各个参数的含义。

表3-7 参数的含义

除了先前的配置,开发人员还必须在应用的web.xml文件使用<resource-ref>元素来申明资源的使用,比如:

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
          http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
<!-- Describe a DataSource -->
<resource-ref>
    <description>
    Resource reference to a factory for java.sql.Connection
    instances that may be used for talking to a particular
    database that is configured in the TomcatBook.xml file.
    </description>
    <res-ref-name>
    jdbc/CatalogDB
    </res-ref-name>
    <res-type>
    javax.sql.DataSource
    </res-type>
    <res-auth>
    SERVLET
    </res-auth>
</resource-ref>
<!-- Define a Security Constraint on this Application -->
<security-constraint>
    <web-resource-collection>
          <web-resource-name>Tomcat Book Application</web-resource-name>
          <url-pattern>/*</url-pattern>
    </web-resource-collection>
<auth-constraint>
      <role-name>Tomcat</role-name>
</auth-constraint>
<user-data-constraint>
      <description>
      Constrain the user data transport for the whole application
      </description>
          <transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<!-- Define the Login Configuration for this Application -->
<login-config>
<auth-method>FORM</auth-method>
<realm-name>Tomcat Book Application</realm-name>
<form-login-config>
      <form-login-page>/ch12/login.jsp</form-login-page>
      <form-error-page>/ch12/error.jsp</form-error-page>
</form-login-config>
</login-config>
<!-- Security roles referenced by this web application -->
<security-role>
<description>
The role that is required to log in to the Tomcat Book Application
</description>
<role-name>Tomcat</role-name>
</security-role>
</web-app>

5.配置Mail Sessions

JavaMail是标准的程序API,用于生成和发送e-mails。Tomcat支持JavaMail,允许用户配置JavaMail session作为JNDI资源。Web应用能通过JNDI查找该资源,使用该session。

JavaMail session的设置过程与JDBC数据源的设置类似,首先必须将JavaMail API放置在CATALINA_HOME/ /lib目录下,便于Tomcat和Web应用能够使用它的类。JavaMail API可以从http://java.sun.com/products/javamail/downloads/index.html查看。在server.xml文件中配置mail session如下:

<Resource name=”mail/Session” auth=”Container”
          Type=”javax.mail.Session”
          Mail.smtp.host=”localhost”/>

最后,在web.xml文件中配置JavaMail Session引用如下:

<resource-ref>
    <res-ref-name>mail/Session</ res-ref-name >
    <res-type>javax.mail.Session</ res-type >
    <res-auth>Container</ res-auth >
</resource-ref>

3.4.3 配置服务

服务组件由多个连接组件和一个引擎组件组成,例如:

<Service name=”Catalina”>

该服务名称为Catalina。在日志和错误信息中将会出现该服务名称,用于清晰的表明该组件。服务管理软件也用该名称表明服务实例。表3-8描述了<Service>元素属性,表3-9描述了<Service>元素的子元素。

表3-8 <Service>元素属性

表3-9 <Service>元素的子元素

3.4.4 配置连接器

请求进入Tomcat的两种情况:

● 来自前端的Web服务器,可能是Apache,IIS或者其他Web服务器。

● 来自Web浏览器。

处理这些连接请求,有一种处理途径是为每个请求定制一个Tomcat,但是这样的话,会非常没有效率且难以管理。连接器传递请求给引擎,使引擎适应外部世界,同时相应传递给用户;连接器处理协议、连接协定等,以至于引擎不必处理它们。

在单个引擎中可以配置多个连接器。例如:可能需要在同一个服务器提供HTTP服务和HTTPS服务给用户,这时,需要在引擎中配置HTTP连接器和SSL连接器。在第8章中将会看到关于连接器的更为详细的信息。先通过浏览server.xml,看一下默认配置。

在配置连接器中有许多不同的可选项,server.xml显示了4个最为普通的选项:

● HTTP连接器

● SSL连接器

● AJP1.3连接器,用于连接其他Web服务器

● 代理连接器

【例3-4】连接器配置示例

对于Catalina引擎来说,默认的连接器是HTTP/1.1连接器。例如:

<!-- Define a non-SSL Coyote HTTP/1.1 Connector on port 8080-->
    <Connector port="8080"
          maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
          enableLookups="false" redirectPort="8443" acceptCount="100"
          debug="0" connectionTimeout="20000"
          disableUploadTimeout="true" />

上面设置了HTTP请求的监听端口为8080。表3-10描述了所有连接器的属性。表3-11描述了HTTP连接器的属性。

表3-1 Tomcat基本配置元素

表3-10 <Connector>元素共同属性

表3-11 HTTP<Connector>元素属性

【例3-5】HTTPS请求的SSL连接器配置示例

<!-- Define a SSL Coyote HTTP/1.1 Connector on port 8443-->
<!--
    <Connector port="8443"
          maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
          enableLookups="false" disableUploadTimeout="true"
          acceptCount="100" debug="0" scheme="https" secure="true"
      clientAuth="false" sslProtocol="TLS" />
-->

上面设置了HTTPS请求的安全SSL连接器的监听端口为8443。既共享了普通的HTTP连接器

的属性,同时又具有自己独特的SSL属性。表3-12描述了SSL属性。

表3-12 SSL<Connector>元素属性

【例3-6】AJP1.3连接器配置示例

<!-- Define a Coyote/JK2 AJP 1.3 Connector on port 8009-->
    <Connector port="8009"
          enableLookups="false" redirectPort="8443" debug="0"
          protocol="AJP/1.3" />

上面设置了AJP1.3连接器的监听端口为8009。通过该连接器允许Tomcat连接到Apache Web服务器,使得Web既能提供JSP页面和servlets服务,同时也能提供HTML页面和重要的用户管理功能。表3-13描述了AJP连接器属性。

表3-13 AJP1.3<Connector>元素属性

【例3-7】连接器与代理服务器协同工作配置示例

    <!-- Define a Proxied HTTP/1.1 Connector on port 8082-->
    <!-- See proxy documentation for more information about using this. -->
    <!--
        <Connector port="8082"
            maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
            enableLookups="false"
            acceptCount="100" debug="0" connectionTimeout="20000"
            proxyPort="80" disableUploadTimeout="true" />
    -->

该配置文件配置了连接器与代理服务器协同工作,允许代理提供防火墙。所有连接器都被配置自动发送错误和记录信息到引擎日志。

3.4.5 配置引擎

在实际单个服务器中,需要多个连接器服务处理不同的连接请求,但是只能有一个引擎。引擎

执行处理Web应用中的请求和响应。例如:

<!-- Define the top level container in our container hierarchy
<Engine name="Catalina" defaultHost="localhost" debug="0">

引擎代表的是servlet处理的运行实例,换句话说它就是servlet引擎。在上面server.xml配置文件中,看到配置的默认引擎是Catalina。默认主机是主机组件,debug属性设置为0,表明引擎没有调式信息写到日志。表3-14描述了<Engine>元素的属性,表3-15描述了<Engine>元素的子元素。

表3-14 <Engine>元素属性

表3-15 <Engine>元素的子元素

3.4.6 Tomcat日志

Tomcat并没有包含日志组件,依赖于Jakarta通用日志机制(Commons logging)。Java1.4内嵌的日志特征和Apache Log4J工具包是两个最为通用的日志。由于在Tomcat中经常使用Log4J,因此后面详细讲述Log4J。

【例3-8】配置启动时加载Log4J

首先从http://logging.apache.org/log4j/下载Log4J类。Tomcat在启动时使用通用日志机制,如果用户想使用Log4J替代通用日志机制,必须把日志包含在启动内。需要修改catalina.bat/Catalina.sh脚本,将log4j.jar增加到启动路径中。

rem catalina.bat
set CLASSPATH=%CLASSPATH%;
%CATALINA_HOME%\bin\bootstrap.jar;
%CATALINA_HOME%\bin\log4j.jar
# catalina.sh
CLASSPATH="$CLASSPATH":
"$CATALINA_HOME"/bin/bootstrap.jar:
"$CATALINA_HOME"/bin/commons-logging-api.jar:
"$CATALINA_HOME"/bin/log4j.jar

3.4.7 配置域

在Tomcat中域的配置用于用户认证,在server.xml文件中,域的配置如下:

<!-- Because this Realm is here, an instance will be shared globally -->
<!-- This Realm uses the UserDatabase configured in the global JNDI
    resources under the key "UserDatabase". Any edits
    that are performed against this UserDatabase are immediately
    available for use by the Realm. -->
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
      debug="0" resourceName="UserDatabase"/>

可以看到,域使用的是在“全局资源配置”一章的全局资源,通过域使得全局资源附属于它所驻留的引擎。

Tomcat使用域执行认证和实现容器内安全管理,实现用户名和密码隐射(认证),用户名与用户角色之间的隐射(容器内安全管理)。通过认证,Tomcat能够确定用户是谁,通过容器内安全管理,可以确定服务器上的哪些资源可以让用户使用。

用户数据库是域的唯一实现。其他的是数据源域、JDBC域、JNDI域和JAAS域。Tomcat 5支持内存与向后兼容Tomcat 4,但是这不是很有效率和安全的。

关于不同域的详细描述在第10章,下面简要介绍一下:

1.配置用户数据库域

用户数据库域是内存域的升级版本,向后兼容内存域。

2.配置数据源域

数据源域使用JDBC数据源验证用户。允许改变潜在的存储机制,而不需改变域的设置。

3.配置JDBC域

JDBC域能访问关系数据库,获得认证信息。任何使用JDBC兼容的访问借口数据源都能使用,例如ODBC。server.xml文件中有许多JDBC域配置的例子,例如下面的MySql数据库配置例子:

<!--
<Realm className="org.apache.catalina.realm.JDBCRealm" debug="99"
      driverName="org.gjt.mm.mysql.Driver"
        connectionURL="jdbc:mysql://localhost/authority"
        connectionName="test" connectionPassword="test"
        userTable="users" userNameCol="user_name"
        userCredCol="user_pass"
        userRoleTable="user_roles" roleNameCol="role_name" />
-->

4.配置JNDI域

JNDI Directory Realm将Catalina连接到一个LDAP目录,通过正确的JNDI驱动访问。LDAP目录存储了用户名,密码以及它们相应的角色。对目录的修改马上反映到用来认证新的登录的数据上面。

5.配置JAAS域

使用JAAS域通过使用Java认证和授权服务(JAAS)实现用户认证机制。在JAAS域中可以使用任何认证机制,但是用户必须实现它。

3.4.8 配置主机

主机组件代表的是运行在服务器上的单个虚拟主机,例如:

<Host name="localhost" debug="0" appBase="webapps"
    unpackWARs="true" autoDeploy="true"
    xmlValidation="false" xmlNamespaceAware="false">

上面描述的是虚拟主机为localhost。运行在主机上的应用程序部署在CATALINA_HOME/webapps目录下。

unpackeWARs属性,如果设置为true,表明Tomcat解压appBase目录下的WAR压缩文件;设置为false,表明Tomcat不需解压WAR文件,直接执行Web应用程序。这样做法解决了空间问题,但是增加了响应时间。

<Host>元素作为容器,有着自己的属性,表3-16描述了这些属性。

表3-16 <Host>元素共同属性

上面描述的是<Host>元素的共同属性,下面表3-17描述了标准host的属性。

表3-17 <Host>元素标准属性

表3-18描述了<Host>元素中可以放置的子元素。

表3-18 <Host>元素的子元素

3.4.9 配置阀

阀是Tomcat中特定拦截机制,用于捕获请求和响应。任何发往localhost主机的请求,没有加以注释的话,都会通过阀。

<!--
<Valve className="org.apache.catalina.valves.AccessLogValve"
      directory="logs" prefix="localhost_access_log."
    suffix=".txt"
    pattern="common" resolveHosts="false"/>
-->

org.apache.cataline.valves.AccessLogValve阀用来创建日志访问文件,格式类似于Apache的日志文件。上面的配置文件描述了一个日志文件的创建,名字为localhost_access_log.Date.txt,存储在CATALINA_HOME/logs目录下。

在引擎层中可以安装阀,不管请求来自于哪个连接器,安装在引擎层中的阀都能够访问到引擎处理的请求。用户使用时,需要测试阀,确保阀完成自己的操作,不需消耗太多处理器时间。Tomcat默认的标准阀已经测试,足够满足大部分的要求。

【注意】

阀为Tomcat所特有的,并不作为Servlet规范的一部分。应用程序员可以使用过滤器作为类似的拦截机制,而这些属于Servlet规范的一部分。

在第6章中,会详细讲叙配置和使用标准阀。

3.4.10 配置监听器

如果用户有一个对象,需要知道服务器的生命周期事件,那么用户必须实现监听器。基本的监听器配置如下:

<Listener className=”com.acme.listeners.Listener”>

className属性是必须要求的,用户也可以增加类的其他属性,这个与JavaBean命名机制完全一致。

3.4.11 配置别名

如果用户需要隐射多个网络名到单个虚拟主机,那么用户必须配置别名。例如,用户想隐射www.company.comwww.company.org到同样的主机,配置如下:

<Host name="www.company.com" ...>
<Alias>www.company.org</Alias>
</Host>

3.4.12 认证配置

Tomcat用户数据库域默认读取Tomcat-users.xm文件到内存中。只要域把文件加载到内存,任何对Tomcat-user.xml文件的修改都不会立刻实施,除非一直等到下一次服务器重启。典型的Tomcat-users.xml文件配置如下:

<?xml version='1.0' encoding='utf-8'?>
<Tomcat-users>
    <role rolename="Tomcat"/>
    <role rolename="role1"/>
    <user username="Tomcat" password="Tomcat" roles="Tomcat"/>
    <user username="both" password="Tomcat" roles="Tomcat,role1"/>
    <user username="role1" password="Tomcat" roles="role1"/>
</Tomcat-users>

用户所能扮演的角色都定义在<role>元素内,每个用户都有<user>属性。特别注意的是通过在role属性中使用逗号分开,一个用户可能担当多个角色。

3.5 Web应用程序配置

每个符合Servlet2.4规范的应用程序都必须包含web.xml部署描述文件。该文件必须放置在web应用的WEB-INF目录下。

Tomcat也不例外,拥有自己默认的web.xml文件,位于CATALINA_HOME/conf目录下。该文件与web应用程序的web.xml文件类似,但是它指定的是运行在该服务器实例上所有web应用的默认属性。

一个典型的web.xml文件如下:

<?xml version="1.0" encoding="ISO-8859-1"?>
<Web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/Web-app_2_4.xsd"
version="2.4">

文件中可以看到,最为显著的是默认的web应用版本是2.4。1.默认Servlet定义

默认servlet用于任何静态资源的服务(静态HTML文件、GIF文件等)和目录列表服务。默认servlet可以在web.xml文件或应用程序的web.xml文件中定义,一般定义在<servlet>元素下,例如:

<web-app>
<servlet>
      <servlet-name>default</servlet-name>
<servlet-class>
      org.apache.catalina.servlets.DefaultServlet
</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

下面是invoker servlet的配置。invoker servlet通过直接使用Servlet的文件名,加载和执行匿名servlets。该机制本身是不安全的,因为存在Tomcat的classpath路径下的类都能通过该机制实现调用。Invoker servlet配置如下:

<!--
<servlet>
    <servlet-name>invoker</servlet-name>
    <servlet-class>
          org.apache.catalina.servlets.InvokerServlet
    </servlet-class>
    <init-param>
          <param-name>debug</param-name>
          <param-value>0</param-value>
    </init-param>
    <load-on-startup>2</load-on-startup>
</servlet>
-->

与Servlets有默认servlet类似,JSP页面也有一个Servlet,用于编译JSP页面和执行它们。配置如下:

<servlet>
    <servlet-name>jsp</servlet-name>
    <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
    <init-param>
          <param-name>fork</param-name>
          <param-value>false</param-value>
</init-param>
<init-param>
      <param-name>xpoweredBy</param-name>
      <param-value>false</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>

2.匹配URLs:Servlet映射

Servlet映射指定了根据请求URL模式,那个servlet将处理该请求。配置如下:

<!-- The mapping for the default servlet -->
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

上面的<servlet-mapping>元素映射URL模式/到默认servlet,下面的<servlet-mapping>映射所有URL以/servlet/*结束的请求到invoker servlet。

<!-- The mapping for the invoker servlet -->
<!--
<servlet-mapping>
    <servlet-name>invoker</servlet-name>
    <url-pattern>/servlet/*</url-pattern>
</servlet-mapping>
-->

下面的<servlet-mapping>指定了所有包含*.jap和*.jspx的URL模式将传递给名字为jsp的servlet来处理。

<!-- The mapping for the JSP servlet -->
<servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>*.jsp</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>*.jspx</url-pattern>
</servlet-mapping>

3.配置Session失效

<session-config>元素配置了Tomcat维持Session多长时间。默认来说,Session的实现时间为30分钟,超过30分钟后,用户的所有信息将会丢失。Session失效配置例子如下:

<session-config>
    <session-timeout>30</session-timeout>
</ session-config >

4.配置MIME映射

<mime-mapping>元素建立mime类型与扩展名相关联,帮助Tomcat服务静态文件,当传输文件到客户端时,它产生HTTP Content-Type头。大多数浏览器接收到传输的文件后,如果识别了Content-Type,使用帮助应用程序处理该文件。例如,浏览器当检测到application/pdf内容类型时,将会启动Adobe Acrobat程序。MIME映射配置如下:

<mime-mapping>
    <extension>abs</extension>
    <mime-type>audio/x-mpeg</mime-type>
</mime-mapping>

5.配置欢迎文件

为了与其他Web服务器兼容,例如Apache等,如果传入的URL以/结尾的话,默认Servlet将会显示欢迎文件,例如www.china.com。默认Servlet将会检查虚拟主机根目录,查找index.html、index.htm或index.jsp,依次显示给用户。Web应用程序可以使用自己的部署描述文件(web.xml)覆盖下列欢迎文件配置:

<welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
</welcome-file-list>

3.6 总结

本章中,介绍了Tomcat的conf目录下所有配置文件。Server.xml是Tomcat的主要配置文件,用户可以根据需要定制server.xml文件。Tomcat中的Tomcat-user.xml文件用于默认的用户认证机制。在实际生产系统中,可能用户还需要更多域的实现,比如JDBC域或者JNDI域。

在CATALINA_HOME/conf目录下的web.xml指定了运行在服务器上的每个Web应用的属性。许多默认的Servlets配置在web.xml文件中,它提供了运行的Web应用类Web服务器特征(例如:服务静态内容、SSI、CGI等)。

虽然Tomcat在非安全模式下启动,但是catalina.policy对于Tomcat安全体系非常重要。它指定了谁能访问什么内容,不能访问哪些资源等。Tomcat利用了成熟、内嵌的Java安全框架。

在CATALINA_HOME/conf目录下的其他文件还有catalina.properties。它主要用于配置Tomcat的类加载器,以及应用程序代码能够执行哪些类。默认的来说,Tomcat internals是被禁止的。

第4章 Web应用程序管理

【本章导读】

在上一章详细介绍了Tomcat的基本配置方法,包括了<CATALINA_HOME>/conf/目录下的配置文件,主要是介绍Server.xml配置文件的配置方法。在本章将主要介绍<CATALINA_HOME>/webapps/目录下Web应用程序的管理和配置方法。具体包括Context.xml上下文的配置、Web应用程序的目录结构检查、Web.xml文件的元素属性及配置和Web应用的具体方法。

本章主要内容包括Contexts上下文配置、Web应用程序检查、web.xml文件检查和Web应用程序示例。

4.1 Contexts上下文配置

在前面一章已经介绍了在Sever.xml文件中如何配置<Contexts>元素的方法。在Tomcat 6的版本中,Contexts元素已经从Server.xml文件中独立出来,放在一个名为Context.xml的文件中。因为Server.xml是不可动态重加载的资源,服务器一旦启动之后,要想让修改过的Server.xml文件配置生效,就需要重启服务器才能重新加载。而Context.xml文件则不然,Tomcat服务器会定时去扫描这个文件。一旦发现该文件被修改(时间戳改变了),就会自动重新加载这个文件,而不需要重启服务器。

4.1.1 Contexts元素的范围

Contexts元素的可用范围是可以控制的,根据应用的不同需求,可以为Contexts元素定义不同级别的可用范围。一般可以分为以下的3种可用范围:

(1)全局可用

全局可用范围意味着Tomcat服务器下面的所有应用都可以使用这个Contexts元素所定义的资源。全局可用范围的Contexts元素在<CATALINA_HOME>/conf/context.xml文件中描述。这个文件在Tomcat刚刚被安装的时候,是没有定义任何资源的。当你打开该文件就可以看到,这个文件的内容如下所示:

<Context>
  <!--Defaultsetofmonitoredresources-->
  <WatchedResource>WEB-INF/web.xml</WatchedResource>
      <!--UncommentthistodisablesessionpersistenceacrossTomcatrestarts-->
      <!--
  <Managerpathname=""/>
    -->
  <!--UncommentthistoenableCometconnectiontacking(providesevents
    onsessionexpirationaswellaswebapplifecycle)-->
  <!--
  <ValveclassName="org.apache.catalina.valves.CometConnectionManagerValve"/>
    -->
</Context>

在这个文件中只是默认地配置了一个服务器监听应用资源:<WatchedResource>WEB-INF/web.xml</WatchedResource>,表示服务器会通过监视Web应用的WEB-INF/web.xml文件来知道哪个Web应用会引用在此处定义的资源。

(2)指定的虚拟主机可用

指定的虚拟主机可用就是Tomcat服务器配置的虚拟主机。只有在指定的那个虚拟主机上运行的应用才能使用该Contexts资源。要配置一个虚拟主机可用的Contexts资源,可以在<CATALINA_HOME>/conf/目录下的${enginename}/${hostname}/context.xml.default文件中表述。

例如,一般当一个Tomcat服务器安装好了以后,都有一个默认名为CATALINA的引擎,在这个引擎下还有一个名为localhost的虚拟主机。所有的应用一般都放在这个虚拟主机下。那么,如果想要配置一个在Catalina/localhost虚拟主机下都可以使用的资源,则需要在<CATALINA_HOME>/conf目录下建立Catalina/localhost目录,然后在这个文件目录下创建一个文件,名为context.xml.default,即此文件全路径是<CATALINA_HOME>/conf/Catalina/localhost/context.xml.default。

(3)指定的应用可用

一个指定的应用可用的Context元素,意味着这是一个指定的引擎,指定的虚拟主机,只有在指定的应用中才可以使用的Context元素。例如,如果用appname来代表这个指定应用的名字,那么元素的定义应该被放置在<CATALINA_HOME>/conf/${enginename}/${hostname}/${appname}.xml文件中或是放置在<CATALINA_HOME>/webapps/${appname}/WEB-INF/context.xml文件中。假设在localhost的虚拟主机下有一个Web应用叫做myApp,那么应该创建文件<CATALINA_HOME>/conf/Catalina/localhost/myApp.xml或是创建文件<CATALINA_HOME>/webapps/myApp/WEB-INF/context.xml。

4.1.2 Contexts元素的配置

【例4-1】配置一个应用的Contexts元素

配置一个应用的Contexts元素,可以按照以下的步骤来完成:

首先,假定Contexts元素是为一个名叫myApp的Web应用创建的,那么这个Web应用的放置路径应该是在<CATALINA_HOME>/webapps/myApp目录下;如果使用的是WAR包,那么就应该是<CATALINA_HOME>/webapps/myApp.war文件。所以,Contexts元素应该指定属性path=”myApp”docBase=”myApp”。由于这是一个可以动态重新加载的资源,所以应该指定属性reloadable=”true”。如下所示:

<Context path="myApp"
docBase="myApp"
debug="5"
reloadable="true"
crossContext="true">

其次,需要指定一个被监视的资源,在这个资源里面,定义Context中的资源被谁引用了。对于Web应用,这个被监视的资源就是web.xml文件,如下所示:

<WatchedResource>WEB-INF/web.xml</WatchedResource>

最后,需要配置一个或多个资源信息。比如一些数据库的资源信息:需要配置一个Oracle的数据源名叫:myoracle,链接数据库的用户名是:user1,密码是:password1,数据库驱动程序是:oracle.jdbc.OracleDriver,数据流链接URL是:jdbc:oracle:thin:@127.0.0.1:1521:mysid。如下所示:

<Resource name="jdbc/myoracle" auth="Container"
    type="javax.sql.DataSource"
    driverClassName="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:@127.0.0.1:1521:mysid"
username="user1"
    password="password1"
    maxActive="20"
    maxIdle="10"
maxWait="-1"/>

配置了Context元素后,完整的context.xml文件如下所示:

<Context path="myApp"
docBase="myApp"
debug="5"
reloadable="true"
crossContext="true">
<!—Default set of monitored resources-->
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
<!--UncommentthistodisablesessionpersistenceacrossTomcatrestarts-->
<!--
    <Managerpathname=""/>
-->
<Resource name="jdbc/myoracle"auth="Container"
type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:@127.0.0.1:1521:mysid"
username="user1"
    password="password1"
    maxActive="20"
    maxIdle="10"
maxWait="-1"/>
</Context>

在上面的配置中,涉及到了Contexts元素的一些属性。Contexts元素的属性具体如表4-1中描述。

表4-1 Contexts元素属性

续表

Context元素所包含的子元素如表4-2中描述。

表4-2 <Context>元素的子元素

4.1.3 Contexts元素的引用

前面在定义Contexts元素的时候,已经指定了一个监视资源:WEB-INF/web.xml。现在就需要在这个监视资源里面声明需要引用的JNDI环境资源,即在<CATALINA_HOME>/webapps/myApp/WEB-INF/web.xml文件里添加,如下所示:

<resource-ref>
    <description>DBConnection</description>
    <res-ref-name>jdbc/myoracle</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref>

然后就可以在程序应用中对Context元素进行引用访问,其中方法可如下所示:

ContextinitContext=newInitialContext();
ContextenvContext=(Context)initContext.lookup("java:/comp/env");
DataSourceds=(DataSource)envContext.lookup("jdbc/myoracle");
Connectionconn=ds.getConnection();

4.2 Web应用程序检查

Web应用项目都是创建在<CATALINA_HOME>/webapps目录下的。当服务器启动的时候,就会加载编译 < CATALINA_HOME>/webapps目录下的所有应用项目。假设在<CATALINA_HOME>/webapps目录下有一个名为myApp的Web应用项目,其目录机构一般如下所示:

--/myApp

//Web应用的根目录。所有的JSP和HTML文件都存放于此目录下,同时也可以根据需要创建多个具有某个含义的文件目录。比如存放图片的目录/myApp/picture,JavaScript应用目录/myApp/js等。

--/myApp/myServlet
//存放Web应用的Servlet类。
--/myApp/myBean
//存放Web应用的Javabean类。
--/myApp/WEB-INF
//存放Web应用的发布描述文件web.xml,Context上下文文件等。
--/myApp/WEB-INF/classes
//存放各种class文件,Servlet类的class文件也放于此目录下。
--/myApp/WE B-INF/lib
//存放Web应用所需的各种JAR文件。比如JDBC驱动程序的JAR文件。

web.xml是Web应用系统的描述文件,用于Web应用的最基本配置,指定了系统的一系列设置,比如welcome欢迎页面,Servlet控制器和Filter过滤器等的设置描述。web.xml存放于Web应用根目录的/WEB_INF目录下,Web工程在启动的时候会在这里面找到具体所用到类的路径,由此进行加载。

下面对web.xml描述文件的各个元素进行简要的介绍:

schema

部署描述符文件就像所有XML文件一样,必须以一个XML头开始。这个头文件声明了使用的XML版本并给出文件的字符编码。比如Servlet规范的版本,管理此文件其余部分内容的语法的DTD(Document Type Definition,文档类型定义)等。Tomcat 6web.xml文件的Schema头文件如下所示:

<?xmlversion="1.0"encoding="ISO-8859-1"?>
<!DOCTYPEweb-app
PUBLIC"-//SunMicrosystems,Inc.//DTDWebApplication2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
    …
</web-app>

其他的元素都放在<web-app>与</web-app>之间。

<discription>、<display-name>、<distributable>

<discription></discription>是对该站点的描述,<display-name></display-name>是定义该站点的名称,<distributable><distributable/>是指定该站点是否可分布式处理。例如:

<discription>ThisisatestforTomcat</discription>
<display-name>test</display-name>
<distributable>true<distributable/>

<context-param>

<context-param></context-param>元素用来设定Web站点的环境参数,它包含两个子元素:<param-name></param-name>用来指定参数的名称;<param-value></param-value>用来设定参数值。例如:

<context-param>
  <param-name>myparam</param-name>
  <param-value>hello</param-value>
  </context-param>

在此设定的参数,可以在Servlet中用getServletContext().getInitParameter("myparam")方法来取得它的参数值。

<filter>

<filter></filter>是用来声明Filter过滤器的相关设定,它包含以下子元素:<filter-name></filter-name>是指定Filter的名字,<filter-class></filter-class>是定义Filter类的名称,<init-param></init-param>是定义参数。其中<init-param></init-param>又有两个子元素:<param-name></param-name>是指定参数的名称,<param-value></param-value>是设定参数值。在一个<filter>里面可以定义多个<init-param></init-param>元素。例如:

<filter>
<filter-name>requestFilter</filter-name>
<filter-class>com.appress.admin.filters.requestFilter</filter-class>
<init-param>
<param-name>allow</param-name>
<param-value></param-value>
</init-param>
    <init-param>
<param-name>deny</param-name>
<param-value>127.0.0.1</param-value>
</init-param>
    <init-param>
<param-name>blockPage</param-name>
<param-value>/blocked.html</param-value>
</init-param>
</filter>

<filter-mapping>

与<filter>配套使用的是<filter-mapping>,<filter-mapping></filter-mapping>是定义Filter所对应的URL,它有两个子元素:<filter-name></filter-name>指定Filter的名字,<url-pattern></url-pattern>指定Filter所对应的URL。例如:

<filter-mapping>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               <filter-name>requestFilter</filter-name>
    <url-pattern>/*</url-pattern>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               </filter-mapping>

<listener>

<listener></listener> 是设定Listener侦听器接口,它的主要子元素为:<listener-class></listener-class>是定义Listener的类名称。例如:

<listener>
    <listener-class>com.test.ContextListener</listener-class>
</listener>

<servlet>

<servlet></servlet> 用来声明一个Servlet的数据,它主要有以下子元素:<servlet-name></servlet-name>指定Servlet的名称,<servlet-class></servlet-class>指定Servlet的类名称,<jsp-file></jsp-file>指定Web站点中的某个Jsp网页的完整路径,<init-param></init-param>用来定义参数。其中<init-param></init-param>又有两个子元素:<param-name></param-name>是指定参数的名称,<param-value></param-value>是设定参数值。在一个<servlet>里面可以定义多个<init-param></init-param>元素。例如:

<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefalutServlet</servlet-class>
      <init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
      <init-param>
<param-name>listings</param-name>
<param-value>0</param-value>
</init-param>
      <load-on-startup>1</load-on-startup>
 </servlet>

<servlet-mapping>

与<servlet>一起配套使用的是<servlet-mapping>,<servlet-mapping></servlet-mapping>用来定义Servlet所对应的URL,包含两个子元素:<servlet-name></servlet-name>指定servlet的名称,<url-pattern></url-pattern>指定Servlet所对应的URL。例如:

<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

<session-config>

<session-config></session-config>用来定义Web站点中的Session参数,它包含一个子元素:<session-timeout></session-timeout>用来定义这个Web站点所有Session的有效期限,单位为分钟。例如:

<session-config>
    <session-timeout>30</session-timeout>
</session-config>

<mime-mapping>

<mime-mapping></mime-mapping>定义某一个扩展名与某一个MIMEType形成对映,包含两个子元素:<extension></extension>指定扩展名的名称,<mime-type></mime-type>是MIME格式。可以定义多个<mime-mapping>,例如:

<mime-mapping>
    <extension>doc</extension>
    <mime-type>application/vnd.ms-word</mime-type>
</mime-mapping>
<mime-mapping>
    <extension>bmp</extension>
    <mime-type>image/bmp</mime-type>
</mime-mapping>

<welcome-file-list>

<welcome-file-list></welcom-file-list>用来定义首页的欢迎列单,包含一个子元素:<welcome-file></welcome-file>指定首页的默认文件名称。可以定义多个<welcome-file>。例如:

<welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  <welcome-file>index.htm</welcome-file>
    <welcome-file>index.html</welcome-file>
</welcom-file-list>

<error-page>

<error-page></error-page>用来处理产生错误代码或发生异常的页面,它包含有三个子元素:<error-code></error-code>指定错误代码,<exception-type></exception-type>指定一个Java异常类型,<location></location>指定在Web站点内的相关资源路径。例如:

<error-page>
  <error-code>404</error-code>
  <location>/error404.jsp</location>
</error-page>
<error-page>
  <exception-type>java.lang.Exception</exception-type>
  <location>/exception.jsp</location>
</error-page>

<taglib>

<taglib></taglib>用来设定JSP网页所用到的TagLibrary路径,它包含两个子元素:<taglib-uri></taglib-uri>定义TLD文件的URI,在JSP网页中用Taglib指令便可取得该URI的TLD文件,<taglib-location></taglib-location>指定TLD文件相对于Web站点的存放位置。例如:

<taglib>
<taglib-uri>myTaglib</taglib-uri>
<taglib-location>/WEB-INF/tlds/MyTaglib.tld</taglib-location>
</taglib>

<resource-env-ref>

<resource-env-ref></resource-env-ref>定义站点可利用的环境资源,它包含三个子元素:<description></description>资源说明;<resource-env-ref-name></resource-env-ref-name>资源名称;<resource-env-res-type></resource-env-res-type>资源种类。例如:

<resource-env-ref>
    <description>Link to the User Database…</description>
    <resource-env-ref-name>users</resource-env-ref-name>
    <resource-env-res-type>org.apache.catalina.UserDatabase</resource-env-res-type>
</resource-env-ref>

<resource-ref>

<resource-ref></resource-ref>定义利用JNDI取得站点可利用的资源,它包含五个子元素:<description></description>资源说明;<rec-ref-name></rec-ref-name>资源名称;<res-type></res-type>资源种类;<res-auth></res-auth> 资源者,通过Application或Container来许可;<res-sharing-scope></res-sharing-scope>资源是否可以共享,有Shareable(可共享)和Unshareable(不可共享)两个值,默认为Shareable。例如配置某数据库链接池如下所示:

<resource-ref>
<description>JNDI JDBC Data Source of BookShop</description>
<res-ref-name>jdbc/sample_db</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>

<jsp-config>

<jsp-config></jsp-config>包括<taglib></taglib>和<jsp-property-group></jsp-property-group>两个子元素。其中<taglib></taglib>元素在JSP1.2时就已经存在;而<jsp-property-group></jsp-property-group>是在JSP2.0新增的元素。其中<jsp-property-group></jsp-property-group>元素主要有八个子元素,它们分别为:<description></description> 设定的说明;<display-name></display-name> 设定名称;<url-pattern></url-pattern>设定值所影响的范围,如:/CH2或/*.jsp;<el-ignored></el-ignored>若为true,表示不支持EL语法;<scripting-invalid></scripting-invalid>若为true,表示不支持<%scripting%>语法;<page-encoding></page-encoding>设定JSP网页的编码;<include-prelude></include-prelude>设置JSP网页的抬头,扩展名为.jspf;<include-coda></include-coda>设置JSP网页的结尾,扩展名为.jspf。例如:

<jsp-config>
    <taglib>
    <taglib-uri>Taglib</taglib-uri>
    <taglib-location>/WEB-INF/tlds/MyTaglib.tld</taglib-location>
    </taglib>
    <jsp-property-group>
    <description>Special property group for JSP Configuration JSP example.</description>
    <display-name>JSPConfiguration</display-name>
    <url-pattern>/jsp/*</url-pattern>
          <el-ignored>true</el-ignored>
          <page-encoding>GB2312</page-encoding>
    <scripting-invalid>true</scripting-invalid>
    <include-prelude>/include/prelude.jspf</include-prelude>
    <include-coda>/include/coda.jspf</include-coda>
    </jsp-property-group>
</jsp-config>

<security-constraint>

在应用中,有时只希望通过认证的用户才能请求某些Servlet,这可以在web.xml中进行相应的配置,来达到此目的。这就需要用到<security-constraint></security-constraint>元素。

要在web.xml中使用<security-constraint></security-constraint>元素,首先需要在位于<CATALINA_HOME>/conf/tomcat-users.xml的XML文件中创建用户名和密码。然后在Web应用程序的web.xml中创建security-constraint、login-config和security-role等元素。先看下面的一段XML配置:

<security-constraint>
<web-resource-collection>
    <web-resource-name>HelloServlet</web-resource-name>
    <url-pattern>/HelloServlet</url-pattern>
    <http-method>GET</http-method>
    <http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
    <description>This applies only to the" tomcat" security role</description>
    <role-name>admin</role-name>
</auth-constraint>
<user-data-constraint>
    <transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>

其中<security-constraint>元素包含一个或多个<web-resource-collection>元素,它是描述Web应用程序中的那些Web资源受到指定安全限制的保护。<http-method>元素指定安全限制覆盖的HTTP方法。在上面的例子中,当对/HelloServlet的GET或POST请求时将触发配置的安全机制。

<auth-constraint>元素用于描述允许访问Web组件的安全角色。此例中安全角色的例子有tomcat、manager、admin。在上面的例子中,只有当作为admin角色的用户才可以访问HelloServlet。

<login-config>

Web应用程序通过<login-config></login-config>元素来认证用户,并确认该用户是否为正确的角色。<login-config>包含的<transport-guarantee>子元素用来指定认证方法,BASIC就是一种常见的Web认证方式。浏览器给用户提示一个对话框,要求输入用户名和密码,随后Tomcat将给出的用户名和密码与CATALINA/conf/tomcat-users.xml文件中的用户名和密码进行比较,然后使用前面的<security-constraint>配置来确定用户是否可访问受保护的Servlet。除BASIC外,还可以是FORM、CLIENT-CERT、DIGEST等。例如:

<login-config>
<auth-method>BASIC</auth-method>
</login-config>

<security-role>

<security-role></security-role>元素是用来定义安全角色的,它主要有两个元素:<description></description>定义描述说明;<role-name></role-name>定义安全角色名称,<role-name>一般是admin,manager或tomcat。例如:

<security-role>
    <description>
          The role that is required to login to the Admin Application
      </description>
<role-name>admin</role-name>
</security-role>

4.3 Web应用程序示例

通过前面章节的学习,已经对Web应用的配置有了比较详细的认识,在这节将通过一个简单的例子来描述如何建立Web应用程序,如何在应用中进行JSP、Servlet和JavaBean的配置。功能强大、应用复杂的Web应用都可以分解成一个个小的功能模块,同样它的建立和实现也是由一个个小的功能模块,从最简单的应用建立起来、逐步完善的。这里通过一个简单的小例子来说明问题,意在说明一般的方法步骤。

【例4-2】Web应用程序示例

● 创建Web应用目录

(1)在<CATALINA_HOME>/webapps/目录下创建一个Web应用项目的目录,比如Web应用项目名称是myApp,则创建一个myApp目录。myApp项目的目录结构如下所示:

    --/myApp
    //Web应用的根目录。所有的JSP和HTML文件都存放于此目录下,同时也可以根据需要创建多个具有某个含义的
文件目录。比如存放图片的目录/myApp/picture,JavaScript应用目录/myApp/js等。
    --/myApp/myServlet
    //存放Web应用的Servlet类。
    --/myApp/myBean
    //存放Web应用的JavaBean类。
    --/myApp/WEB-INF
    //存放Web应用的发布描述文件web.xml,Context上下文文件等。
    --/myApp/WEB-INF/classes
    //存放各种class文件,Servlet类的Class文件也放于此目录下。
    --/myApp/WEB-INF/lib
    //存放Web应用所需的各种JAR文件。比如JDBC驱动程序的JAR文件。

(2)在WEB-INF目录下创建Web.xml文件,内容如下:

<?xmlversion="1.0"encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC"-//Sun Microsystems,Inc.//DTD Web Application2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
      <display-name>My Web Application</display-name>
      <description>
          Aapplication for test.
      </description>
</web-app>

web.xml文件的具体内容可以根据应用的需要进行配置。配置的元素方法,可以参考前一节的介绍。

● 创建JSP页面

Web应用包含很多动态JSP与静态HTML页面,用于显示和输入信息,与用户进行最直接的交互。

(1)在myApp目录下创建一个测试的JSP页面,文件名为index.jsp,文件内容如下:

<html>
<body>
      <center>
          Welcome to you:This is a test JSP!
      </center>
</body>
</html>

(2)重启Tomcat服务器,打开浏览器,输入http://localhost:8080/myApp/index.jsp,如果看到“Welcome to you:This is a test JSP!”说明成功。

● 创建Servlet类

(1)在/myApp/myServlet目录下创建一个Servlet类,文件名为TestServlet.java,文件内容如下:

importjava.io.IOException;
importjava.io.PrintWriter;
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
publicclassTestServletextendsHttpServlet{
      protectedvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
          throwsServletException,IOException{
      PrintWriterout=response.getWriter();
      out.println("<html><body><h1>Thisisaservlettest.</h1></body></html>");
      out.flush();
      }
}

(2)运行cmd,进入/myApp/myServlet目录后,使用如下命令编译Java类:>javacTestServlet.java,然后在/myApp/myServlet目录下会产生一个编译Servlet后的class文件:TestServlet.class,将TestServlet.class复制到/myApp/WEB-INF/classes目录下。

(3)修改/myApp/WEB-INF/web.xml,添加Servlet和servlet-mapping配置,添加的内容为:

<servlet>
      <servlet-name>TestServlet</servlet-name>
      <display-name>TestServlet</display-name>
    <description>AtestServlet</description>
    <servlet-class>test.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
      <servlet-name>TestServlet</servlet-name>
      <url-pattern>/TestServlet</url-pattern>
</servlet-mapping>
</web-app>

(4)重新启动Tomcat服务器,打开浏览器,输入 http://localhost:8080/myApp/TestServlet,如果看到输出Thisisaservlettest.,就说明刚刚编写的Servlet成功了。

● 创建JavaBean类

(1)在/myApp/myBean目录下创建一个JavaBean类,文件名为TestBean.java,文件内容如下:

publicclassTestBean{
      privateStringname=null;
      publicTestBean(StringstrName_p){
          this.name=strName_p;
      }
      publicvoidsetName(StringstrName_p){
          this.name=strName_p;
      }
      publicStringgetName(){
      returnthis.name;
      }
}

(2)运行cmd,进入/myApp/myBean目录后,使用如下命令编译:>javacTestBean.java,然后在/myApp/myBean目录下会产生一个编译JavaBean后的class文件:TestBean.class,将TestBean.class复制到/myApp/WEB-INF/classes目录下。

(3)在/myApp目录下创建一个TestBean.jsp文件,对TestBean进行应用操作,文件内容如下:

<%@pageimport="test.TestBean"%>
<html>
<body>
<center>
<%TestBeantestBean=newTestBean("This is a test Javabean.");%>
      Javabean name is:<%=testBean.getName()%>
</center>
</body>
</html>

(4)重新启动Tomcat服务器,打开浏览器,输入http://localhost:8080/myapp/TestBean.jsp如果看到输出“Javabean name is: This is a test Javabean.”,就说明刚编写的JavaBean成功了。

4.4 小结

本章主要是介绍了<CATALINA_HOME>/webapps/目录下Web应用程序的管理和配置方法,以及如何建立Web应用程序的一般步骤方法。

在Tomcat 6中,Contexts元素已从server.xml文件中独立出来,无须Tomcat重启服务器,就会自动重新加载context.xml文件,在context.xml文件中指定数据库的JNDI资源信息。web.xml是Web应用系统的主要且重要的描述文件,是Web应用的最基本配置。它指定了系统的一系列设置,比如常用的Servlet控制器和Filter过滤器等的应用都可以在web.xml文件中进行设置。

第5章 使用Tomcat管理工具

【本章导读】

在Tomcat应用中可以直接通过手工修改server.xml文件来配置Tomcat服务器,也可以通过修改web.xml文件来配置Tomcat的Web应用。通过手工直接修改配置文件,需要对配置文件的每个属性都十分了解,对开发人员要求比较高。而且手工修改虽然灵活,但不直观且较为复杂,容易出错。通过Tomcat提供的基于Web方式的管理平台和控制平台,用户就可以很方便直观地配置Tomcat服务器和Web应用。同时Ant是Apache提供给Java开发人员的构建工具,通过Ant可以很方便地构建和管理Web项目。

5.1 Ant管理应用程序

Ant是Apache提供给Java开发人员的构建工具,它可以在Windows系统和Unix系统下运行。Ant是一种基于Java的Build工具,有些类似于Unix系统中的make命令,具有跨平台性、操作简单等特点。

5.1.1安装配置Ant

Ant的下载地址为:http://www.apache.org/dist/ant/binaries,目前Ant的最新版本是1.7.0。下载了apache-ant-1.7.0-bin.zip压缩包后,把它直接解压到本地硬盘,比如C:\apache-ant-1.7.0目录下。解压后的目录如图5-1所示。

图5-1 解压后的Ant目录

其中:

/bin:包含Ant的运行程序文件。

/lib:包含Ant所用到的JAR包资源。

/docs:包含Ant的文档信息资源。

/etc:包含Ant的应用资源。

接下来需要在系统中设置相关的环境变量,环境变量的设置方法步骤可以参考本书第2章2.1节的JDK环境变量的设置方法。需要设置以下的环境变量:

(1)ANT_HOME:Ant的安装目录,即C:\apache-ant-1.7.0。

(2)JAVA_HOME:JDK的安装目录,即C:\Program Files\Java\jdk1.6.0_03。

(3)PATH:把%ANT_HOME%\bin目录加到path变量,以便于从命令行下直接运行Ant,即C:\apache-ant-1.7.0\bin。

为了检验Ant配置安装是否成功,可以通过运行cmd。在cmd模式下输入ant –version,然后按回车键,如果看到有关Ant版本信息的输出,则说明配置成功。如图5-2所示。

图5-2 在cmd模式下查看Ant的版本号

5.1.2 Ant的主要标签

Ant的构建文件是一个XML文件,一般默认命名为build.xml。一个Ant构建文件需要定义一个唯一的项目元素(project元素),还可以定义多个目标元素(target元素)。下面先简要介绍一下Ant的一些主要标签属性,见表5-1所示。

表5-1 Ant的主要标签

5.1.3 建立工程描述文件build.xml

用Ant编译规模较大的工程非常方便。每个工程都对应一个XML文件,一般默认命名为build.xml,这个文件包含与这个工程有关的路径信息和构建任务。

如果是Web项目,通常把构建文件放在顶层目录下,即根目录下,与src文件夹并列。一般构建的Web项目工程目录如下:

tomcat_ant
+--jsp
|
+--src
|
+--WEB-INF
|  +--classes
|  |
|  +--lib
|  |
|  +--web.xml
|
+--build.xml

【例5-1】build.xml文件配置示例

<project name=" tomcat_ant" basedir="." default="dist">
<property name="dist.name" value=" tomcat_ant "/>
<property name="src" location="src"/>
<property name="build" location="WEB-INF/classes"/>
<property name="dist" location="C:/Tomcat 6.0/webapps/dist"/>
<!-- Build working classpath -->
<path id="project.class.path">
      <pathelement path ="WEB-INF/lib/ant.jar"/>
      <pathelement path ="WEB-INF/classes"/>
      <pathelement path ="${classpath}"/>
</path>
<target name="init">
<!-- Create the build directory structure used by compile -->
      <delete dir="${dist}"/>
</target>
<target name="compile" depends="init">
      <javac srcdir="${src}" destdir="${build}">
          <classpath refid="project.class.path"/>
      </javac>
</target>
<!-- Build binary distribution -->
<target name="dist" depends="compile" description="Create binary distribution">
<mkdir dir="${dist}"/>
      <war destfile="${dist}/${dist.name}.war" webxml="WEB-INF/web.xml">
          <lib dir="WEB-INF/lib"/>
          <classes dir="WEB-INF/classes"/>
          <fileset dir="${basedir}"/>
      </war>
</target>
</project>

在每个build.xml文件中都包含一个project和至少一个target元素。target包含任务元素,任务是一段可执行代码,每个任务元素都有一个id属性,以便于在文件中引用。Ant有内置任务集可供使用,如上面文件中用到的property、javac和war,分别完成设置属性、编译和打包任务。各个目标元素之间可以有一定的依赖关系,其中depends指向所依赖的target元素,例如:

<target name="init">
<target name="compile" depends="init">

在上面代码中,target compile依赖于target init,即系统必须先执行完target init后,然后才可以执行target compile。

(1)根元素project

在build.xml文件中根元素是project,它具有3个属性:name、basedir和default。name表示项目名,basedir表示项目的基准目录,default表示默认的运行目标,这个属性是必须的。在上面的project配置中,default属性是“dist”,如下所示:

<project name=" tomcat_ant" basedir="." default="dist">

接着定义了project的几个属性property,指定了构件目录,如下所示:

<property name="dist.name" value="tomcat_ant"/>
<property name="src" location="src"/>
<property name="build" location="WEB-INF/classes"/>
<property name="dist" location="C:/Tomcat 6.0/webapps/dist"/>

(2)classpath

Classpath是指定了生成类的路径。

(3)init target

init target完成了初始化操作,在这里主要是删除${dist}目录。

(4)compile target

compile target依赖于init target,它主要是完成编译Java文件,指明源程序的目录和生成class文件的输出目录。

(5)dist target

dist target依赖于compile target,它主要是完成编译WAR文件。它先建立文件目录,然后生成WAR文件及web.xml文件,指明了生成文件和资源的生成目录。

5.3.4 运行Ant

使用Ant.bat可以直接运行Ant。如果不带任何参数,Ant会在当前路径下搜索build.xml文件。如果找到,就运行project中default指定的target,也可以带参数来选择build.xml文件和要运行的target。

对于上面的例子,假定build.xml所在的目录为C:\Tomcat 6.0\webapps\tomcat_ant,则下面三种执行方式效果是一样的:

● cd C:\Tomcat 6.0\webapps\tomcat_antant

● ant -buildfile C:\Tomcat 6.0\webapps\tomcat_ant\build.xml

● ant -buildfile C:\Tomcat 6.0\webapps\tomcat_ant\build.xml dist

如果执行ant -buildfile C:\Tomcat 6.0\webapps\tomcat_ant\build.xml compile,则执行compile target。

运行了Ant后,可以通过浏览器来运行、应用、查看结果。

5.2 Tomcat控制平台

在Tomcat 5版本中,可以通过运行在网页浏览器配置的应用程序非常方便地进行服务器的配置。这个应用程序被称为Tomcat Administration Web Application,即Tomcat控制平台。然而,在Tomcat 5.5及Tomcat 6的版本中,Binary核心安装版不再提供Tomcat Administration Web Application。要使用Tomcat控制平台,就要单独下载和安装。

5.2.1 创建管理用户

要想使用Tomcat管理平台,就需要有登录的用户及具有相关的操作权限。这可以通过“<CATALINA_HOME>/conf/tomcat-users.xml”文件来创建用户。当你打开tomcat-users.xml文件时,将看到如下所示:

<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
      <role rolename="manager"/>
    <role rolename="admin"/>
    <user username="admin" password="" roles="admin,manager"/>
</tomcat-users>

在tomcat-users.xml文件中创建了两种用户权限角色,即访问管理平台和控制平台的权限:admin和manage。接着创建了一个“admin”的用户,它同时具有访问管理平台和控制平台的权限,其登录密码为空。同时,可以通过在<tomcat-users>和</tomcat-users>之间创建用户来分配用户权限。比如在该文件中添加如下内容:

<user username="manager" password="123" roles="manager"/>
<user username="administrator" password="456" roles="admin"/>

上述代码分别创建了两个用户“manager”和“administrator”,其中用户“manager”具有“manager”权限,可以访问管理平台,访问密码为“123”;用户“administrator”具有“admin”权限,可以访问控制平台,访问密码为“456”。

tomcat-users.xml文件修改后,需要重新启动Tomcat服务器,这样刚添加的用户才可以登录访问,进行操作。

5.2.2 配置Admin应用

目前对于Tomcat 6来说,还没有专门的Admin应用包,但可以下载Tomcat 5.5的Admin应用包,它同样适用于Tomcat 6。具体下载地址为http://tomcat.apache.org/download-55.cgi,下载的Admin应用压缩包为apache-tomcat-5.5.25-admin.zip。同时还需要下载所用到的Apache Commons Modeler和Logging组件,其中commons-modeler具体下载地址为:http://commons.apache.org/downloads/download_modeler.cgi,而commons-logging下载地址为:http://commons.apache.org/downloads/download_logging.cgi。然后,可以按照下面的步骤来完成Admin应用的配置:

(1)把下载的apache-tomcat-5.5.25-admin.zip压缩文件先解压到本地硬盘,比如C:\admin目录下。解压后文件为:C:\admin\apache-tomcat-5.5.25。

(2)将解压后C:\admin\apache-tomcat-5.5.25\目录下的conf和server两个文件夹拷贝到<CATALINA_HOME>目录下。

(3)将commons-modeler-2.0.1.zip和commons-logging-1.1.zip解压后,分别将其commons-modeler-2.0.1.jar和commons-logging-1.1.jar文件拷贝到“<CATALINA_HOME>/lib”目录下。

配置Admin应用后,需要重新启动Tomcat服务器。

5.2.3 登录控制平台

Tomcat控制平台的Web应用位于“<CATALINA_HOME>/webapps/admin”目录下,访问的URL是“http://localhost:8080/admin”。重新启动Tomcat服务器后,打开IE浏览器,在地址栏中输入“http://localhost:8080/admin”,将出现Admin应用的登录页面,如图5-3所示。

图5-3 Admin应用的登录页面

在登录页面输入正确的用户名administrator和密码456,将成功登录控制平台,显示如图5-4所示的控制平台页面。

图5-4 Admin应用的控制平台页面

5.2.4 控制平台的应用

通过Tomcat控制平台,可以配置管理Tomcat服务器的各种元素。Tomcat控制平台的配置信息可以分成3大类:

● Tomcat Server:Tomcat服务配置。

● Resources:资源配置。

● User Definition:用户定义。

(1)Tomcat Server

Tomcat Server用于管理配置Tomcat服务器下的各个应用资源,对应server.xml文件中的<Server>元素。通过控制平台可以查看和修改Server的各种子元素,它们的对应关系与server.xml是一致的。

展开Tomcat Server,在Host(localhost)下将显示“<CATALINA_HOME>/webapps”目录下的所有Web应用项目。每个Web应用项目都包含了Resources资源信息,包括Data Sources、Mail Sessions、Resource Links和Environment Entries等。如果选中某个元素,就可以在右边的展示区显示该元素的属性,并且可以进行编辑。如图5-5所示。

图5-5 控制平台的Tomcat Server

(2)Resources

Resources用于管理配置各种资源信息,包括Data Sources、Mail Sessions、 Environment Entries和User Databases。

● Data Sources:管理配置数据资源JNDI引用。

● Mail Sessions:管理配置电子邮件的服务主机信息。

● Environment Entries:管理配置环境变量。

● User Databases:管理配置用户的数据库信息。

下面以创建JNDI资源引用为例,简要说明管理配置资源信息的基本方法,具体配置应用JNDI的方法将在后面章节详细介绍。展开Resources,选择Data Sources,在右边的Data Source Actions中选择Create New Data Source,在新建立的Data Sources里填写所要配置的信息。假如数据库是mysql,配置如图5-6所示。

图5-6 控制平台创建Data Sources

填写完毕后,需要单击【Save】按钮进行保存,并且需要单击【Commit Changes】按钮进行提交改变,这样创建才会生效。

(3)User Definition

User Definition用于用户的定义,包括Users,Groups和Roles。

● Users:管理配置用户的基本信息,包括用户名、密码、权限和分组信息等。可以创建新的用户、设置密码、分配权限和分组等。

● Groups:管理配置用户的分组信息。可以创建新的用户分组,并且可以进行编辑。

● Roles:Tomcat系统默认的用户角色是admin和manager,admin是登录控制平台的角色,manager是登录管理平台的角色。

下面以创建一个新的用户为例。展开User Definition,选择Users,在右边的User Actions中选择Create New User,并在新建立的User Properties里填写新的用户信息。假如User Name为lpc,密码为123456,所分配的角色为admin,如图5-7所示。

图5-7 控制平台创建User

【提示】

通过Tomcat控制平台进行编辑配置,都需要先“Save”保存,然后通过单击【Commit Changes】按钮进行提交改变,这样创建才会生效。

5.3 Tomcat管理平台

Tomcat管理平台是Tomcat 6自带的一个Web应用。通过Tomcat管理平台可以发布、启动、停止或删除某个Web应用,同时也可以查看Web应用的状态。当需要修改其中某个Web应用时,只需要对该应用进行相关的操作,而不需要操作整个Tomcat服务器,也不会影响其他Web应用的运行。管理平台可以完成以下任务:

● 部署新的Web应用。

● 显示当前已经部署的Web应用,以及Session信息。

● 重载Web应用。

● 显示操作系统和JVM属性。

● 显示可用的全局JNDI资源。

● 显示可用的安全角色。

● 显示Session统计状态。

● 启动已经停止的应用。

● 停止已经运行的应用。

● 卸载Web应用。

5.3.1 登录管理平台

Tomcat管理平台的Web应用位于“<CATALINA_HOME>/webapps/manager”目录下,访问的URL是“http://localhost:8080/manager/html/”。打开IE浏览器,在地址栏中键入“http://localhost:8080/manager/html/”,将出现Manager应用的登录页面,如图5-8所示。

图5-8 Manager应用的登录页面

在登录页面输入正确的用户名manager和密码123,将成功登录管理平台,显示如图5-9所示的管理平台页面。

图5-9 Manager应用的管理平台页面

在图5-9所示的管理平台页面中已经列出了所有的Web应用,以及它们的运用状态。同时,我们可以通过Web应用的Start、Stop、Reload和Undeploy命令来管理某个Web应用,而不需要对整个服务器或别的应用进行操作,保证了其他的Web应用可以照常运行。其中命令的含义如下所示:

● Start:启动Web应用。

● Stop:停止Web应用。

● Reload:重新启动Web应用。

● Undeploy:移除Web应用,并且删除<CATALINA_HOME>/webapps目录下对应的Web应用文件内容。

5.3.2 管理平台发布Web应用

Tomcat管理平台除了可以管理Web应用外,还可以发布Web应用。在前面的章节中,我们已经知道可以把Web应用直接发布在<CATALINA_HOME>/webapps目录下,但发布后需要重新启动服务器。而通过Tomcat管理平台发布Web应用,则可以不需要重新启动服务器,实现热部署。

Tomcat管理平台提供了两种发布方式:一种方式是发布位于<CATALINA_HOME>/webapps目录下的Web应用,而另一种方式是发布位于文件系统任意位置的WAR文件。在Tomcat管理平台中,发布Web应用的页面如图5-10所示。

图5-10 发布Web应用的页面

【例5-2】发布“helloWorld” Web应用示例

下面通过具体的例子来说明Tomcat管理平台使用两种发布方式发布Web应用的方法。为了便于说明这两种发布方式的应用方法,下面的步骤是先采用第一钟方式进行发布,然后删除,再采用第二种方式进行发布应用。

假如要发布一个名为“helloWorld”的Web应用,文件名为“helloWorld.war”。可以按照下面的步骤来进行:

1 先把helloWorld.war文件拷贝到<CATALINA_HOME>/webapps目录下,在管理平台页面的“Deploy|Deploy directory or WAR file located on server”一栏中输入Web应用Context Path(上下文路径)、XML Configuration file URL(XML配置文件URL)和WAR or Directory URL(WAR文件或目录URL)等信息,如图5-11所示。

图5-11 发布位于<CATALINA_HOME>/webapps目录下的应用

然后单击【Deploy】按钮进行发布。待发布完成后,可以通过访问“http://localhost:8080/helloWorld/index.htm”来检验发布是否成功。

2 选择“Undeploy”命令移除helloWorld的应用,然后再进入<CATALINA_HOME>/webapps目录,将发现helloWorld.war文件已经被删除。

3 先把helloWorld.war文件拷贝到文件系统的任意位置,比如D盘根目录D:\ helloWorld.war,在管理平台页面的“WAR file to deploy”一栏中选择D盘根目录的D:\ helloWorld.war文件,如图5-12所示。

图5-12 发布位于任意文件系统目录下的应用

然后单击【Deploy】按钮进行发布。待发布完成后,可以通过访问“http://localhost:8080/helloWorld/index.htm”来检验发布是否成功。同时如果发布成功,进入<CATALINA_HOME>/webapps目录,将发现helloWorld.war文件已经被拷贝进来。

5.4 小结

本章主要是介绍了Tomcat提供的基于Web方式的管理平台和控制平台的使用方法,同时也介绍了利用Ant构建和管理Web项目的一般方法步骤。

Ant是Apache提供给Java开发人员的构建工具,通过Ant可以很方便地构建和编译Web项目。一般一个工程都对应一个默认名为build.xml的文件,通过该文件完成工程的构建和编译任务。通过Tomcat提供的基于Web方式的管理平台和控制平台,用户可以很方便直观地配置Tomcat服务器和Web应用,而无须手工修改。通过Tomcat控制平台可以完成Tomcat服务配置、资源配置和用户定义;通过Tomcat管理平台则可以发布、启动、停止或删除某个Web应用,同时也可以查看Web应用的运行状态。