<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>agapple</title>
    <description></description>
    <link>http://agapple.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>（tomact , jboss) WEB调试配置</title>
        <author>agapple</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://agapple.javaeye.com">agapple</a>&nbsp;
          链接：<a href="http://agapple.javaeye.com/blog/181103" style="color:red;">http://agapple.javaeye.com/blog/181103</a>&nbsp;
          发表时间: 2008年04月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          DEBUG方法， 我这里讲下WIN的，LINUX下修改对应的sh即可
如果是TOMACT ， 修改 %TOMACT_HOME%/bin/catalina.bat 中
搜索DEBUG_OPTS 改成如下内容，address为你需要调试的端口,suspend=y表明需要挂住应用，等待你客户端DEBUG连接，这样就可以调试一下servlet , filter , listener启动 。
set DEBUG_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=8000,suspend=n

如果是JBOSS , 在%JBOSS_HOME%/bin/run.bat中，找到JAVA_OPTS，去掉前面的屏蔽语句（rem），改为
set JAVA_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,address=7009,server=y,suspend=n %JAVA_OPTS%

然后打开eclipse


          <br/>
          <span style="color:red;">
            <a href="http://agapple.javaeye.com/blog/181103#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 10 Apr 2008 09:45:51 +0800</pubDate>
        <link>http://agapple.javaeye.com/blog/181103</link>
        <guid>http://agapple.javaeye.com/blog/181103</guid>
      </item>
      <item>
        <title>Class文件</title>
        <author>agapple</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://agapple.javaeye.com">agapple</a>&nbsp;
          链接：<a href="http://agapple.javaeye.com/blog/173862" style="color:red;">http://agapple.javaeye.com/blog/173862</a>&nbsp;
          发表时间: 2008年03月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          一、Java Class文件是什么 <br />《The JavaTM Virtual Machine Specification》(Second Edtion)中有表述：Java Class文件由8位字节流组成，所有的16位、32位和64位数据分别通过读入2个、4个和8个字节来构造，多字节数据总是按照Big-endian顺序来存放，即高位字节在前(放在低地址)。每个Class文件都包含且仅包含一个Java类型(类或者接口)。<br /><br />或许，《The JavaTM Virtual Machine Specification》中的表述不够明确，那么我们可以参考一下《Inside the Java Virtual Machine》(Second Edtion)中的表述：Java Class文件特指以.class为后缀名的Java虚拟机可装载的文件。<br /><br />分析一下两者的表述，我觉得都不够全面、不够明确。我是这么定义的：Java Class文件就是指符合特定格式的字节流组成的二进制文件。这个特定的格式就是指第二节要讨论的Class文件格式，亦即在《The JavaTM Virtual Machine Specification》中定义的Class文件格式。从另一个角度来说，这个特定格式就是指JVM能够识别、能够装载的格式。为什么这么说呢？因为JVM在装载class文件时，要进行class文件验证，以保证装载的class文件内容符合正确的内部结构。这个内部结构指的就是这个特定格式，只要是符合这个特定格式的Class文件都是合法的、规范的Class文件，都是JVM能够装载的Class文件。如果觉得这样的表述还是不够明确，我只能建议你读完这篇文章之后再回头来理解看看了J<br /><br />为了讨论方便，在下文中将对这两个参考资料做个简记：<br /><br />1)《The Java Virtual Machine Specification》(Second Edtion)简记为《JVM Spec》(2nded)。<br /><br />2)《Inside the Java Virtual Machine》(Second Edtion) 简记为《Inside JVM》(2nded)。<br /><br />二、Java Class文件的格式<br /><br />在讲Class文件的格式之前，要介绍三个概念：<br /><br />1)数据类型：《JVM Spec》(2nded)中指出，Java Class文件的数据用自己定义的一个数据类型集来表示，即u1，u2，u4，分别用于表示一个无符号类型的、占1，2，4个字节的数据。在《Inside JVM》(2nded)一书中，作者把这个数据类型集称之为Class文件的基本类型，本人觉得比较形象，便于理解。所以，在本文中，我们也用基本类型来表示Java Class文件的数据。<br /><br />2)表：根据《JVM Spec》(2nded)中的定义，表(table)由项（定义见3）组成，用于几种Class文件结构中。《JVM Spec》(2nded)中指出，Java Class文件格式用一个类似于C结构的记号编写的伪结构来表示。这个伪结构指的就是这里的表，例如下面的ClassFile表就是这种伪结构的一个典型例子，下文中所有的表都是指这种伪结构的表。表的大小是可变的，这是因为它的组成部分项是可变的。注意；这里的可变是针对Class层次而言的，即在不同的Class文件中该项的大小可能不一样的，但是对于每一个具体的Class文件来说，这个项的大小又是一定的，因而这个表的大小也是一定的。那么，项为什么是可变的呢？请看下面的分析。<br /><br />3)项：描述Java Class文件格式的结构的内容称为项(items)。每个项都有自己的类型和名称。项的类型可能是基本类型，也可能是一个表的名字，这种项都是一些数组项。数组项的每一个元素都是一个表，这个表同顶层的ClassFile表一样，也都是一种伪结构，也都是由一些项构成的，而且这些表不一定是同一种格式的，因此数组项也可以看作一个可变大小的结构流J。这些表对于该数组项来说就是子项，当然子项可能还有子项(目前子项的深度最多就两层)。项的名称，没有什么好说的，就是《JVM Spec》(2nded)中指定的一些名称。另外，项也是有大小的，对于没有子项的项来说，其大小是固定的；对于有子项的项来说，其大小是可变的。在一个具体的Class文件中，一个可变项(数组)的大小都会在其前一项中指定，为什么会是这样的呢？因为《JVM Spec》(2nded)中就是这么定义的！在Class文件中，每个项按规范中定义好的顺序存储在Class文件中，相邻的项之间没有任何间隔，连续的项（数组）也是按顺序存储，不进行填充或者对齐，这样可以使Class文件紧凑。<br /><br />好了，我想这三个概念我已经解释地比较清楚了，下面开始正式解析Class文件的格式。<br /><br />首先要来解析一下ClassFile表结构，这是《JVM Spec》(2nded)中定义的Class文件最外层的结构，换言之，就是Class文件的格式。<br /><br /><br />ClassFile表结构<br />    ClassFile {<br />        u4 magic;<br /><br />        u2 minor_version;<br /><br />        u2 major_version;<br /><br />        u2 constant_pool_count;<br /><br />        cp_info constant_pool[constant_pool_count-1];<br /><br />        u2 access_flags;<br /><br />        u2 this_Class;<br /><br />        u2 super_Class;<br /><br />        u2 interfaces_count;<br /><br />        u2 interfaces[interfaces_count];<br /><br />        u2 fields_count;<br /><br />        field_info fields[fields_count];<br /><br />        u2 methods_count;<br /><br />        method_info methods[methods_count];<br /><br />        u2 attributes_count;<br /><br />        attribute_info attributes[attributes_count];<br /><br />    }<br /> <br />ClassFile表结构由16个不同的项组成，其中的各项可以简要地分析如下：<br /><br />(1) magic<br /><br />每个Class文件的前4个字节被称为它的魔数（magic number）: 0xCAFEBABE。魔数的作用在于：可以轻松地分辨出Java Class文件和非Java Class文件。（如果一个文件不是以0xCAFEBABE开头，它就肯定不是Java Class文件，因为它不符合规范J）。当Java还称为“Oak”的时候，这个魔数就已经定下来了，它预示了Java这个名字的出现。魔数的来历请大家自己查阅J<br /><br />(2) minor_version和major_version<br /><br />Class文件的下面4个字节包含了次、主版本号。通常只有给定主版本号和一系列次版本号后，Java虚拟机才能够读取Class文件。如果Class文件的版本号超出了Java虚拟机所能够处理的有效范围，Java虚拟机将不会处理该Class文件。例如J2SE5.0版本的虚拟机就不能执行由J2SE6.0版本的编译器编译出来的Class文件。<br /><br />(3) constant_pool_count<br /><br />版本号后面的项是constant_pool_count即常量池计数项，该项的值必须大于零，它给出该Class文件中常量池列表项的元素个数，这个计数项包括了索引为0的constant_pool表项，但是该表项不出现在Class文件的constant_pool列表中，因为它被保留为Java虚拟机内部实现使用了，因此常量池列表的元素个数constant_pool_count-1，各个常量池表项的索引值分别为1到constant_pool_count-1。<br /><br />注：在这里，有几个术语需要解释一下，常量池即为constant_pool，常量池列表就是指constant_pool[ ]，常量池表项即指常量池列表中的某一个具体的表项(元素)。这些常量池表项的可能类型如下述的cp_type表所示：<br /><br />cp_type<br />入口类型                                标志值 <br /><br />CONSTANT_Class                           7 <br /><br />CONSTANT_Fieldref                        9 <br /><br />CONSTANT_Methodref                       10 <br /><br />CONSTANT_InterfaceMethodref              11 <br /><br />CONSTANT_String                           8 <br /><br />CONSTANT_Integer                          3 <br /><br />CONSTANT_Float                            4 <br /><br />CONSTANT_Long                             5 <br /><br />CONSTANT_Double                           6 <br /><br />CONSTANT_NameAndType                      12 <br /><br />CONSTANT_Utf8                              1<br /> <br /><br />(4) constant_pool[ ]<br /><br />constant_pool_count项下面是constant_pool[ ]项，即常量池列表，其中存储了该ClassFile结构及其子结构中引用的各种常量，诸如文字字符串、final变量值、类名和方法名等等。在Java Class文件中，常量池表项是用一个cp_info结构来描述的，常量池列表就是由constant_pool_count-1个连续的、可变长度的cp_info表结构构成的constant_pool[ ]数组。为什么是constant_pool_count-1个constant_pool的原因，在上面已经解释了。每一个常量池表项都是一个变长结构，其通常格式如下所示：<br /><br />cp_info<br />cp_info {<br />        u1 tag;<br />        u1 info[];<br />    }<br /><br />cp_info表的tag项是一个无符号的byte类型值，它表明了cp_info表的类型和格式，具体的tag类型见上表。<br /><br />需要说明的是，cp_info只是一个抽象的概念，在Class文件中，它表现为一系列具体的、形如CONSTANT_Xxxx_info的constant_pool结构，其具体的格式由cp_info表的tag项（即第一个字节）来确定。不同的cp_info表，其info[]项也是不一样的，例如，CONSTANT_Class_info表的info[]项为“u2 name_index”，而CONSTANT_Utf8_info表的info[]项为“u2 length; u1 bytes[length];”，显然，这两个cp_info表是不一样的，大小更是不一样的，因而常量池表项的大小是可变的。由于常量池列表中的每个常量池表项的结构是不一样，因此常量池列表的大小也是可变的。在Class文件中，常量池列表项是一个可变长度的结构流。<br /><br />由cp_info表以及cp_type表我们可以知道，若cp_info表中tag(标志)项的值为1时，当前的cp_info就是一个CONSTANT_Utf8_info表结构，若cp_info表中tag项的值为3，当前的cp_info就是一个CONSTANT_Integer_info表结构，其它情况类推。这些表的结构可以查阅《JVM Spec》(2nded)的第四章或者《Inside JVM》(2nded)的第六章。<br /><br />(5) access_flags<br /><br />紧接常量池后的两个字节称为access_flags，access_flags项描述了该Java类型的一些访问标志信息。例如，访问标志指明文件中定义的是类还是接口；访问标志还定义了在类或接口的声明中，使用了哪些修饰符；类和接口是抽象的还是公共的等等。实际上，access_flags项的值是Java类型声明中使用的访问标志符的掩码(mask，这里掩码指的是access_flags的值是所有访问标志值的总和，当然，未被使用的标志位在Class文件中都被设置为0。例如，若access_flags的值就是0x0001，就表示该Java类型的访问标志符是ACC_PUBLIC；若access_flags的值是0x0011，就表示该Java类型的访问标志符是ACC_PUBLIC和ACC_FINAL，因为只有这两个标志位的和才可能是0x0011；其它情况类推)。<br /><br />一个Java类型的所有access_flags标志符如下表所示：<br /><br /><br /><br />access_flags<br />标志名称         值           含义<br /><br />ACC_PUBLIC     0x0001   声明为public，可以从它的包外访问<br /><br />ACC_FINAL      0x0010   声明为final，不允许有子类<br /><br />ACC_SUPER      0x0020   用invokespecial指令处理超类的调用<br /><br />ACC_INTERFACE  0x0200   表明是一个接口，而不是一个类<br /><br />ACC_ABSTRACT   0x0400   声明为abstract，不能被实例化<br /> <br />需要说明的是，这是针对一个Java类型的访问标志符列表，有的标志符只有类可以使用，有的标志符只有接口才可以使用，详情请查阅《JVM Spec》(2nded)。<br /><br />(6) this_class<br /><br />接下来的两个字节为this_class项,其值为一个对常量池表项的索引，即它指向一个常量池表项，而且该常量池表项必须为CONSTANT_Class_info表的结构。该表有一个name_index项，该项将指向另一个常量池表项，该表项包含了该类或者接口的完全限定名称。<br /><br />(7) super_class<br /><br />紧接着this_class之后的两个字节是super_class项，该项必须是对常量池表项的一个有效索引或者值为0。如果super_class项的值为0，则该Class文件必须表示java.lang.Object类。如果super_class项的值不为0，则又分为两种情况，若该Class文件表示一个类，则super_class项必须是对常量池中该类的超类的CONSTANT_Class_info表项的索引，这个超类和它的任何超类都不能是一个final类；若该Class文件表示一个接口，则super_class项必须是对常量池中表示java.lang.Object类的一个CONSTANT_Class_info表项的索引。<br /><br />(8) interfaces_count和interfaces[ ]<br /><br />紧接着super_class项后面的两个字节是interfaces_count项，此项表示由该类直接实现或者由该接口所扩展的超接口的数量。<br /><br />紧接着interfaces_count项后面的是interfaces列表项，它包含了由该类直接实现或者由该接口所扩展的超接口的常量池索引，共计interfaces_count个索引。interfaces列表中的常量池索引按照该类型在源代码中给定的从左到右的顺序排列。<br /><br />(9) fields_count和fields[ ]<br /><br />接下来的是fields_count项，该项的值给出了fields列表项中的field_info表结构的数量，即表示了该Java类型声明的类变量和实例变量的个数总和。<br /><br />fields列表项包含了在该Java类型中声明的所有字段的完整描述。fields列表中的每个field_info表项都完整地表示了一个字段的信息，包括该字段的名称、描述符和修饰符等。这些信息有的放在field_info表中，如修饰符；有的则放在field_info表所指向的常量池中，如名字和描述符。同前面的分析，fields列表项也是一个变长结构。    <br /><br />需要说明的是，只有在该Java类型中声明的字段才可能在fields列表中列出，fields列表中不包括从超类或者超接口中继承而来的字段信息。<br /><br />(10) methods_count和methods[ ]<br /><br />在Class文件中，紧接着fields后面的是对在该Java类型中所声明的方法的描述。首先是methods_count项，它占两个字节长度，它的值表示对该Java类型中声明的所有方法的总计数。methods_count项后面是methods列表项，它由methods_count个连续的method_info表构成。每个method_info表都包含了与一个方法相关的信息，如方法名、描述符（即方法的返回值及参数类型）以及一些其它信息。如果一个方法既非abstract也非native，那么该method_info表将包含该方法局部变量所需的栈空间长度、为方法所捕获的异常表、字节码序列以及可选的行号表和局部变量表等信息。<br /><br />需要说明的是，只有在该Java类型中显式定义的方法才可能在fields列表中列出，fields列表中不包括从超类或者超接口中继承而来的方法信息。<br /><br />(11) attributes_count和attributes[ ]<br /><br />Class文件中最后的部分是属性（attribute）,它给出了在该Java类型中所定义的属性的基本信息。首先是attributes_count项，它占两个字节长度，它的值表示在后续的attributes列表中的attributes_info表的总个数。每个attributes_info表的第一项都是对常量池中CONSTANT_Utf8_info表项的一个索引，该表给出了此属性的名称。<br /><br />需要说明的是，属性有很多种，在Class文件中的很多地方都出现了属性这一项，在顶层ClassFile表中有attributes属性项，在field_info表中也有attributes属性项，在method_info中也有attributes属性项，但是它们各有各的功能，详见上述分析。在《JVM Spec》(2nded)中，为ClassFile表结构的attributes列表项定义的唯一属性是SourceFile属性，为field_info表结构的attributes列表项定义的唯一属性是ConstantValue属性，为method_info表结构的attributes列表项定义的属性是Code属性和Exceptions属性。<br /><br />总而言之，Class文件格式是一个规范性的格式。这个规范指的就是，上面提到的这些表结构本身的规范性，以及这些表结构之间的包含关系的规范性。实际上，《JVM Spec》(2nded)中就是通过表和项这两个概念来组织Class文件的格式的。首先，ClassFile表就是Class文件最外层的结构，换言之，这就是Class文件的格式。其次，ClassFile表又是一些项组成的，这些项的内容都要符合《JVM Spec》(2nded)中定义的规范，具体来说，若这个项的类型是基本类型，该项的值要符合规范，例如magic项一定要是0xCAFEBABE，access_flags项的值一定要是有效的标志值等等；若这个项的类型是一个表名，即该项是一个数组项，那么该数组项列表中的每一个表项都要是一个合法的、规范的表，不能是一个规范中没有定义的新表，这就是包含关系的规范性，同样，列表项中的每个表项本身也都要是符合其规范定义的表项，例如常量池列表中的某个CONSTANT_Class_info表的name_index项不是对一个CONSTANT_Utf8_info表结构的索引，那么这个常量池的表项就不是一个合法的表项，因而这个常量池列表项就是不符合规范的，因而整个文件就是不符合规范的。
          <br/>
          <span style="color:red;">
            <a href="http://agapple.javaeye.com/blog/173862#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 19 Mar 2008 18:33:39 +0800</pubDate>
        <link>http://agapple.javaeye.com/blog/173862</link>
        <guid>http://agapple.javaeye.com/blog/173862</guid>
      </item>
      <item>
        <title>web.xml 模板</title>
        <author>agapple</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://agapple.javaeye.com">agapple</a>&nbsp;
          链接：<a href="http://agapple.javaeye.com/blog/151366" style="color:red;">http://agapple.javaeye.com/blog/151366</a>&nbsp;
          发表时间: 2007年12月27日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">&lt;webapp>

	&lt;description>站台描述&lt;/discription>

	&lt;display-name>MyListeningApplication&lt;/display-name>

	&lt;!-- 指向web站台中某个小图标的路径,大小为16 X 16 pixel,GIF或JPEG格式,扩展名必须为:.gif或.jpg-->

  &lt;!-- 指向web站台中某个大图表路径,大小为32 X 32 pixel,GIF或JPEG的格式,扩展名必须为; gif或jpg-->

	&lt;icon>

   &lt;small-icon>/images/small.gif&lt;/small-icon>

   &lt;large-icon>/images/large.gir&lt;/large-icon>

	&lt;/icon>

	

	&lt;!-- distributable 元素为空标签,它的存在与否可以指定站台是否可分布式处理.

	 如果web.xml中出现这个元素,则代表站台在开发时已经被设计为能在多个JSP Container 之间分散执行. -->

	&lt;distributable/>

	

	&lt;!-- context-param 元素用来设定web站台的环境参数(context) -->

	&lt;!-- getServletContext().getInitParamter("param_name"); 	-->

	&lt;context-param>

   &lt;param-name>param_name&lt;/param-name>

   &lt;param-value>param_value&lt;/param-value>

	&lt;/context-param>



	

	&lt;filter>

			&lt;filter-name>Test Filter&lt;/filter-name>

			&lt;filter-class>com.alibaba.filter.testFilter&lt;/filter-class>

			&lt;init-param>

					&lt;param-name>Encodeing&lt;/param-name>

					&lt;param-value>GBK&lt;/param-value>

					&lt;param-name>timeout&lt;/param-name>

					&lt;param-value>90&lt;/param-value>

			&lt;/init-param>

			&lt;filter-mapping>

					&lt;filter-name>Test Filter&lt;/filter-name>

					&lt;url-pattern>/*&lt;/url-pattern>

			&lt;/filter-mapping>

	&lt;/filter>

	

	&lt;listener>

			&lt;listener-class>com.acme.MyConnectionManager&lt;/listen-class>

	&lt;/listener>

	&lt;listenrer>

			&lt;listener-class>com.acme.MyLoggingModele&lt;/listener-class>

	&lt;/listener>

	

	&lt;servlet>

		 &lt;display-name>MyServlet&lt;/display-name>

		 &lt;servlet-name>MyServlet&lt;/servlet-name>

		 &lt;servlet-class>com.mycorp.CatalogServlet&lt;/servlet-class>

		 &lt;init-param>

					&lt;param-name>catalog&lt;/param-name>

					&lt;param-value>Spring&lt;/param-value>

			&lt;/init-param>

	&lt;/servlet>

	&lt;servlet-mapping>

			&lt;servlet-name>catalog&lt;/servlet-name>

			&lt;url-pattern>/catalog/*&lt;/url-pattern>

	&lt;/servlet-mapping>

	

	&lt;!-- 定义首页的文件名，服务器会依照设定的顺序来找首页 -->

	&lt;welcome-file-list>

  	&lt;welcome-file>index.jsp&lt;/welcome-file>

  	&lt;welcome-file>index.htm&lt;/welcome-file>

	&lt;/welcome-file-list>



	

	&lt;!-- 设置session 超时时间 ,单位 分-->

	&lt;session-config>

   	&lt;session-timeout>20&lt;/session-timeout>

	&lt;/session-config>

	

	&lt;!-- mime-mapping包含两个子元素extension和mime-type.定义某一个扩展名和某一MIME Type做对映  -->

	&lt;mime-mapping>

   &lt;extension>doc&lt;/extension>

   &lt;mime-type>application/vnd.ms-word&lt;/mime-type>

	&lt;/mime-mapping>

	&lt;mime-mapping>

   &lt;extension>xls&lt;/extension>

   &lt;mime-type>application/vnd.ms-excel&lt;/mime-type>

	&lt;/mime-mapping>

	&lt;mime-mapping>

   &lt;extension>ppt&lt;/extesnion>

   &lt;mime-type>application/vnd.ms-powerpoint&lt;/mime-type>

&lt;/mime-mapping>



&lt;!-- 包含三个子元素error-code,exception-type和location  -->

&lt;!-- 将错误代码(Error Code)或异常(Exception)的种类对应  -->

&lt;!-- 到web站台资源路径 																	-->

	&lt;error-page>

   &lt;error-code>404&lt;/error-code>

   &lt;location>/error404.jsp&lt;/location>

	&lt;/error-page>

	&lt;error-page>

   &lt;exception-type>java.lang.Exception&lt;/exception-type>

   &lt;location>/except.jsp&lt;/location>

	&lt;/error-page>

	

	&lt;!--  &lt;description>说明&lt;/description> 资源说明

				&lt;rec-ref-name>资源名称&lt;/rec-ref-name>资源名称

				&lt;res-type>资源种类&lt;/res-type>资源种类

				&lt;res-auth>Application|Container&lt;/res-auth>资源由Application或Container来许可

				&lt;res-sharing-scope>Shareable|Unshareable&lt;/res-sharing-scope>资源是否可以共享.默认值为 Shareable

	-->

	&lt;resource-ref>

   &lt;description>JNDI JDBC DataSource of JSPBook&lt;/description>

   &lt;res-ref-name>jdbc/sample_db&lt;/res-ref-name>

   &lt;res-type>javax.sql.DataSoruce&lt;/res-type>

   &lt;res-auth>Container&lt;/res-auth>

	&lt;/resource-ref>

	&lt;!--  安全登录控制 -->
	&lt;security-constraint>
		&lt;!-- 指定保护的资源 -->
		&lt;web-resource-coolection>
			&lt;web-resource-name>Proprietary&lt;/web-resource-name>
			&lt;url-pattern>/propritary/*&lt;/url-pattern>
		&lt;/web-resource-coolection>
		&lt;!-- install_dir/conf/tomcat-users.xml将用户名与角色名和口令相关联 ,可按如下配置 -->
	        &lt;!--
		&lt;tomcat-users>
			&lt;user name="joe" password="bigshot" roles="administrator,kahuna" />
			&lt;user name="jane" password="enaj" roles="kahuna" />
		&lt;/tomcat-users>
		  -->
		&lt;auth-constraint>
			&lt;role-name>administrator&lt;/role-name>
			&lt;role-name>kahuna&lt;/role-name>
		&lt;/auth-constraint>
		&lt;!--包含的值为 NONE、 INTEGRAL或CONFIDENTIAL  -->
		&lt;!-- NONE值将对所用的通讯协议不加限制 -->
		&lt;!--INTEGRAL和CONFIDENTIAL 简单地要求用SSL -->		
		&lt;user-data-constraint>
			&lt;transport-guarantee>CONFIDENTIAL&lt;/transport-guarantee>
		&lt;/user-data-constraint>
	&lt;/security-constraint>

	 &lt;!--  --------------------------------------------   -->
	&lt;!-- 登录控制 -->		
	&lt;login-config>
		&lt;auth-method> FORM &lt;/auth-method>
		&lt;form-login-config>
 			&lt;form-login-page>/login.jsp&lt;/form-login-page>
			&lt;form-error-page>/login-error.jsp&lt;/form-error-page>
		&lt;/form-login-config>
	&lt;/login-config>
	 &lt;!--  --------------------------------------------   -->
      &lt;!--调用 request.isUserInRole（"boss"） -->
	&lt;security-role-ref>
		&lt;role-name>boss&lt;/role-name> &lt;!-- New alias -->
		&lt;role-link>manager&lt;/role-link> &lt;!-- Real name -->
	&lt;/security-role-ref>


&lt;/webapp></pre>
          <br/>
          <span style="color:red;">
            <a href="http://agapple.javaeye.com/blog/151366#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 27 Dec 2007 23:06:50 +0800</pubDate>
        <link>http://agapple.javaeye.com/blog/151366</link>
        <guid>http://agapple.javaeye.com/blog/151366</guid>
      </item>
      <item>
        <title>（转）认识Tomcat中用web.xml控制Web应用</title>
        <author>agapple</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://agapple.javaeye.com">agapple</a>&nbsp;
          链接：<a href="http://agapple.javaeye.com/blog/151362" style="color:red;">http://agapple.javaeye.com/blog/151362</a>&nbsp;
          发表时间: 2007年12月27日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">1 定义头和根元素

部署描述符文件就像所有XML文件一样，必须以一个XML头开始。这个头声明可以使用的XML版本并给出文件的字符编码。

DOCYTPE声明必须立即出现在此头之后。这个声明告诉服务器适用的servlet规范的版本（如2.2或2.3）并指定管理此文件其余部分内容的语法的DTD(Document Type Definition，文档类型定义)。

所有部署描述符文件的顶层（根）元素为web-app。请注意，XML元素不像HTML，他们是大小写敏感的。因此，web-App和WEB-APP都是不合法的，web-app必须用小写。

 
2 部署描述符文件内的元素次序

 

XML元素不仅是大小写敏感的，而且它们还对出现在其他元素中的次序敏感。例如，XML头必须是文件中的第一项，DOCTYPE声明必须是第二项，而web-app元素必须是第三项。在web-app元素内，元素的次序也很重要。服务器不一定强制要求这种次序，但它们允许（实际上有些服务器就是这样做的）完全拒绝执行含有次序不正确的元素的Web应用。这表示使用非标准元素次序的web.xml文件是不可移植的。

下面的列表给出了所有可直接出现在web-app元素内的合法元素所必需的次序。例如，此列表说明servlet元素必须出现在所有servlet-mapping元素之前。请注意，所有这些元素都是可选的。因此，可以省略掉某一元素，但不能把它放于不正确的位置。

l icon icon元素指出IDE和GUI工具用来表示Web应用的一个和两个图像文件的位置。

l display-name display-name元素提供GUI工具可能会用来标记这个特定的Web应用的一个名称。

l description description元素给出与此有关的说明性文本。

l context-param context-param元素声明应用范围内的初始化参数。

l filter 过滤器元素将一个名字与一个实现javax.servlet.Filter接口的类相关联。

l filter-mapping 一旦命名了一个过滤器，就要利用filter-mapping元素把它与一个或多个servlet或JSP页面相关联。

l listener servlet API的版本2.3增加了对事件监听程序的支持，事件监听程序在建立、修改和删除会话或servlet环境时得到通知。Listener元素指出事件监听程序类。

l servlet 在向servlet或JSP页面制定初始化参数或定制URL时，必须首先命名servlet或JSP页面。Servlet元素就是用来完成此项任务的。

l servlet-mapping 服务器一般为servlet提供一个缺省的URL：http://host/webAppPrefix/servlet/ServletName。但是，常常会更改这个URL，以便servlet可以访问初始化参数或更容易地处理相对URL。在更改缺省URL时，使用servlet-mapping元素。

l session-config 如果某个会话在一定时间内未被访问，服务器可以抛弃它以节省内存。可通过使用HttpSession的setMaxInactiveInterval方法明确设置单个会话对象的超时值，或者可利用session-config元素制定缺省超时值。

l mime-mapping 如果Web应用具有想到特殊的文件，希望能保证给他们分配特定的MIME类型，则mime-mapping元素提供这种保证。

l welcom-file-list welcome-file-list元素指示服务器在收到引用一个目录名而不是文件名的URL时，使用哪个文件。

l error-page error-page元素使得在返回特定HTTP状态代码时，或者特定类型的异常被抛出时，能够制定将要显示的页面。

l taglib taglib元素对标记库描述符文件（Tag Libraryu Descriptor file）指定别名。此功能使你能够更改TLD文件的位置，而不用编辑使用这些文件的JSP页面。

l resource-env-ref resource-env-ref元素声明与资源相关的一个管理对象。

l resource-ref resource-ref元素声明一个资源工厂使用的外部资源。

l security-constraint security-constraint元素制定应该保护的URL。它与login-config元素联合使用

l login-config 用login-config元素来指定服务器应该怎样给试图访问受保护页面的用户授权。它与sercurity-constraint元素联合使用。

l security-role security-role元素给出安全角色的一个列表，这些角色将出现在servlet元素内的security-role-ref元素的role-name子元素中。分别地声明角色可使高级IDE处理安全信息更为容易。

l env-entry env-entry元素声明Web应用的环境项。

l ejb-ref ejb-ref元素声明一个EJB的主目录的引用。

l ejb-local-ref ejb-local-ref元素声明一个EJB的本地主目录的应用。

 
3 分配名称和定制的UL

 

在web.xml中完成的一个最常见的任务是对servlet或JSP页面给出名称和定制的URL。用servlet元素分配名称，使用servlet-mapping元素将定制的URL与刚分配的名称相关联。
3.1 分配名称

为了提供初始化参数，对servlet或JSP页面定义一个定制URL或分配一个安全角色，必须首先给servlet或JSP页面一个名称。可通过 servlet元素分配一个名称。最常见的格式包括servlet-name和servlet-class子元素（在web-app元素内），如下所示：

&lt;servlet>

&lt;servlet-name>Test&lt;/servlet-name>

&lt;servlet-class>moreservlets.TestServlet&lt;/servlet-class>

&lt;/servlet>

 

这表示位于WEB-INF/classes/moreservlets/TestServlet的servlet已经得到了注册名Test。给 servlet一个名称具有两个主要的含义。首先，初始化参数、定制的URL模式以及其他定制通过此注册名而不是类名引用此servlet。其次,可在 URL而不是类名中使用此名称。因此，利用刚才给出的定义，URL http://host/webAppPrefix/servlet/Test 可用于 http://host/webAppPrefix/servlet/moreservlets.TestServlet 的场所。

请记住：XML元素不仅是大小写敏感的，而且定义它们的次序也很重要。例如，web-app元素内所有servlet元素必须位于所有servlet- mapping元素（下一小节介绍）之前，而且还要位于5.6节和5.11节讨论的与过滤器或文档相关的元素（如果有的话）之前。类似地，servlet 的servlet-name子元素也必须出现在servlet-class之前。5.2节"部署描述符文件内的元素次序"将详细介绍这种必需的次序。

例如，程序清单5-1给出了一个名为TestServlet的简单servlet，它驻留在moreservlets程序包中。因为此servlet是扎根在一个名为deployDemo的目录中的Web应用的组成部分，所以TestServlet.class放在deployDemo/WEB- INF/classes/moreservlets中。程序清单5-2给出将放置在deployDemo/WEB-INF/内的web.xml文件的一部分。此web.xml文件使用servlet-name和servlet-class元素将名称Test与TestServlet.class相关联。图 5-1和图5-2分别显示利用缺省URL和注册名调用TestServlet时的结果。

 

程序清单5-1 TestServlet.java

package moreservlets;

 

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

 

/** Simple servlet used to illustrate servlet naming

* and custom URLs.

* &lt;P>

* Taken from More Servlets and JavaServer Pages

* from Prentice Hall and Sun Microsystems Press,

* http://www.moreservlets.com/.

* &copy; 2002 Marty Hall; may be freely used or adapted.

*/

 

public class TestServlet extends HttpServlet {

public void doGet(HttpServletRequest request,

HttpServletResponse response)

throws ServletException, IOException {

response.setContentType("text/html");

PrintWriter out = response.getWriter();

String uri = request.getRequestURI();

out.println(ServletUtilities.headWithTitle("Test Servlet") +

"&lt;BODY BGCOLOR=\"#FDF5E6\">\n" +

"&lt;H2>URI: " + uri + "&lt;/H2>\n" +

"&lt;/BODY>&lt;/HTML>");

}

}

 

 

程序清单5-2 web.xml（说明servlet名称的摘录）

&lt;?xml version="1.0" encoding="ISO-8859-1"?>

&lt;!DOCTYPE web-app

PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

"http://java.sun.com/dtd/web-app_2_3.dtd">

 

&lt;web-app>

&lt;!-- … -->

&lt;servlet>

&lt;servlet-name>Test&lt;/servlet-name>

&lt;servlet-class>moreservlets.TestServlet&lt;/servlet-class>

&lt;/servlet>

&lt;!-- … -->

&lt;/web-app>

 
3.2 定义定制的URL

大多数服务器具有一个缺省的serlvet URL：

<a href="http://host/webAppPrefix/servlet/packageName.ServletName" target="_blank">http://host/webAppPrefix/servlet/packageName.ServletName</a>。虽然在开发中使用这个URL很方便，但是我们常常会希望另一个URL用于部署。例如，可能会需要一个出现在Web应用顶层的URL（如，http://host/webAppPrefix/Anyname），并且在此URL中没有servlet项。位于顶层的URL简化了相对URL的使用。此外，对许多开发人员来说，顶层URL看上去比更长更麻烦的缺省URL更简短。

事实上，有时需要使用定制的URL。比如，你可能想关闭缺省URL映射，以便更好地强制实施安全限制或防止用户意外地访问无初始化参数的servlet。如果你禁止了缺省的URL，那么你怎样访问servlet呢？这时只有使用定制的URL了。

为了分配一个定制的URL，可使用servlet-mapping元素及其servlet-name和url-pattern子元素。Servlet- name元素提供了一个任意名称，可利用此名称引用相应的servlet；url-pattern描述了相对于Web应用的根目录的URL。url- pattern元素的值必须以斜杠（/）起始。

下面给出一个简单的web.xml摘录，它允许使用URL http://host/webAppPrefix/UrlTest而不是http://host/webAppPrefix/servlet/Test或

<a href="http://host/webAppPrefix/servlet/moreservlets.TestServlet" target="_blank">http://host/webAppPrefix/servlet/moreservlets.TestServlet</a>。请注意，仍然需要XML头、DOCTYPE声明以及web-app封闭元素。此外，可回忆一下，XML元素出现地次序不是随意的。特别是，需要把所有servlet元素放在所有servlet-mapping元素之前。

&lt;servlet>

&lt;servlet-name>Test&lt;/servlet-name>

&lt;servlet-class>moreservlets.TestServlet&lt;/servlet-class>

&lt;/servlet>

&lt;!-- ... -->

&lt;servlet-mapping>

&lt;servlet-name>Test&lt;/servlet-name>

&lt;url-pattern>/UrlTest&lt;/url-pattern>

&lt;/servlet-mapping>

URL模式还可以包含通配符。例如，下面的小程序指示服务器发送所有以Web应用的URL前缀开始，以..asp结束的请求到名为BashMS的servlet。

&lt;servlet>

&lt;servlet-name>BashMS&lt;/servlet-name>

&lt;servlet-class>msUtils.ASPTranslator&lt;/servlet-class>

&lt;/servlet>

&lt;!-- ... -->

&lt;servlet-mapping>

&lt;servlet-name>BashMS&lt;/servlet-name>

&lt;url-pattern>/*.asp&lt;/url-pattern>

&lt;/servlet-mapping>

3.3 命名JSP页面

因为JSP页面要转换成sevlet，自然希望就像命名servlet一样命名JSP页面。毕竟，JSP页面可能会从初始化参数、安全设置或定制的URL中受益，正如普通的serlvet那样。虽然JSP页面的后台实际上是servlet这句话是正确的，但存在一个关键的猜疑：即，你不知道JSP页面的实际类名（因为系统自己挑选这个名字）。因此，为了命名JSP页面，可将jsp-file元素替换为servlet-calss元素，如下所示：

&lt;servlet>

&lt;servlet-name>Test&lt;/servlet-name>

&lt;jsp-file>/TestPage.jsp&lt;/jsp-file>

&lt;/servlet>

命名JSP页面的原因与命名servlet的原因完全相同：即为了提供一个与定制设置（如，初始化参数和安全设置）一起使用的名称，并且，以便能更改激活 JSP页面的URL（比方说，以便多个URL通过相同页面得以处理，或者从URL中去掉.jsp扩展名）。但是，在设置初始化参数时，应该注意，JSP页面是利用jspInit方法，而不是init方法读取初始化参数的。

例如，程序清单5-3给出一个名为TestPage.jsp的简单JSP页面，它的工作只是打印出用来激活它的URL的本地部分。TestPage.jsp放置在deployDemo应用的顶层。程序清单5-4给出了用来分配一个注册名PageName，然后将此注册名与http://host/webAppPrefix/UrlTest2/anything 形式的URL相关联的web.xml文件（即，deployDemo/WEB-INF/web.xml）的一部分。

 

程序清单5-3 TestPage.jsp

&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

&lt;HTML>

&lt;HEAD>

&lt;TITLE>

JSP Test Page

&lt;/TITLE>

&lt;/HEAD>

&lt;BODY BGCOLOR="#FDF5E6">

&lt;H2>URI: &lt;%= request.getRequestURI() %>&lt;/H2>

&lt;/BODY>

&lt;/HTML>

 

 

程序清单5-4 web.xml（说明JSP页命名的摘录）

&lt;?xml version="1.0" encoding="ISO-8859-1"?>

&lt;!DOCTYPE web-app

PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

"http://java.sun.com/dtd/web-app_2_3.dtd">

 

&lt;web-app>

&lt;!-- ... -->

&lt;servlet>

&lt;servlet-name>PageName&lt;/servlet-name>

&lt;jsp-file>/TestPage.jsp&lt;/jsp-file>

&lt;/servlet>

&lt;!-- ... -->

&lt;servlet-mapping>

&lt;servlet-name> PageName &lt;/servlet-name>

&lt;url-pattern>/UrlTest2/*&lt;/url-pattern>

&lt;/servlet-mapping>

&lt;!-- ... -->

&lt;/web-app>

 

 
4 禁止激活器servlet

 

对servlet或JSP页面建立定制URL的一个原因是，这样做可以注册从init（servlet）或jspInit（JSP页面）方法中读取得初始化参数。但是，初始化参数只在是利用定制URL模式或注册名访问servlet或JSP页面时可以使用，用缺省URL http://host/webAppPrefix/servlet/ServletName 访问时不能使用。因此，你可能会希望关闭缺省URL，这样就不会有人意外地调用初始化servlet了。这个过程有时称为禁止激活器servlet，因为多数服务器具有一个用缺省的servlet URL注册的标准servlet，并激活缺省的URL应用的实际servlet。

有两种禁止此缺省URL的主要方法：

l 在每个Web应用中重新映射/servlet/模式。

l 全局关闭激活器servlet。

重要的是应该注意到，虽然重新映射每个Web应用中的/servlet/模式比彻底禁止激活servlet所做的工作更多，但重新映射可以用一种完全可移植的方式来完成。相反，全局禁止激活器servlet完全是针对具体机器的，事实上有的服务器（如ServletExec）没有这样的选择。下面的讨论对每个Web应用重新映射/servlet/ URL模式的策略。后面提供在Tomcat中全局禁止激活器servlet的详细内容。
4.1 重新映射/servlet/URL模式

在一个特定的Web应用中禁止以http://host/webAppPrefix/servlet/ 开始的URL的处理非常简单。所需做的事情就是建立一个错误消息servlet，并使用前一节讨论的url-pattern元素将所有匹配请求转向该servlet。只要简单地使用：

&lt;url-pattern>/servlet/*&lt;/url-pattern>

作为servlet-mapping元素中的模式即可。

例如，程序清单5-5给出了将SorryServlet servlet（程序清单5-6）与所有以http://host/webAppPrefix/servlet/ 开头的URL相关联的部署描述符文件的一部分。

 

程序清单5-5 web.xml（说明JSP页命名的摘录）

&lt;?xml version="1.0" encoding="ISO-8859-1"?>

&lt;!DOCTYPE web-app

PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

"http://java.sun.com/dtd/web-app_2_3.dtd">

 

&lt;web-app>

&lt;!-- ... -->

&lt;servlet>

&lt;servlet-name>Sorry&lt;/servlet-name>

&lt;servlet-class>moreservlets.SorryServlet&lt;/servlet-class>

&lt;/servlet>

&lt;!-- ... -->

&lt;servlet-mapping>

&lt;servlet-name> Sorry &lt;/servlet-name>

&lt;url-pattern>/servlet/*&lt;/url-pattern>

&lt;/servlet-mapping>

&lt;!-- ... -->

&lt;/web-app>

 

 

程序清单5-6 SorryServlet.java

package moreservlets;

 

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

 

/** Simple servlet used to give error messages to

* users who try to access default servlet URLs

* (i.e., http://host/webAppPrefix/servlet/ServletName)

* in Web applications that have disabled this

* behavior.

* &lt;P>

* Taken from More Servlets and JavaServer Pages

* from Prentice Hall and Sun Microsystems Press,

* http://www.moreservlets.com/.

* &copy; 2002 Marty Hall; may be freely used or adapted.

*/

 

public class SorryServlet extends HttpServlet {

public void doGet(HttpServletRequest request,

HttpServletResponse response)

throws ServletException, IOException {

response.setContentType("text/html");

PrintWriter out = response.getWriter();

String title = "Invoker Servlet Disabled.";

out.println(ServletUtilities.headWithTitle(title) +

"&lt;BODY BGCOLOR=\"#FDF5E6\">\n" +

"&lt;H2>" + title + "&lt;/H2>\n" +

"Sorry, access to servlets by means of\n" +

"URLs that begin with\n" +

"http://host/webAppPrefix/servlet/\n" +

"has been disabled.\n" +

"&lt;/BODY>&lt;/HTML>");

}

 

public void doPost(HttpServletRequest request,

HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}

 

 
4.2 全局禁止激活器：Tomcat

Tomcat 4中用来关闭缺省URL的方法与Tomcat 3中所用的很不相同。下面介绍这两种方法：

1．禁止激活器： Tomcat 4

Tomcat 4用与前面相同的方法关闭激活器servlet，即利用web.xml中的url-mapping元素进行关闭。不同之处在于Tomcat使用了放在 install_dir/conf中的一个服务器专用的全局web.xml文件，而前面使用的是存放在每个Web应用的WEB-INF目录中的标准 web.xml文件。

因此，为了在Tomcat 4中关闭激活器servlet，只需在install_dir/conf/web.xml中简单地注释出/servlet/* URL映射项即可，如下所示：

&lt;!--

&lt;servlet-mapping>

&lt;servlet-name>invoker&lt;/servlet-name>

&lt;url-pattern>/servlet/*&lt;/url-pattern>

&lt;/servlet-mapping>

-->

再次提醒，应该注意这个项是位于存放在install_dir/conf的Tomcat专用的web.xml文件中的，此文件不是存放在每个Web应用的WEB-INF目录中的标准web.xml。

2．禁止激活器：Tomcat3

在Apache Tomcat的版本3中，通过在install_dir/conf/server.xml中注释出InvokerInterceptor项全局禁止缺省 servlet URL。例如，下面是禁止使用缺省servlet URL的server.xml文件的一部分。

&lt;!--

&lt;RequsetInterceptor

className="org.apache.tomcat.request.InvokerInterceptor"

debug="0" prefix="/servlet/" />

-->

 
5 初始化和预装载servlet与JSP页面

 

这里讨论控制servlet和JSP页面的启动行为的方法。特别是，说明了怎样分配初始化参数以及怎样更改服务器生存期中装载servlet和JSP页面的时刻。
5.1 分配servlet初始化参数

利用init-param元素向servlet提供初始化参数，init-param元素具有param-name和param-value子元素。例如，在下面的例子中，如果initServlet servlet是利用它的注册名（InitTest）访问的，它将能够从其方法中调用getServletConfig(). getInitParameter("param1")获得"Value 1"，调用getServletConfig().getInitParameter("param2")获得"2"。

&lt;servlet>

&lt;servlet-name>InitTest&lt;/servlet-name>

&lt;servlet-class>moreservlets.InitServlet&lt;/servlet-class>

&lt;init-param>

&lt;param-name>param1&lt;/param-name>

&lt;param-value>value1&lt;/param-value>

&lt;/init-param>

&lt;init-param>

&lt;param-name>param2&lt;/param-name>

&lt;param-value>2&lt;/param-value>

&lt;/init-param>

&lt;/servlet>

在涉及初始化参数时，有几点需要注意：

l 返回值。GetInitParameter的返回值总是一个String。因此，在前一个例子中，可对param2使用Integer.parseInt获得一个int。

l JSP中的初始化。JSP页面使用jspInit而不是init。JSP页面还需要使用jsp-file元素代替servlet-class。

l 缺省URL。初始化参数只在通过它们的注册名或与它们注册名相关的定制URL模式访问Servlet时可以使用。因此，在这个例子中，param1和param2初始化参数将能够在使用URL http://host/webAppPrefix/servlet/InitTest 时可用，但在使用URL http://host/webAppPrefix/servlet/myPackage.InitServlet 时不能使用。

例如，程序清单5-7给出一个名为InitServlet的简单servlet，它使用init方法设置firstName和emailAddress字段。程序清单5-8给出分配名称InitTest给servlet的web.xml文件。

程序清单5-7 InitServlet.java

package moreservlets;

 

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

 

/** Simple servlet used to illustrate servlet

* initialization parameters.

* &lt;P>

* Taken from More Servlets and JavaServer Pages

* from Prentice Hall and Sun Microsystems Press,

* http://www.moreservlets.com/.

* &copy; 2002 Marty Hall; may be freely used or adapted.

*/

 

public class InitServlet extends HttpServlet {

private String firstName, emailAddress;

 

public void init() {

ServletConfig config = getServletConfig();

firstName = config.getInitParameter("firstName");

emailAddress = config.getInitParameter("emailAddress");

}

 

public void doGet(HttpServletRequest request,

HttpServletResponse response)

throws ServletException, IOException {

response.setContentType("text/html");

PrintWriter out = response.getWriter();

String uri = request.getRequestURI();

out.println(ServletUtilities.headWithTitle("Init Servlet") +

"&lt;BODY BGCOLOR=\"#FDF5E6\">\n" +

"&lt;H2>Init Parameters:&lt;/H2>\n" +

"&lt;UL>\n" +

"&lt;LI>First name: " + firstName + "\n" +

"&lt;LI>Email address: " + emailAddress + "\n" +

"&lt;/UL>\n" +

"&lt;/BODY>&lt;/HTML>");

}

}

 

 

程序清单5-8 web.xml（说明初始化参数的摘录）

&lt;?xml version="1.0" encoding="ISO-8859-1"?>

&lt;!DOCTYPE web-app

PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

"http://java.sun.com/dtd/web-app_2_3.dtd">

 

&lt;web-app>

&lt;!-- ... -->

&lt;servlet>

&lt;servlet-name>InitTest&lt;/servlet-name>

&lt;servlet-class>moreservlets.InitServlet&lt;/servlet-class>

&lt;init-param>

&lt;param-name>firstName&lt;/param-name>

&lt;param-value>Larry&lt;/param-value>

&lt;/init-param>

&lt;init-param>

&lt;param-name>emailAddress&lt;/param-name>

&lt;param-value>Ellison@Microsoft.com&lt;/param-value>

&lt;/init-param>

&lt;/servlet>

&lt;!-- ... -->

&lt;/web-app>

 
5.2 分配JSP初始化参数

给JSP页面提供初始化参数在三个方面不同于给servlet提供初始化参数。

1）使用jsp-file而不是servlet-class。因此，WEB-INF/web.xml文件的servlet元素如下所示：

&lt;servlet>

&lt;servlet-name>PageName&lt;/servlet-name>

&lt;jsp-file>/RealPage.jsp&lt;/jsp-file>

&lt;init-param>

&lt;param-name>...&lt;/param-name>

&lt;param-value>...&lt;/param-value>

&lt;/init-param>

...

&lt;/servlet>

2)几乎总是分配一个明确的URL模式。对servlet，一般相应地使用以http://host/webAppPrefix/servlet/ 开始的缺省URL。只需记住，使用注册名而不是原名称即可。这对于JSP页面在技术上也是合法的。例如，在上面给出的例子中，可用URL http://host/webAppPrefix/servlet/PageName 访问RealPage.jsp的对初始化参数具有访问权的版本。但在用于JSP页面时，许多用户似乎不喜欢应用常规的servlet的URL。此外，如果 JSP页面位于服务器为其提供了目录清单的目录中（如，一个既没有index.html也没有index.jsp文件的目录），则用户可能会连接到此 JSP页面，单击它，从而意外地激活未初始化的页面。因此，好的办法是使用url-pattern（5.3节）将JSP页面的原URL与注册的 servlet名相关联。这样，客户机可使用JSP页面的普通名称，但仍然激活定制的版本。例如，给定来自项目1的servlet定义，可使用下面的 servlet-mapping定义：

&lt;servlet-mapping>

&lt;servlet-name>PageName&lt;/servlet-name>

&lt;url-pattern>/RealPage.jsp&lt;/url-pattern>

&lt;/servlet-mapping>

3）JSP页使用jspInit而不是init。自动从JSP页面建立的servlet或许已经使用了inti方法。因此，使用JSP声明提供一个init方法是不合法的，必须制定jspInit方法。

为了说明初始化JSP页面的过程，程序清单5-9给出了一个名为InitPage.jsp的JSP页面，它包含一个jspInit方法且放置于deployDemo Web应用层次结构的顶层。一般，http://host/deployDemo/InitPage.jsp 形式的URL将激活此页面的不具有初始化参数访问权的版本，从而将对firstName和emailAddress变量显示null。但是，web.xml文件（程序清单5-10）分配了一个注册名，然后将该注册名与URL模式/InitPage.jsp相关联。

 

程序清单5-9 InitPage.jsp

&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

&lt;HTML>

&lt;HEAD>&lt;TITLE>JSP Init Test&lt;/TITLE>&lt;/HEAD>

&lt;BODY BGCOLOR="#FDF5E6">

&lt;H2>Init Parameters:&lt;/H2>

&lt;UL>

&lt;LI>First name: &lt;%= firstName %>

&lt;LI>Email address: &lt;%= emailAddress %>

&lt;/UL>

&lt;/BODY>&lt;/HTML>

&lt;%!

private String firstName, emailAddress;

 

public void jspInit() {

ServletConfig config = getServletConfig();

firstName = config.getInitParameter("firstName");

emailAddress = config.getInitParameter("emailAddress");

}

%>

 

 

程序清单5-10 web.xml（说明JSP页面的init参数的摘录）

&lt;?xml version="1.0" encoding="ISO-8859-1"?>

&lt;!DOCTYPE web-app

PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

"http://java.sun.com/dtd/web-app_2_3.dtd">

 

&lt;web-app>

&lt;!-- ... -->

&lt;servlet>

&lt;servlet-name>InitPage&lt;/servlet-name>

&lt;jsp-file>/InitPage.jsp&lt;/jsp-file>

&lt;init-param>

&lt;param-name>firstName&lt;/param-name>

&lt;param-value>Bill&lt;/param-value>

&lt;/init-param>

&lt;init-param>

&lt;param-name>emailAddress&lt;/param-name>

&lt;param-value>gates@oracle.com&lt;/param-value>

&lt;/init-param>

&lt;/servlet>

&lt;!-- ... -->

&lt;servlet-mapping>

&lt;servlet-name> InitPage&lt;/servlet-name>

&lt;url-pattern>/InitPage.jsp&lt;/url-pattern>

&lt;/servlet-mapping>

&lt;!-- ... -->

&lt;/web-app>

 

 
5.3 提供应用范围内的初始化参数

一般，对单个地servlet或JSP页面分配初始化参数。指定的servlet或JSP页面利用ServletConfig的getInitParameter方法读取这些参数。但是，在某些情形下，希望提供可由任意servlet或JSP页面借助ServletContext的getInitParameter方法读取的系统范围内的初始化参数。

可利用context-param元素声明这些系统范围内的初始化值。context-param元素应该包含param-name、param-value以及可选的description子元素，如下所示：

&lt;context-param>

&lt;param-name>support-email&lt;/param-name>

&lt;param-value>blackhole@mycompany.com&lt;/param-value>

&lt;/context-param>

可回忆一下，为了保证可移植性，web.xml内的元素必须以正确的次序声明。但这里应该注意，context-param元素必须出现任意与文档有关的元素（icon、display-name或description）之后及filter、filter-mapping、listener或 servlet元素之前。

5.4 在服务器启动时装载servlet

假如servlet或JSP页面有一个要花很长时间执行的init （servlet）或jspInit（JSP）方法。例如，假如init或jspInit方法从某个数据库或ResourceBundle查找产量。这种情况下，在第一个客户机请求时装载servlet的缺省行为将对第一个客户机产生较长时间的延迟。因此，可利用servlet的load-on- startup元素规定服务器在第一次启动时装载servlet。下面是一个例子。

&lt;servlet>

&lt;servlet-name> … &lt;/servlet-name>

&lt;servlet-class> … &lt;/servlet-class> &lt;!-- Or jsp-file -->

&lt;load-on-startup/>

&lt;/servlet>

可以为此元素体提供一个整数而不是使用一个空的load-on-startup。想法是服务器应该在装载较大数目的servlet或JSP页面之前装载较少数目的servlet或JSP页面。例如，下面的servlet项（放置在Web应用的WEB-INF目录下的web.xml文件中的web-app元素内）将指示服务器首先装载和初始化SearchServlet，然后装载和初始化由位于Web应用的result目录中的index.jsp文件产生的 servlet。

&lt;servlet>

&lt;servlet-name>Search&lt;/servlet-name>

&lt;servlet-class>myPackage.SearchServlet&lt;/servlet-class> &lt;!-- Or jsp-file -->

&lt;load-on-startup>1&lt;/load-on-startup>

&lt;/servlet>

&lt;servlet>

&lt;servlet-name>Results&lt;/servlet-name>

&lt;servlet-class>/results/index.jsp&lt;/servlet-class> &lt;!-- Or jsp-file -->

&lt;load-on-startup>2&lt;/load-on-startup>

&lt;/servlet>

 
6 声明过滤器

 

servlet版本2.3引入了过滤器的概念。虽然所有支持servlet API版本2.3的服务器都支持过滤器，但为了使用与过滤器有关的元素，必须在web.xml中使用版本2.3的DTD。

过滤器可截取和修改进入一个servlet或JSP页面的请求或从一个servlet或JSP页面发出的相应。在执行一个servlet或JSP页面之前，必须执行第一个相关的过滤器的doFilter方法。在该过滤器对其FilterChain对象调用doFilter时，执行链中的下一个过滤器。如果没有其他过滤器，servlet或JSP页面被执行。过滤器具有对到来的ServletRequest对象的全部访问权，因此，它们可以查看客户机名、查找到来的cookie等。为了访问servlet或JSP页面的输出，过滤器可将响应对象包裹在一个替身对象（stand-in object）中，比方说把输出累加到一个缓冲区。在调用FilterChain对象的doFilter方法之后，过滤器可检查缓冲区，如有必要，就对它进行修改，然后传送到客户机。

例如，程序清单5-11帝国难以了一个简单的过滤器，只要访问相关的servlet或JSP页面，它就截取请求并在标准输出上打印一个报告（开发过程中在桌面系统上运行时，大多数服务器都可以使用这个过滤器）。

 

程序清单5-11 ReportFilter.java

package moreservlets;

 

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

import java.util.*;

 

/** Simple filter that prints a report on the standard output

* whenever the associated servlet or JSP page is accessed.

* &lt;P>

* Taken from More Servlets and JavaServer Pages

* from Prentice Hall and Sun Microsystems Press,

* http://www.moreservlets.com/.

* &copy; 2002 Marty Hall; may be freely used or adapted.

*/

 

public class ReportFilter implements Filter {

public void doFilter(ServletRequest request,

ServletResponse response,

FilterChain chain)

throws ServletException, IOException {

HttpServletRequest req = (HttpServletRequest)request;

System.out.println(req.getRemoteHost() +

" tried to access " +

req.getRequestURL() +

" on " + new Date() + ".");

chain.doFilter(request,response);

}

 

public void init(FilterConfig config)

throws ServletException {

}

 

public void destroy() {}

}

 

一旦建立了一个过滤器，可以在web.xml中利用filter元素以及filter-name（任意名称）、file-class（完全限定的类名）和（可选的）init-params子元素声明它。请注意，元素在web.xml的web-app元素中出现的次序不是任意的；允许服务器（但不是必需的）强制所需的次序，并且实际中有些服务器也是这样做的。但这里要注意，所有filter元素必须出现在任意filter-mapping元素之前， filter-mapping元素又必须出现在所有servlet或servlet-mapping元素之前。

例如，给定上述的ReportFilter类，可在web.xml中作出下面的filter声明。它把名称Reporter与实际的类ReportFilter（位于moreservlets程序包中）相关联。

&lt;filter>

&lt;filter-name>Reporter&lt;/filter-name>

&lt;filter-class>moresevlets.ReportFilter&lt;/filter-class>

&lt;/filter>

一旦命名了一个过滤器，可利用filter-mapping元素把它与一个或多个servlet或JSP页面相关联。关于此项工作有两种选择。

首先，可使用filter-name和servlet-name子元素把此过滤器与一个特定的servlet名（此servlet名必须稍后在相同的 web.xml文件中使用servlet元素声明）关联。例如，下面的程序片断指示系统只要利用一个定制的URL访问名为SomeServletName 的servlet或JSP页面，就运行名为Reporter的过滤器。

&lt;filter-mapping>

&lt;filter-name>Reporter&lt;/filter-name>

&lt;servlet-name>SomeServletName&lt;/servlet-name>

&lt;/filter-mapping>

其次，可利用filter-name和url-pattern子元素将过滤器与一组servlet、JSP页面或静态内容相关联。例如，相面的程序片段指示系统只要访问Web应用中的任意URL，就运行名为Reporter的过滤器。

&lt;filter-mapping>

&lt;filter-name>Reporter&lt;/filter-name>

&lt;url-pattern>/*&lt;/url-pattern>

&lt;/filter-mapping>

例如，程序清单5-12给出了将ReportFilter过滤器与名为PageName的servlet相关联的web.xml文件的一部分。名字PageName依次又与一个名为TestPage.jsp的JSP页面以及以模式http://host/webAppPrefix/UrlTest2/ 开头的URL相关联。TestPage.jsp的源代码已经JSP页面命名的谈论在前面的3节"分配名称和定制的URL"中给出。事实上，程序清单5- 12中的servlet和servlet-name项从该节原封不动地拿过来的。给定这些web.xml项，可看到下面的标准输出形式的调试报告（换行是为了容易阅读）。

audit.irs.gov tried to access

<a href="http://mycompany.com/deployDemo/UrlTest2/business/tax-plan.html" target="_blank">http://mycompany.com/deployDemo/UrlTest2/business/tax-plan.html</a>

on Tue Dec 25 13:12:29 EDT 2001.

 

程序清单5-12 Web.xml（说明filter用法的摘录）

&lt;?xml version="1.0" encoding="ISO-8859-1"?>

&lt;!DOCTYPE web-app

PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

"http://java.sun.com/dtd/web-app_2_3.dtd">

 

&lt;web-app>

&lt;filter>

&lt;filter-name>Reporter&lt;/filter-name>

&lt;filter-class>moresevlets.ReportFilter&lt;/filter-class>

&lt;/filter>

&lt;!-- ... -->

&lt;filter-mapping>

&lt;filter-name>Reporter&lt;/filter-name>

&lt;servlet-name>PageName&lt;/servlet-name>

&lt;/filter-mapping>

&lt;!-- ... -->

&lt;servlet>

&lt;servlet-name>PageName&lt;/servlet-name>

&lt;jsp-file>/RealPage.jsp&lt;/jsp-file>

&lt;/servlet>

&lt;!-- ... -->

&lt;servlet-mapping>

&lt;servlet-name> PageName &lt;/servlet-name>

&lt;url-pattern>/UrlTest2/*&lt;/url-pattern>

&lt;/servlet-mapping>

&lt;!-- ... -->

&lt;/web-app>
7 指定欢迎页

 

假如用户提供了一个像http://host/webAppPrefix/directoryName/ 这样的包含一个目录名但没有包含文件名的URL，会发生什么事情呢？用户能得到一个目录表？一个错误？还是标准文件的内容？如果得到标准文件内容，是index.html、index.jsp、default.html、default.htm或别的什么东西呢？

Welcome -file-list元素及其辅助的welcome-file元素解决了这个模糊的问题。例如，下面的web.xml项指出，如果一个URL给出一个目录名但未给出文件名，服务器应该首先试用index.jsp，然后再试用index.html。如果两者都没有找到，则结果有赖于所用的服务器（如一个目录列表）。

&lt;welcome-file-list>

&lt;welcome-file>index.jsp&lt;/welcome-file>

&lt;welcome-file>index.html&lt;/welcome-file>

&lt;/welcome-file-list>

虽然许多服务器缺省遵循这种行为，但不一定必须这样。因此，明确地使用welcom-file-list保证可移植性是一种良好的习惯。

 
8 指定处理错误的页面

 

现在我了解到，你在开发servlet和 JSP页面时从不会犯错误，而且你的所有页面是那样的清晰，一般的程序员都不会被它们的搞糊涂。但是，是人总会犯错误的，用户可能会提供不合规定的参数，使用不正确的URL或者不能提供必需的表单字段值。除此之外，其它开发人员可能不那么细心，他们应该有些工具来克服自己的不足。

error-page 元素就是用来克服这些问题的。它有两个可能的子元素，分别是：error-code和exception-type。第一个子元素error-code指出在给定的HTTP错误代码出现时使用的URL。第二个子元素excpetion-type指出在出现某个给定的Java异常但未捕捉到时使用的URL。 error-code和exception-type都利用location元素指出相应的URL。此URL必须以/开始。location所指出的位置处的页面可通过查找HttpServletRequest对象的两个专门的属性来访问关于错误的信息，这两个属性分别是： javax.servlet.error.status_code和javax.servlet.error.message。

可回忆一下，在web.xml内以正确的次序声明web-app的子元素很重要。这里只要记住，error-page出现在web.xml文件的末尾附近，servlet、servlet-name和welcome-file-list之后即可。

 
8.1 error-code元素

为了更好地了解error-code元素的值，可考虑一下如果不正确地输入文件名，大多数站点会作出什么反映。这样做一般会出现一个404错误信息，它表示不能找到该文件，但几乎没提供更多有用的信息。另一方面，可以试一下在www.microsoft.com、www.ibm.com 处或者特别是在www.bea.com 处输出未知的文件名。这是会得出有用的消息，这些消息提供可选择的位置，以便查找感兴趣的页面。提供这样有用的错误页面对于Web应用来说是很有价值得。事实上，http://www.plinko.net/404/ 就是把整个站点专门用于404错误页面这个内容。这个站点包含来自全世界最好、最糟和最搞笑的404页面。

程序清单5-13给出一个JSP页面，此页面可返回给提供位置程序名的客户机。程序清单5-14给出指定程序清单5-13作为返回404错误代码时显示的页面的web.xml。请注意，浏览器中显示的URL仍然是客户机所提供的。错误页面是一种后台实现技术。

最后一点，请记住IE5的缺省配置显然不符合HTTP规范，它忽略了服务器生成的错误消息，而是显示自己的标准出错信息。可转到其Tools菜单，选择 Internet Options，单击Advanced，取消Show Friendly HTTP Error Message来解决此问题。

 

程序清单5-13 NotFound.jsp

&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

&lt;HTML>

&lt;HEAD>&lt;TITLE>404: Not Found&lt;/TITLE>&lt;/HEAD>

&lt;BODY BGCOLOR="#FDF5E6">

&lt;H2>Error!&lt;/H2>

I'm sorry, but I cannot find a page that matches

&lt;%= request.getRequestURI() %> on the system. Maybe you should

try one of the following:

&lt;UL>

&lt;LI>Go to the server's &lt;A HREF="/">home page&lt;/A>.

&lt;LI>Search for relevant pages.&lt;BR>

&lt;FORM ACTION="http://www.google.com/search">

&lt;CENTER>

Keywords: &lt;INPUT TYPE="TEXT" NAME="q">&lt;BR>

&lt;INPUT TYPE="SUBMIT" VALUE="Search">

&lt;/CENTER>

&lt;/FORM>

&lt;LI>Admire a random multiple of 404:

&lt;%= 404*((int)(1000*Math.random())) %>.

&lt;LI>Try a &lt;A HREF="http://www.plinko.net/404/rndindex.asp"

TARGET="_blank">

random 404 error message&lt;/A>. From the amazing and

amusing plinko.net &lt;A HREF="http://www.plinko.net/404/">

404 archive&lt;/A>.

&lt;/UL>

&lt;/BODY>&lt;/HTML>

 

 

程序清单5-14 web.xml（指出HTTP错误代码的错误页面的摘录）

&lt;?xml version="1.0" encoding="ISO-8859-1"?>

&lt;!DOCTYPE web-app

PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

"http://java.sun.com/dtd/web-app_2_3.dtd">

 

&lt;web-app>

&lt;error-page>

&lt;error-code>404&lt;/error-code>

&lt;location>/NotFound.jsp&lt;/location>

&lt;/error-page>

&lt;!-- ... -->

&lt;/web-app>

 

 
8.2 exception-type元素

error -code元素处理某个请求产生一个特定的HTTP状态代码时的情况。然而，对于servlet或JSP页面返回200但产生运行时异常这种同样是常见的情况怎么办呢？这正是exception-type元素要处理的情况。只需提供两样东西即可：即提供如下的一个完全限定的异常类和一个位置：

&lt;error-page>

&lt;exception-type>packageName.className&lt;/exception-type>

&lt;location>/SomeURL&lt;/location>

&lt;/error-page>

这样，如果Web应用中的任何servlet或JSP页面产生一个特定类型的未捕捉到的异常，则使用指定的URL。此异常类型可以是一个标准类型，如 javax.ServletException或java.lang.OutOfMemoryError，或者是一个专门针对你的应用的异常。

例如，程序清单5-15给出了一个名为DumbDeveloperException的异常类，可用它来特别标记经验较少的程序员（不是说你的开发组中一定有这种人）所犯的错误。这个类还包含一个名为dangerousComputation的静态方法，它时不时地生成这种类型的异常。程序清单5-16给出对随机整数值调用dangerousCompution的一个JSP页面。在抛出此异常时，如程序清单5-18的web.xml版本中所给出的 exception-type所指出的那样，对客户机显示DDE.jsp（程序清单5-17）。图5-16和图5-17分别给出幸运和不幸的结果。

 

程序清单5-15 DumbDeveloperException.java

package moreservlets;

 

/** Exception used to flag particularly onerous

programmer blunders. Used to illustrate the

exception-type web.xml element.

* &lt;P>

* Taken from More Servlets and JavaServer Pages

* from Prentice Hall and Sun Microsystems Press,

* http://www.moreservlets.com/.

* &copy; 2002 Marty Hall; may be freely used or adapted.

*/

 

public class DumbDeveloperException extends Exception {

public DumbDeveloperException() {

super("Duh. What was I *thinking*?");

}

 

public static int dangerousComputation(int n)

throws DumbDeveloperException {

if (n &lt; 5) {

return(n + 10);

} else {

throw(new DumbDeveloperException());

}

}

}

 

 

程序清单5-16 RiskyPage.jsp

&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

&lt;HTML>

&lt;HEAD>&lt;TITLE>Risky JSP Page&lt;/TITLE>&lt;/HEAD>

&lt;BODY BGCOLOR="#FDF5E6">

&lt;H2>Risky Calculations&lt;/H2>

&lt;%@ page import="moreservlets.*" %>

&lt;% int n = ((int)(10 * Math.random())); %>

&lt;UL>

&lt;LI>n: &lt;%= n %>

&lt;LI>dangerousComputation(n):

&lt;%= DumbDeveloperException.dangerousComputation(n) %>

&lt;/UL>

&lt;/BODY>&lt;/HTML>

 

 

程序清单5-17 DDE.jsp

&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

&lt;HTML>

&lt;HEAD>&lt;TITLE>Dumb&lt;/TITLE>&lt;/HEAD>

&lt;BODY BGCOLOR="#FDF5E6">

&lt;H2>Dumb Developer&lt;/H2>

We're brain dead. Consider using our competitors.

&lt;/BODY>&lt;/HTML>

 

 

程序清单5-18 web.xml（为异常指定错误页面的摘录）

&lt;?xml version="1.0" encoding="ISO-8859-1"?>

&lt;!DOCTYPE web-app

PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

"http://java.sun.com/dtd/web-app_2_3.dtd">

 

&lt;web-app>

&lt;!-- ... -->

&lt;servlet> … &lt;/servlet>

&lt;!-- ... -->

&lt;error-page>

&lt;exception-type>

moreservlets.DumbDeveloperException

&lt;/exception-type>

&lt;location>/DDE.jsp&lt;/location>

&lt;/error-page>

&lt;!-- ... -->

&lt;/web-app>

 
9 提供安全性

 

利用web.xml中的相关元素为服务器的内建功能提供安全性。
9.1 指定验证的方法

使用login-confgi元素规定服务器应该怎样验证试图访问受保护页面的用户。它包含三个可能的子元素，分别是：auth-method、realm -name和form-login-config。login-config元素应该出现在web.xml部署描述符文件的结尾附近，紧跟在 security-constraint元素之后。

l auth-method

login-config的这个子元素列出服务器将要使用的特定验证机制。有效值为BASIC、DIGEST、FORM和CLIENT-CERT。服务器只需要支持BASIC和FORM。

BASIC 指出应该使用标准的HTTP验证，在此验证中服务器检查Authorization头。如果缺少这个头则返回一个401状态代码和一个WWW- Authenticate头。这导致客户机弹出一个用来填写Authorization头的对话框。此机制很少或不提供对攻击者的防范，这些攻击者在 Internet连接上进行窥探（如通过在客户机的子网上执行一个信息包探测装置），因为用户名和口令是用简单的可逆base64编码发送的，他们很容易得手。所有兼容的服务器都需要支持BASIC验证。

DIGEST指出客户机应该利用加密Digest Authentication形式传输用户名和口令。这提供了比BASIC验证更高的防范网络截取得的安全性，但这种加密比SSL（HTTPS）所用的方法更容易破解。不过，此结论有时没有意义，因为当前很少有浏览器支持Digest Authentication，所以servlet容器不需要支持它。

FORM 指出服务器应该检查保留的会话cookie并且把不具有它的用户重定向到一个指定的登陆页。此登陆页应该包含一个收集用户名和口令的常规HTML表单。在登陆之后，利用保留会话级的cookie跟踪用户。虽然很复杂，但FORM验证防范网络窥探并不比BASIC验证更安全，如果有必要可以在顶层安排诸如 SSL或网络层安全（如IPSEC或VPN）等额外的保护。所有兼容的服务器都需要支持FORM验证。

CLIENT-CERT规定服务器必须使用HTTPS（SSL之上的HTTP）并利用用户的公开密钥证书（Pulic Key Certificat）对用户进行验证。这提供了防范网络截取的很强的安全性，但只有兼容J2EE的服务器需要支持它。

l realm-name

此元素只在auth-method为BASIC时使用。它指出浏览器在相应对话框标题使用的、并作为Authorization头组成部分的安全域的名称。

l form-login-config

此元素只在auth-method为FORM时适用。它指定两个页面，分别是：包含收集用户名及口令的HTML表单的页面（利用form-login- page子元素），用来指示验证失败的页面（利用form-error-page子元素）。由form-login-page给出的HTML表单必须具有一个j_security_check的ACTION属性、一个名为j_username的用户名文本字段以及一个名为j_password的口令字段。

例如，程序清单5-19指示服务器使用基于表单的验证。Web应用的顶层目录中的一个名为login.jsp的页面将收集用户名和口令，并且失败的登陆将由相同目录中名为login-error.jsp的页面报告。

 

程序清单5-19 web.xml（说明login-config的摘录）

&lt;?xml version="1.0" encoding="ISO-8859-1"?>

&lt;!DOCTYPE web-app

PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

"http://java.sun.com/dtd/web-app_2_3.dtd">

 

&lt;web-app>

&lt;!-- ... -->

&lt;security-constraint> ... &lt;/security-constraint>

&lt;login-config>

&lt;auth-method> FORM &lt;/auth-method>

&lt;form-login-config>

&lt;form-login-page>/login.jsp&lt;/form-login-page>

&lt;form-error-page>/login-error.jsp&lt;/form-error-page>

&lt;/form-login-config>

&lt;/login-config>

&lt;!-- ... -->

&lt;/web-app>

 

 
9.2 限制对Web资源的访问

现在，可以指示服务器使用何种验证方法了。"了不起，"你说道，"除非我能指定一个来收到保护的URL，否则没有多大用处。"没错。指出这些URL并说明他们应该得到何种保护正是security-constriaint元素的用途。此元素在web.xml中应该出现在login-config的紧前面。它包含是个可能的子元素，分别是：web-resource-collection、auth-constraint、user-data- constraint和display-name。下面各小节对它们进行介绍。

l web-resource-collection

此元素确定应该保护的资源。所有security-constraint元素都必须包含至少一个web-resource-collection项。此元素由一个给出任意标识名称的web-resource-name元素、一个确定应该保护的URL的url-pattern元素、一个指出此保护所适用的 HTTP命令（GET、POST等，缺省为所有方法）的http-method元素和一个提供资料的可选description元素组成。例如，下面的 Web-resource-collection项（在security-constratint元素内）指出Web应用的proprietary目录中所有文档应该受到保护。

&lt;security-constraint>

&lt;web-resource-coolection>

&lt;web-resource-name>Proprietary&lt;/web-resource-name>

&lt;url-pattern>/propritary/*&lt;/url-pattern>

&lt;/web-resource-coolection>

&lt;!-- ... -->

&lt;/security-constraint>

重要的是应该注意到，url-pattern仅适用于直接访问这些资源的客户机。特别是，它不适合于通过MVC体系结构利用 RequestDispatcher来访问的页面，或者不适合于利用类似jsp:forward的手段来访问的页面。这种不匀称如果利用得当的话很有好处。例如，servlet可利用MVC体系结构查找数据，把它放到bean中，发送请求到从bean中提取数据的JSP页面并显示它。我们希望保证决不直接访问受保护的JSP页面，而只是通过建立该页面将使用的bean的servlet来访问它。url-pattern和auth-contraint元素可通过声明不允许任何用户直接访问JSP页面来提供这种保证。但是，这种不匀称的行为可能让开发人员放松警惕，使他们偶然对应受保护的资源提供不受限制的访问。

l auth-constraint

尽管web-resource-collention元素质出了哪些URL应该受到保护，但是auth-constraint元素却指出哪些用户应该具有受保护资源的访问权。此元素应该包含一个或多个标识具有访问权限的用户类别role- name元素，以及包含（可选）一个描述角色的description元素。例如，下面web.xml中的security-constraint元素部门规定只有指定为Administrator或Big Kahuna（或两者）的用户具有指定资源的访问权。

&lt;security-constraint>

&lt;web-resource-coolection> ... &lt;/web-resource-coolection>

&lt;auth-constraint>

&lt;role-name>administrator&lt;/role-name>

&lt;role-name>kahuna&lt;/role-name>

&lt;/auth-constraint>

&lt;/security-constraint>

重要的是认识到，到此为止，这个过程的可移植部分结束了。服务器怎样确定哪些用户处于任何角色以及它怎样存放用户的口令，完全有赖于具体的系统。

例如，Tomcat使用install_dir/conf/tomcat-users.xml将用户名与角色名和口令相关联，正如下面例子中所示，它指出用户joe（口令bigshot）和jane（口令enaj）属于administrator和kahuna角色。

&lt;tomcat-users>

&lt;user name="joe" password="bigshot" roles="administrator,kahuna" />

&lt;user name="jane" password="enaj" roles="kahuna" />

&lt;/tomcat-users>

l user-data-constraint

这个可选的元素指出在访问相关资源时使用任何传输层保护。它必须包含一个transport-guarantee子元素（合法值为NONE、 INTEGRAL或CONFIDENTIAL），并且可选地包含一个description元素。transport-guarantee为NONE值将对所用的通讯协议不加限制。INTEGRAL值表示数据必须以一种防止截取它的人阅读它的方式传送。虽然原理上（并且在未来的HTTP版本中），在 INTEGRAL和CONFIDENTIAL之间可能会有差别，但在当前实践中，他们都只是简单地要求用SSL。例如，下面指示服务器只允许对相关资源做 HTTPS连接：

&lt;security-constraint>

&lt;!-- ... -->

&lt;user-data-constraint>

&lt;transport-guarantee>CONFIDENTIAL&lt;/transport-guarantee>

&lt;/user-data-constraint>

&lt;/security-constraint>

l display-name

security-constraint的这个很少使用的子元素给予可能由GUI工具使用的安全约束项一个名称。

9.3 分配角色名

迄今为止，讨论已经集中到完全由容器（服务器）处理的安全问题之上了。但servlet以及JSP页面也能够处理它们自己的安全问题。

例如，容器可能允许用户从bigwig或bigcheese角色访问一个显示主管人员额外紧贴的页面，但只允许bigwig用户修改此页面的参数。完成这种更细致的控制的一种常见方法是调用HttpServletRequset的isUserInRole方法，并据此修改访问。

Servlet的 security-role-ref子元素提供出现在服务器专用口令文件中的安全角色名的一个别名。例如，假如编写了一个调用 request.isUserInRole（"boss"）的servlet，但后来该servlet被用在了一个其口令文件调用角色manager而不是boss的服务器中。下面的程序段使该servlet能够使用这两个名称中的任何一个。

&lt;servlet>

&lt;!-- ... -->

&lt;security-role-ref>

&lt;role-name>boss&lt;/role-name> &lt;!-- New alias -->

&lt;role-link>manager&lt;/role-link> &lt;!-- Real name -->

&lt;/security-role-ref>

&lt;/servlet>

也可以在web-app内利用security-role元素提供将出现在role-name元素中的所有安全角色的一个全局列表。分别地生命角色使高级IDE容易处理安全信息。

 
10 控制会话超时

 

如果某个会话在一定的时间内未被访问，服务器可把它扔掉以节约内存。可利用HttpSession的setMaxInactiveInterval方法直接设置个别会话对象的超时值。如果不采用这种方法，则缺省的超时值由具体的服务器决定。但可利用session-config和session-timeout元素来给出一个适用于所有服务器的明确的超时值。超时值的单位为分钟，因此，下面的例子设置缺省会话超时值为三个小时（180分钟）。

&lt;session-config>

&lt;session-timeout>180&lt;/session-timeout>

&lt;/session-config>

 
11 Web应用的文档化

 

越来越多的开发环境开始提供 servlet和JSP的直接支持。例子有Borland Jbuilder Enterprise Edition、Macromedia UltraDev、Allaire JRun Studio（写此文时，已被Macromedia收购）以及IBM VisuaAge for Java等。

大量的web.xml元素不仅是为服务器设计的，而且还是为可视开发环境设计的。它们包括icon、display-name和discription等。

可回忆一下，在web.xml内以适当地次序声明web-app子元素很重要。不过，这里只要记住icon、display-name和description是web.xml的web-app元素内的前三个合法元素即可。

l icon

icon元素指出GUI工具可用来代表Web应用的一个和两个图像文件。可利用small-icon元素指定一幅16 x 16的GIF或JPEG图像，用large-icon元素指定一幅32 x 32的图像。下面举一个例子：

&lt;icon>

&lt;small-icon>/images/small-book.gif&lt;/small-icon>

&lt;large-icon>/images/tome.jpg&lt;/large-icon>

&lt;/icon>

l display-name

display-name元素提供GUI工具可能会用来标记此Web应用的一个名称。下面是个例子。

&lt;display-name>Rare Books&lt;/display-name>

l description

description元素提供解释性文本，如下所示：

&lt;description>

This Web application represents the store developed for

rare-books.com, an online bookstore specializing in rare

and limited-edition books.

&lt;/description>

 
12 关联文件与MIME类型

 

服务器一般都具有一种让Web站点管理员将文件扩展名与媒体相关联的方法。例如，将会自动给予名为mom.jpg的文件一个image/jpeg的MIME类型。但是，假如你的Web应用具有几个不寻常的文件，你希望保证它们在发送到客户机时分配为某种MIME类型。mime-mapping元素（具有extension和mime-type子元素）可提供这种保证。例如，下面的代码指示服务器将application/x-fubar的MIME类型分配给所有以.foo结尾的文件。

&lt;mime-mapping>

&lt;extension>foo&lt;/extension>

&lt;mime-type>application/x-fubar&lt;/mime-type>

&lt;/mime-mapping>

或许，你的Web应用希望重载（override）标准的映射。例如，下面的代码将告诉服务器在发送到客户机时指定.ps文件作为纯文本（text/plain）而不是作为PostScript（application/postscript）。

&lt;mime-mapping>

&lt;extension>ps&lt;/extension>

&lt;mime-type>application/postscript&lt;/mime-type>

&lt;/mime-mapping>

 

 
13 定位TLD

 

JSP taglib元素具有一个必要的uri属性，它给出一个TLD（Tag Library Descriptor）文件相对于Web应用的根的位置。TLD文件的实际名称在发布新的标签库版本时可能会改变，但我们希望避免更改所有现有JSP页面。此外，可能还希望使用保持taglib元素的简练性的一个简短的uri。这就是部署描述符文件的taglib元素派用场的所在了。Taglib包含两个子元素：taglib-uri和taglib-location。taglib-uri元素应该与用于JSP taglib元素的uri属性的东西相匹配。Taglib-location元素给出TLD文件的实际位置。例如，假如你将文件chart-tags- 1.3beta.tld放在WebApp/WEB-INF/tlds中。现在，假如web.xml在web-app元素内包含下列内容。

&lt;taglib>

&lt;taglib-uri>/charts.tld&lt;/taglib-uri>

&lt;taglib-location>

/WEB-INF/tlds/chart-tags-1.3beta.tld

&lt;/taglib-location>

&lt;/taglib>

给出这个说明后，JSP页面可通过下面的简化形式使用标签库。

&lt;%@ taglib uri="/charts.tld" prefix="somePrefix" %>

 
14 指定应用事件监听程序

 

应用事件监听器程序是建立或修改servlet环境或会话对象时通知的类。它们是servlet规范的版本2.3中的新内容。这里只简单地说明用来向Web应用注册一个监听程序的web.xml的用法。

注册一个监听程序涉及在web.xml的web-app元素内放置一个listener元素。在listener元素内，listener-class元素列出监听程序的完整的限定类名，如下所示：

&lt;listener>

&lt;listener-class>package.ListenerClass&lt;/listener-class>

&lt;/listener>

虽然listener元素的结构很简单，但请不要忘记，必须正确地给出web-app元素内的子元素的次序。listener元素位于所有的servlet 元素之前以及所有filter-mapping元素之后。此外，因为应用生存期监听程序是serlvet规范的2.3版本中的新内容，所以必须使用 web.xml DTD的2.3版本，而不是2.2版本。

例如，程序清单5-20给出一个名为ContextReporter的简单的监听程序，只要Web应用的Servlet-Context建立（如装载Web应用）或消除（如服务器关闭）时，它就在标准输出上显示一条消息。程序清单5-21给出此监听程序注册所需要的web.xml文件的一部分。

 

程序清单5-20 ContextReporterjava

package moreservlets;

 

import javax.servlet.*;

import java.util.*;

 

/** Simple listener that prints a report on the standard output

* when the ServletContext is created or destroyed.

* &lt;P>

* Taken from More Servlets and JavaServer Pages

* from Prentice Hall and Sun Microsystems Press,

* http://www.moreservlets.com/.

* &copy; 2002 Marty Hall; may be freely used or adapted.

*/

 

public class ContextReporter implements ServletContextListener {

public void contextInitialized(ServletContextEvent event) {

System.out.println("Context created on " +

new Date() + ".");

}

 

public void contextDestroyed(ServletContextEvent event) {

System.out.println("Context destroyed on " +

new Date() + ".");

}

}

 

 

程序清单5-21 web.xml（声明一个监听程序的摘录）

&lt;?xml version="1.0" encoding="ISO-8859-1"?>

&lt;!DOCTYPE web-app

PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

"http://java.sun.com/dtd/web-app_2_3.dtd">

 

&lt;web-app>

&lt;!-- ... -->

&lt;filter-mapping> … &lt;/filter-mapping>

&lt;listener>

&lt;listener-class>package.ListenerClass&lt;/listener-class>

&lt;/listener>

&lt;servlet> ... &lt;/servlet>

&lt;!-- ... -->

&lt;/web-app>

 

 
15 J2EE元素

 

本节描述用作J2EE环境组成部分的Web应用的web.xml元素。这里将提供一个简明的介绍，详细内容可以参阅http://java.sun.com/j2ee/j2ee-1_3-fr-spec.pdf的Java 2 Plantform Enterprise Edition版本1.3规范的第5章。

l distributable

distributable 元素指出，Web应用是以这样的方式编程的：即，支持集群的服务器可安全地在多个服务器上分布Web应用。例如，一个可分布的应用必须只使用 Serializable对象作为其HttpSession对象的属性，而且必须避免用实例变量（字段）来实现持续性。distributable元素直接出现在discription元素之后，并且不包含子元素或数据，它只是一个如下的标志。

&lt;distributable />

l resource-env-ref

resource -env-ref元素声明一个与某个资源有关的管理对象。此元素由一个可选的description元素、一个resource-env-ref- name元素（一个相对于java:comp/env环境的JNDI名）以及一个resource-env-type元素（指定资源类型的完全限定的类），如下所示：

&lt;resource-env-ref>

&lt;resource-env-ref-name>

jms/StockQueue

&lt;/resource-env-ref-name>

&lt;resource-env-ref-type>

javax.jms.Queue

&lt;/resource-env-ref-type>

&lt;/resource-env-ref>

l env-entry

env -entry元素声明Web应用的环境项。它由一个可选的description元素、一个env-entry-name元素（一个相对于java: comp/env环境JNDI名）、一个env-entry-value元素（项值）以及一个env-entry-type元素（java.lang程序包中一个类型的完全限定类名，java.lang.Boolean、java.lang.String等）组成。下面是一个例子：

&lt;env-entry>

&lt;env-entry-name>minAmout&lt;/env-entry-name>

&lt;env-entry-value>100.00&lt;/env-entry-value>

&lt;env-entry-type>minAmout&lt;/env-entry-type>

&lt;/env-entry>

l ejb-ref

ejb -ref元素声明对一个EJB的主目录的应用。它由一个可选的description元素、一个ejb-ref-name元素（相对于java: comp/env的EJB应用）、一个ejb-ref-type元素（bean的类型，Entity或Session）、一个home元素（bean的主目录接口的完全限定名）、一个remote元素（bean的远程接口的完全限定名）以及一个可选的ejb-link元素（当前bean链接的另一个 bean的名称）组成。

l ejb-local-ref

ejb-local-ref元素声明一个EJB的本地主目录的引用。除了用local-home代替home外，此元素具有与ejb-ref元素相同的属性并以相同的方式使用。</pre><br />Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1925232
          <br/>
          <span style="color:red;">
            <a href="http://agapple.javaeye.com/blog/151362#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 27 Dec 2007 23:01:19 +0800</pubDate>
        <link>http://agapple.javaeye.com/blog/151362</link>
        <guid>http://agapple.javaeye.com/blog/151362</guid>
      </item>
      <item>
        <title>servlet学习</title>
        <author>agapple</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://agapple.javaeye.com">agapple</a>&nbsp;
          链接：<a href="http://agapple.javaeye.com/blog/150616" style="color:red;">http://agapple.javaeye.com/blog/150616</a>&nbsp;
          发表时间: 2007年12月25日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <a href="http://www.onjava.com/pub/a/onjava/2003/05/14/java_webserver.html" target="_blank">http://www.onjava.com/pub/a/onjava/2003/05/14/java_webserver.html</a>
          <br/>
          <span style="color:red;">
            <a href="http://agapple.javaeye.com/blog/150616#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 25 Dec 2007 00:20:54 +0800</pubDate>
        <link>http://agapple.javaeye.com/blog/150616</link>
        <guid>http://agapple.javaeye.com/blog/150616</guid>
      </item>
      <item>
        <title>maven 介绍</title>
        <author>agapple</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://agapple.javaeye.com">agapple</a>&nbsp;
          链接：<a href="http://agapple.javaeye.com/blog/147380" style="color:red;">http://agapple.javaeye.com/blog/147380</a>&nbsp;
          发表时间: 2007年12月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          版权声明：任何获得Matrix授权的网站，转载时请务必保留以下作者信息和链接<br />作者:Chris Hardin;mycj(作者的blog:http://blog.matrix.org.cn/page/mycj)<br />原文:http://www.onjava.com/pub/a/onjava/2006/03/29/maven-2-0.html<br />Matrix:http://www.matrix.org.cn/resource/article/44/44475_Maven2.html<br />关键字:Maven2<br /><br />Maven2.0的优点<br /><br />Maven2.0有许多很好功能，这些功能不仅仅是帮助您构建项目。如果您刚刚开始启动一个Java项目，并且想使该项目快速地开展下去，Maven2.0能够在几分钟内达到您的要求。以下是Maven2.0的一些优点：<br />--标准的项目布局和项目结构生成器<br />--标准的依赖管理机制<br />--多项目支持<br />--在开发者需要的时候及时地下载新的插件和功能部件<br />--生成最新项目信息的网站<br />--集成了源代码控制软件：CVS和Subversion<br /><br />以上列表展示的只是Maven2.0特点中的一小部分。但这足以使Maven2.0成为一个构建管理系统可靠的选择。既然我们已经知道Maven是个什么东西了，接下来让我们看看如何使用它。<br /><br />入门<br /><br />我们要做的第一件事情就是设置目录结构，但这并不需要让我们手动设置，Maven会根据您开发的项目类型来为您做这件事。一旦您下载并解压了最新发布的Maven 2.0，您应该将Maven所在目录下面的bin目录添加到您的系统路径下。您可以运行命令mvn -version来测试您的安装。<br /><br />既然已经安装上了工具，让我们看看创建一个简单的Java项目的例子。Maven使用原型来决定目录结构是如何展现的。Maven自带了几个内建的原型，您也可以自定义原型。<br /><br />mvn archetype:create -DgroupId=com.oreilly -DartifactId=my-app<br /><br />您看，这就生成了我们的项目布局。<br />my-app<br />----src<br />    ----main<br />        ----java<br />           ----com<br />               ----oreilly<br />    ----test<br />        ----java<br />            ----com<br />                ----oreilly<br /><br />对， 就这么简单。这种目录结构可以通过创建一个新的原型来覆写，但并不推荐这么做，因为Maven的一个优点就是使用标准的目录结构。该目录结构包含两个源代 码树，一个是Java应用程序的源代码，另一个是单元测试代码。同时您也许会注意到，当第一次运行Maven的时候，它会进行一些下载工作。当您开始调用 工具时，Maven会根据您使用的插件来更新自身的一些所需功能。Maven默认会从Ibiblio存储库中得到更新。您可以在Maven安装目录下的 conf目录中，或者项目自身中修改Maven远程存储库的选择。<br />您会发现Maven在my-app目录下创建了一个pom.xml文件。这是项 目的最基本部分。pom.xml文件包含了一组指令，这些指令告诉Maven如何构建项目和包含哪些其它的特殊指令（POM是“项目对象模型”的缩写）。 在默认的情况下，Maven包含了JUnit的依赖以此来鼓励单元测试。<br /><br /><br /><br />&lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><br />  &lt;modelVersion>4.0.0&lt;/modelVersion> <br />       &lt;groupId>com.oreilly&lt;/groupId><br />       &lt;artifactId>my-app&lt;/artifactId>  <br />       &lt;packaging>jar&lt;/packaging> <br />       &lt;version>1.0-SNAPSHOT&lt;/version><br />       &lt;name>Maven Quick Start Archetype&lt;/name>  <br />       &lt;url>http://maven.apache.org&lt;/url>  <br />       &lt;dependencies>&lt;dependency>     <br />       &lt;groupId>junit&lt;/groupId>      <br />       &lt;artifactId>junit&lt;/artifactId>    <br />       &lt;version>3.8.1&lt;/version>   <br />       &lt;scope>test&lt;/scope>  <br />       &lt;/dependency>  <br />       &lt;/dependencies><br />&lt;/project><br /><br /><br />创建完项目后，我们可以往项目里添加代码并使用Maven的所有全新技巧。注意以下命令必须在pom.xml文件所在的目录中运行。<br />--mvn test：运行应用程序中的单元测试<br />--mvn package：依据项目生成jar文件<br />--mvn install：将项目的jar文件添加到库中，        以备依赖此项目时使用<br />--mvn site：生成项目相关信息的网站<br />--mvn clean：清除目标目录中的生成结果<br />--mvn eclipse:eclipse：生成Eclipse项目文件<br /><br />接下来我们看看稍微复杂点的地方，我们知道手动开始一个Java web项目比手动开始一个简单的Java项目更耗时，然而Maven的使用则能化难为易。下面的例子（实际上是一行命令）展现了项目结构的构造。<br />mvn archetype:create -DgroupId=com.oreilly<br />    -DartifactId=Oreilly<br />    -DarchetypeArtifactId=maven-archetype-webapp<br /><br />生成的结果结构如下所示：<br />Oreilly<br />----src<br />    ----main<br />        ----resources<br />        ----webapp<br />            ----WEB-INF<br /><br />这 一次，我们的项目由于支持了将包含在war文件中的web资源而设置有所不同。pom.xml文件中将包含一行来表明项目应该被打包成war文件： &lt;packaging>war&lt;/packaging>。现在就可以使用mvn package命令来生成war文件。不用担心 如何从WEB-INF/lib目录中得到依赖项，在依赖属性值被设置成compile的情况下，Maven会自动包含依赖项。也可以将以下代码添加到 pom.xml文件中来改变war文件的名称：<br /><br /><br />&lt;build>    <br />      &lt;finalName>PromoteC&lt;/finalName><br />&lt;/build><br /><br /><br />依赖管理<br /><br />创 建好项目结构，添加完一些代码，测试并编译好应用程序后，接下来可以看看Maven是如何处理依赖关系的。为了给项目添加一个依赖项，必须将此依赖项添加 到pom.xml文件中。下次运行Maven的时候，它将从Ibiblio存储库中得到这个依赖项，并且将此依赖项添加到项目构建路径中。<br /><br />关 于依赖的问题有几个重要的事情值得注意。在写这篇文章的时候，Maven中最大的麻烦之处就是不能从Maven存储库中获取Sun的jar文件。这个问题 归因于Sun在其代码中设置的许可证限制。解决这个问题的办法有两种，一种是下载这些代码并将它们安装在您本地的存储库中，另一种是做一个外部声明，并将 这个声明指向文件系统中依赖项所在的位置。希望Sun能够尽早地创建自己的存储库，尽管如此，Maven也会被升级来使之能够下载这些资源，只是在下载之 前它会提示用户接受许可证协议。<br /><br />另外一个麻烦的地方就是有时候使用的最新的库文件可能在远程存储库中不存在。另一种可能是由于无法访问 Internet，需要所有的依赖项都能在本地获取。这些问题的最好解决方案就是将jar文件安装到本地的存储库中。将本地的存储库放在一台web服务器 上也同样是个便利之举，这样整个开发团队就能从此获益，每个人都没有必要去管理自己的存储库了。改变Maven的存储库路径只需简单地编辑其安装目录下 conf文件夹下面的settings.xml文件即可。<br /><br />在Maven中使用依赖是简单的。让我们看看往上述pom.xml文件中添加一 个依赖项的情况。我们虽然已经使用了JUnit，但让我们将功能强大的Quartz库添加到项目中。Quartz是一款用纯Java编写的关于时间安排的 开源项目，它是您时间安排需求方面的很好的选择。<br /><br /><br />&lt;dependency>  <br />     &lt;groupId>quartz&lt;/groupId>   <br />     &lt;artifactId>quartz&lt;/artifactId><br />     &lt;version>1.5.1&lt;/version> <br />     &lt;scope>compile&lt;/scope> <br />&lt;/dependency><br /><br /><br />我 们仅仅只需添加&lt;dependencies>这个元素，Maven就能下载Quartz并将其作为项目中的一个依赖项。不用担心Quartz 的依赖项，一个Maven的存储库将包含依赖项自身依赖的资源信息，当Maven下载Quartz的时候，它自身的依赖资源也同样会被下载。为了验证版本 为1.5.1的Quartz存在于Ibiblio库中，我们可以浏览Maven存储库。注意到scope参数的使用，它告诉了Maven依赖项在何种阶段 是所需的。在使用JUnit的情况下，我们设置scope参数的值为test来告诉Maven这个依赖项只是在测试阶段所需的，而不是运行时所需的资源。 以下是scope参数值的说明：<br />--compile：默认值。表明是所有任务所需的资源<br />--test：运行所有的测试用例时所需资源<br />--runtime：表明是运行时所需资源<br />--provided：JDK部分或应用服务器的classpath所需的资源<br /><br />现 在，如何处理那些麻烦的Sun的jar包和那些需要但却不能在远程存储库中找到的jar包了？我们必须使用Maven来手动将这些jar包安装到本地的存 储库中。不用担心，这没有听上去那么困难。为了做个示例，我们将安装Java Activation框架的jar包。首先我们必须从Sun的站点上下载此 jar包，接着我们使用Maven将它导入本地的存储库中。您自己也可以按照Maven上传资源指南中的指导将缺少的jar包安装到Ibiblio中。<br />mvn install:install-file -Dfile=activation.jar<br />    -DgroupId=javax.activation -DartifactId=activation<br />    -Dversion=1.0 -Dpackaging=jar<br /><br />现 在，新的jar包就像其它的项目依赖项一样安装到了本地存储库中。在只需添加依赖声明后，我们就已准备就绪了。在添加jar包和声明它们为依赖项时，必须 确保版本信息的正确性。版本的不匹配会导致Maven在寻找资源时的失败。在导入Sun的jar包时，如果您需要寻求标准命名参数的帮助，可以参考Sun 标准jar包命名。记住，在目前您不能通过存储库来公开发布这些jar包，这将违反Sun的使用条款。<br /><br /><br />&lt;dependency> <br />     &lt;groupId>javax.activation&lt;/groupId>  <br />     &lt;artifactId>activation&lt;/artifactId>   <br />     &lt;version>1.0&lt;/version>   <br />    &lt;scope>compile&lt;/scope> <br />&lt;/dependency><br /><br /><br />您 或许想将依赖项存入一个源代码控制器的库中，源代码控制器决不能执行这个任务。依赖项是经常变化的，并且通常有一套数字方案来标明其版本。这就是说，您明 确地希望有一个内部远程存储库的备份，如果您有一个，这将确保在存储库服务器崩溃并且不能恢复的情况下，您不会丢失所有的自定义资源。不将依赖项放入源代 码控制器中也会节省源代码控制器的存储库服务器上的大量磁盘空间。<br /><br />配置存储库<br /><br />要求项目的每个开发者必须在conf目录中 配置存储库是不方便的，所以Maven可以同时查看多个存储库并且将它们全部配置在pom.xml文件中。让我们看看一个例子，它展示了如何在应用程序用 使用多个存储库。在以下从pom.xml文件摘录的片断中，我们设置了两个存储库来让Maven寻找依赖项。Ibiblio一直是默认的存储库，我们又添 加了Planet Mirror作为后援存储库。我们也可以让团队使用的本地web服务器作为第二个存储库。<br /><br /><br />&lt;repositories>    <br />    &lt;repository>      <br />        &lt;id>Ibiblio&lt;/id>      <br />        &lt;name>Ibiblio&lt;/name>      <br />        &lt;url>http://www.ibiblio.org/maven/&lt;/url>    <br />    &lt;/repository><br />    &lt;repository>      <br />        &lt;id>PlanetMirror&lt;/id>      <br />        &lt;name>Planet Mirror&lt;/name>      <br />        &lt;url>http://public.planetmirror.com/pub/maven/&lt;/url>    <br />   &lt;/repository>  <br />&lt;/repositories><br /><br /><br />使用pom.xml父文件来构建多个项目<br /><br />软 件公司通常的一种做法就是将多个项目构建到主要产品中。维护依赖关系链和一次性地构建整个产品足以成为一个挑战，但是如果使用Maven的话，事情将变得 简单。如果您创建了一个指向其它子模块的pom.xml父文件，Maven将为您处理整个构建过程。它将分析每个子模块的pom.xml文件，并且按照这 些子模块的相互依赖顺序来构建项目。如果每个项目明确地指明它们的依赖项，那么子模块在父文件中的放置顺序是不造成任何影响的。但是考虑到其他的开发者， 最好保证子模块在pom.xml父文件中的放置顺序和您期望的子项目被构建的顺序一样。下面我们看个示例。<br />pom.xml主文件如下：<br /><br /><br />&lt;project>  <br />        &lt;modelVersion>4.0.0&lt;/modelVersion>  <br />        &lt;groupId>com.oreilly&lt;/groupId>  <br />        &lt;version>1.0-SNAPSHOT&lt;/version>  <br />        &lt;artifactId>my-app&lt;/artifactId>  <br />        &lt;packaging>pom&lt;/packaging>  <br />        &lt;modules>    <br />            &lt;module>Common&lt;/module>    <br />            &lt;module>Utilities&lt;/module>    <br />            &lt;module>Application&lt;/module>     <br />            &lt;module>WebApplication&lt;/module>  <br />        &lt;/modules><br />&lt;/project><br /><br /><br />我 们需要确保WebApplication子模块包含了所有的三个jar包，所以需要将这些jar包声明为依赖项。在这个例子中，Utilities项目依 赖于Common项目，所以Utilities项目中需要添加一个对Common项目的依赖。Application子模块也是同样的道理，因为它依赖于 Common和Utilities项目，Utilities又赖于Common。如果这个例子中有60个子模块，并且它们都相互依赖，这会使得新开发者难 以算出什么项目依赖于其它项目，所以这正好是要求确保pom.xml父文件中项目放置顺序要清除的原因。<br /><br />以下是Utility模块的依赖项：<br /><br /><br />&lt;dependencies>    <br />        &lt;dependency>      <br />            &lt;groupId>com.oreilly&lt;/groupId>      <br />            &lt;artifactId>Common&lt;/artifactId>      <br />            &lt;version>1.0-SNAPSHOT&lt;/version>    <br />        &lt;/dependency>  <br />&lt;/dependencies><br /><br /><br />以下是如何声明Application模块的依赖项：<br /><br /><br />&lt;dependencies>    <br />    &lt;dependency>      <br />        &lt;groupId>com.oreilly&lt;/groupId>     <br />         &lt;artifactId>Common&lt;/artifactId>     <br />         &lt;version>1.0-SNAPSHOT&lt;/version>    <br />    &lt;/dependency><br />    &lt;dependency>      <br />        &lt;groupId>com.oreilly&lt;/groupId>      <br />        &lt;artifactId>Utilities&lt;/artifactId>      <br />        &lt;version>1.0-SNAPSHOT&lt;/version>    <br />&lt;/dependency>  <br />&lt;/dependencies><br /><br /><br />最后是WebApplication模块的依赖项：<br /><br /><br />&lt;dependencies>    <br />    &lt;dependency>      <br />        &lt;groupId>com.oreilly&lt;/groupId>      <br />        &lt;artifactId>Common&lt;/artifactId>      <br />        &lt;version>1.0-SNAPSHOT&lt;/version>    <br />    &lt;/dependency>    <br />    <br />    &lt;dependency>      <br />        &lt;groupId>com.oreilly&lt;/groupId>      <br />        &lt;artifactId>Utilities&lt;/artifactId>      <br />        &lt;version>1.0-SNAPSHOT&lt;/version>    <br />    &lt;/dependency>        <br /><br />    &lt;dependency>      <br />        &lt;groupId>com.oreilly&lt;/groupId>      <br />        &lt;artifactId>Application&lt;/artifactId>      <br />        &lt;version>1.0-SNAPSHOT&lt;/version>    <br />    &lt;/dependency>     <br />&lt;/dependencies><br /><br /><br />现在，我们只需为每个子模块的pom.xml文件添加一个元素来表明它们是一个逻辑构建的一部分：<br /><br /><br />&lt;parent>    <br />    &lt;groupId>com.oreilly&lt;/groupId>    <br />    &lt;artifactId>my-app&lt;/artifactId>    <br />    &lt;version>1.0-SNAPSHOT&lt;/version>  <br />&lt;/parent><br /><br /><br />在pom.xml父文件所在的同一个目录中，存在有项目目录：Common, Utilities, Application, 和WebApplication。当我们在该目录中运行mvn package命令时，这些项目会按照依赖顺序而被构建。<br /><br />插件和报表<br /><br />Maven2.0 有大量的插件可以使用。不幸的是，由于Maven的重写，Maven1.0的插件不能在2.0中使用。尽管如此，还是存在一些可以使用的Maven2.0 的插件。下面pom.xml文件中的插件配置示例是直接从Maven2.0网站上得来的。这个插件是用来配置编译选项的。<br /><br /><br />&lt;plugins>    <br />    &lt;plugin>      <br />        &lt;groupId>org.apache.maven.plugins&lt;/groupId>      <br />        &lt;artifactId>maven-compiler-plugin&lt;/artifactId>      <br />        &lt;configuration>        <br />            &lt;source>1.5&lt;/source>        <br />            &lt;target>1.5&lt;/target>      <br />            &lt;/configuration>    <br />        &lt;/plugin><br />&lt;/plugins><br /><br /><br />Maven报表插件可以用来生成不同的报表，这些报表是在当你使用mvn site命令生成项目的站点时产生的。下面的例子展示了如何使用&lt;reporting>元素来配置这类插件中的一个。<br /><br /><br />&lt;reporting>    <br />    &lt;plugins>      <br />        &lt;plugin>        <br />            &lt;groupId>org.apache.maven.plugins&lt;/groupId>        <br />            &lt;artifactId>maven-project-info-reports-plugin&lt;/artifactId>      <br />         &lt;/plugin>    <br />    &lt;/plugins>  <br />&lt;/reporting><br /><br /><br />Maven Plugin Matrix是一个十分实用的工具，它能给出哪些Maven插件适合于哪些版本的Maven。<br /><br />Maven 和 Eclipse<br /><br />如 何能使全世界最好的IDE变得更好了？答案是使用Maven2的插件，它能帮助您寻找依赖项并自动地将它们添加到pom.xml文件中。虽然最好的方法是 首先使用Maven来创建您的项目，然后再用命令mvn eclipse:eclipse来生成Eclipse项目文件，这样最初就能得到一个好的目录结 构，但Maven也可通过其Eclipse插件来管理任何项目。<br /><br />您可以在Eclipse自身的升级器中输入站点http: //m2eclipse.codehaus.org/来安装插件。在安装完成并重启IDE后，您需要在Eclipse的参数选项中配置此插件，设置本地存 储库的位置。这是很重要的一步，因为如果Eclipse默认的存储库不能匹配您默认的需求，Maven会重新下载您的依赖项。配置完成后，将项目导入 Eclipse，鼠标右击该项目，选择Maven 2 -> Enable。现在您可以回到之前的步骤，您可以有更多的选项比如添加依赖项，这将弹 出一个搜索框，您可以搜索依赖项并添加它们，插件会替你编辑pom.xml文件。<br /><br />插件会使用Maven来构建您的项目，就像Eclipse使用Ant来构建项目一样。如果您想获取更多的关于Eclipse整合Maven的信息，可以查阅Maven站点上的Eclipse集成Maven 2.x使用指南。<br /><br />另 一方面，如果您是一个IntelliJ使用爱好者，您也能通过运行指令mvn idea:idea来完成同样的任务。这些IDE        工具能够 节省开发人员的时间。例如，如果一个开发人员为一个项目添加了一些特征，团队里的其他开发人员只需从源代码控制器的存储库中重新获取项目文件即可，这就节 省了每个开发人员必须配置IDE的时间。<br /><br />结论<br /><br />Maven2.0有着许多实用的特点，并且完成任务十分出色。Maven中 最值得称赞的地方就是使用了标准的目录结构和部署。这就使得开发人员能够适应不同的项目，并且不用学习任何结构方面新的东西，也不用掌握特殊的指令来构建 结构。Maven可以通过纯脚本来实现。在文档方面，由于使用了项目站点构建工具，所以当项目构建完成后，您可以查看所有开发的当前状态。<br /><br />毫 无疑问，当提到构建配置的伸缩性，易用性和项目管理方面时，Maven2.0足可以将Ant取而代之。在接下来的几年内，我们将看到Maven作为标准构 建技术更多的使用，直到有人带来了大家公认的“高级捕鼠器”。您可以从下面列出的Maven项目站点上下载Maven。<br /><br />资源<br />Matrix:http://www.matrix.org.cn<br />Onjava:http://www.onjava.com<br />Maven项目站点
          <br/>
          <span style="color:red;">
            <a href="http://agapple.javaeye.com/blog/147380#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 10 Dec 2007 19:54:48 +0800</pubDate>
        <link>http://agapple.javaeye.com/blog/147380</link>
        <guid>http://agapple.javaeye.com/blog/147380</guid>
      </item>
      <item>
        <title>maven2完全使用手册</title>
        <author>agapple</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://agapple.javaeye.com">agapple</a>&nbsp;
          链接：<a href="http://agapple.javaeye.com/blog/147304" style="color:red;">http://agapple.javaeye.com/blog/147304</a>&nbsp;
          发表时间: 2007年12月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          maven2完全使用手册<br />maven2 起步<br />    相信maven1 大家都已经很熟悉了，具体maven能做什么，就不详细说了。个人觉得maven在开源项目中用的还是比较多的，公司内部，就不太清楚了。我以前的公司用过一段时间，不过后来就没有下文了。<br />    与maven1 相比，maven2可算是几乎重写了，不过从速度来说应该更快。<br />    主要的几个新特性包括：（详细参考http://www.ibm.com/developerworks/cn/opensource/os-maven2/index.html）<br />    1． 更快、更简单<br />        速度方面可以比上ant了<br />    2． 更少的配置文件<br />        现在的配置文件只剩下了settings.xml和pom.xml了。<br />    3.  Plugin语言更换<br />        语言开始支持java,BeanShell和ant<br />    4.  提供了预定义的模版<br />        这点是最有帮助的，用户可以自己定义自己的项目模版了，就像用appfuse一样生成项目结构<br />    5． 生命周期的引入<br />         在Maven2中有了明确的生命周期概念，而且都提供与之对应的命令，使得项目构建更加清晰明了。<br />    6.  新增Dependency Scope    <br />         这点也比较重要，有些用于test范围的包，可以不用加入依赖了<br />    7.  传递依赖，简化依赖管理<br />        这是最为方便的，可以省了很多配置。如a 依赖 b,b 依赖c  默认 a也会依赖 c。但是也会带来隐患，如版本冲突。不过maven 也已经考虑到了，可以使用exclusions来排除相应的重复依赖<br /><br />介绍了那么多，现在切入正题，开始maven2 之旅：<br />首些下载需要的工具：<br />maven2: http://maven.apache.org/download.html 最主要的<br />maven-proxy：用来代理repository，使用本地库代替maven2的远程库<br />            http://maven-proxy.codehaus.org/<br />continuum：一个不错的持续整合工具，用于自动build。支持ant,maven<br />http://maven.apache.org/continuum/<br />svn:版本控制工具相信都已经配置了。<br />maven 用于eclipse的插件 ,在maven主站有下载，不错的插件。当然idea也有相应的插件<br />最后，http，服务器是必不可少的。用于内部开发使用。<br />可以使用apache ，或者jetty  http://www.mortbay.org/<br /><br />安装：<br />    安装maven2很简单，把下载来的maven包解开就行了。（目前我的配置都在win2003上，还没有应用于linux，所有所有的配置都针对 windows).增加相应的环境变量m2_home=maven2的安装目录，不要忘了设置java_home的目录。另外在path中增加% m2_home%\bin;可以直接在命令行下面使用mvn。<br />其他工具的安装在后续的文章会介绍。<br /><br />开始第一个mvean2项目：<br />  mvn archetype:create -DgroupId=com.mycompany.app \<br />                   -DartifactId=my-app<br />  简单介绍一下 groupId相当于你的组织，如同org.springframework，会转化为相应得本地路径 artifactId，你主要的jar包名称，也就是你要打成的jar 名称。<br />编译应用资源<br />    mvn compile<br />        编译相应的jave 文件<br />编译测试类以及运行测试类<br />    mvn test<br />       运行测试类<br />如果只想编译test，执行<br />    mvn test-compile<br />打包和安装你的本地库<br />打包：<br />    mvn package<br />安装：<br />    mvn install<br />创建web site<br />    mvn site<br />清除所有输出<br />    mvn clean<br />创建相关的ide文件<br />    mvn idea:idea        或者    mvn eclipse:eclipse<br /><br />    顺便说一下，maven2 是有生命周期这一概念的，也就是说如果你执行package，相应的以前步骤，如compile,test等都会自动执行。<br />刚开始执行会比较慢，需要从maven2远程库中下载所有的文件到本地。如果你的本地没有相应的依赖包，则每次maven都会去远程下载，所以配置一个镜像库就比较重要了。<br />    另外介绍一下主要的参考资料：<br />    mavn2 主站：主要的pom和settings.xml参考资料<br />    Better Builds with Maven     http://www.mergere.com/m2book_download.jsp<br />    不错的书，主要通过例子介绍。可惜都是E文的，花点时间还是值得的。<br />    下一个主题，会说一下maven2的主要配置。<br /><br />--------------------------------------------------------------------------------<br /><br /> <br /> <br />maven 配置篇 之 settings.xml <br />    maven2 比起maven1 来说，需要配置的文件少多了，主要集中在pom.xml和settings.xml中。<br />    先来说说settings.xml，settings.xml对于maven来说相当于全局性的配置，用于所有的项目。在maven2中存在两个 settings.xml，一个位于maven2的安装目录conf下面，作为全局性配置。对于团队设置，保持一致的定义是关键，所以 maven2/conf下面的settings.xml就作为团队共同的配置文件。保证所有的团队成员都拥有相同的配置。当然对于每个成员，都需要特殊的 自定义设置，如用户信息，所以另外一个settings.xml就作为本地配置。默认的位置为：${user.dir} /.m2/settings.xml目录中（${user.dir} 指windows 中的用户目录）。<br />    settings.xml基本结构如下：<br />    &lt;settings xmlns="http://maven.apache.org/POM/4.0.0"<br />          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br />          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 <br />                               http://maven.apache.org/xsd/settings-1.0.0.xsd"><br />  &lt;localRepository/><br />  &lt;interactiveMode/><br />  &lt;usePluginRegistry/><br />  &lt;offline/><br />  &lt;pluginGroups/><br />  &lt;servers/><br />  &lt;mirrors/><br />  &lt;proxies/><br />  &lt;profiles/><br />  &lt;activeProfiles/><br />&lt;/settings><br />简单介绍一下几个主要的配置因素：<br />localRepository：表示本地库的保存位置，也就是maven2主要的jar保存位置，默认在${user.dir}/.m2/repository，如果需要另外设置，就换成其他的路径。<br />offline：如果不想每次编译，都去查找远程中心库，那就设置为true。当然前提是你已经下载了必须的依赖包。<br />Servers<br />   在POM中的 distributionManagement元素定义了开发库。然而，特定的username和pwd不能使用于pom.xml，所以通过此配置来保存server信息<br />  &lt;servers><br />    &lt;server><br />      &lt;id>server001&lt;/id><br />      &lt;username>my_login&lt;/username><br />      &lt;password>my_password&lt;/password><br />      &lt;privateKey>${usr.home}/.ssh/id_dsa&lt;/privateKey><br />      &lt;passphrase>some_passphrase&lt;/passphrase><br />      &lt;filePermissions>664&lt;/filePermissions><br />      &lt;directoryPermissions>775&lt;/directoryPermissions><br />      &lt;configuration>&lt;/configuration><br />    &lt;/server><br />  &lt;/servers> <br />id:server 的id,用于匹配distributionManagement库id，比较重要。 <br />username, password:用于登陆此服务器的用户名和密码 <br />privateKey, passphrase：设置private key，以及passphrase <br />filePermissions, directoryPermissions：当库文件或者目录创建后，需要使用权限进行访问。参照unix文件许可，如664和775 <br />Mirrors <br />表示镜像库，指定库的镜像，用于增加其他库<br />  &lt;mirrors><br />    &lt;mirror><br />      &lt;id>planetmirror.com&lt;/id><br />      &lt;name>PlanetMirror Australia&lt;/name><br />      &lt;url>http://downloads.planetmirror.com/pub/maven2&lt;/url><br />      &lt;mirrorOf>central&lt;/mirrorOf><br />    &lt;/mirror><br />  &lt;/mirrors><br />id,name:唯一的标志，用于区别镜像 <br />url:镜像的url <br />mirrorOf：此镜像指向的服务id <br />Proxies <br />此设置，主要用于无法直接访问中心的库用户配置。<br />  &lt;proxies><br />    &lt;proxy><br />      &lt;id>myproxy&lt;/id><br />      &lt;active>true&lt;/active><br />      &lt;protocol>http&lt;/protocol><br />      &lt;host>proxy.somewhere.com&lt;/host><br />      &lt;port>8080&lt;/port><br />      &lt;username>proxyuser&lt;/username><br />      &lt;password>somepassword&lt;/passwo