<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>41897179</title>
    <description></description>
    <link>http://41897179.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>jsp重复提交问题 </title>
        <author>41897179</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://41897179.javaeye.com">41897179</a>&nbsp;
          链接：<a href="http://41897179.javaeye.com/blog/174276" style="color:red;">http://41897179.javaeye.com/blog/174276</a>&nbsp;
          发表时间: 2008年03月20日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          看了网上的，有几种方法：<br />1 在你的表单页里HEAD区加入这段代码: <br />&lt;META HTTP-EQUIV="pragma" CONTENT="no-cache"> <br />&lt;META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate"> <br />&lt;META HTTP-EQUIV="expires" CONTENT="Wed, 26 Feb 1997 08:21:57 GMT"><br />2 <br />生成一个令牌保存在用户session中，在form中加一个hidden域，显示该令 <br />牌的值，form提交后重新生成一个新的令牌，将用户提交的令牌和session <br />中的令牌比较，如相同则是重复提交<br />3<br />在你的服务器端控件的代码中使用Response.Redirect("selfPage")语句。但是大多的数都不使用这种方法。<br />方法还有很多。。。<br />4<br />&lt;input type="button" value="提交" onclick="this.disabled=true;this.form.submit()"><br /><br />5<br /><br />在JSP页面的FORM表单中添加一个hidden域   <br />  &lt;input   type="hidden"   name="url"value=&lt;%=request.getRequestURL()%>>   <br />    <br />  在你的serverlet中添加如下语句   <br />  String   url=request.getParameter("url");   <br />  response.sendRedirect(url);   <br />  我一般都是采用这样的方法返回JSP页面的,不太明白你说的重复刷新是什么概念   <br /><br />6 ajax 无刷新提交<br /><br />7  Web开发中防止浏览器的刷新键引起系统操作重复提交<br /> 怎么解决呢？重定向可以解决页面刷新带来的数据的重复提交的问题，我们自然可以利用重定向的方式来解决这个问题。但是struts的action里面mapping.findword（）；跳转的话，默认的是在工程文件夹里面找要跳转的页面。这种情况，怎么解决呢？<br /> 修改struts－config.xml 文件， 在action里面有一个redirect重新定向的属性，struts中默认的是false，添加这个属性，改成true，在forword中写上要跳转页面的绝对或者相对地址就行了<br />修改如下：<br />&lt;action-mappings><br />  &lt;action attribute="newsActionForm" name="newsActionForm"<br />   input="/addnews.jsp" path="/newsAction" parameter="method"<br />   scope="request" type="com.yongtree.news.action.NewsAction"><br />   &lt;forward name="list" path="/listnews.jsp" redirect="true">&lt;/forward><br />   &lt;forward name="error" path="/addnews.jsp">&lt;/forward><br />  &lt;/action><br />&lt;/action-mappings><br /> <br /><br /> 重复提交、重复刷新、防止后退的问题以及处理方式<br /><br />一。前言<br />你在任何一个比较专业的BBS都会看到这样的问题，即使你Google一下，也会发现有很多的人在关注和询问，但大家给出的解决方法却都是千差万别，（有的人主张采用脚本来解决;有的则想重定向到别的页面;有的则将此问题提升到Token的角度）为什么会有如此大的差异呢？<br /><br />二。问题场景<br />首先，我们应该先了解为什么要处理这样的问题？或者专业一点就是它适合的场景是什么？（似乎只有人来问没有人来解释）<br /><br />1。重复提交、重复刷新的场景<br />重复提交、重复刷新都是来解决系统重复记录的问题。也就是说某个人在多次的提交某条记录（为什么？也许是闲了没有事情干的;最有可能是用户根本就不知道自己的提交结果是否已经执行了？！）。<br /><br />但出现了这样的问题并不见得就必须处理，要看你所开发的系统的类别而定。比如你接手的是某个资源管理系统，系统本身从需求的角度根本就不允许出现"重复"的记录，在这样需求的约束条件下，去执行重复的提交动作只会引发“业务级异常”的产生，根本就不可能执行成功也就无所谓避免不避免的问题了。<br /><br /> <br /><br />2。防止后退的场景<br />了解了重复刷新、重复提交的场景，我们来了解一下"防止后退"操作的原因是什么？比如你在开发某个投票系统，它有很多的步骤，并且这些步骤之间是有联系的，比如第一步会将某些信息发送给第二步，第二步缓存了这些信息，同时将自身的信息发送给了第三步。。。。。等等，如果此时用户处在第三步骤下，我们想象一下某个淘气用户的用户点击了后退按钮，此时屏幕出现了第二步骤的页面，他再次的修改或者再次的提交，进入到下一个步骤（也就是第三步骤），错误就会在此产生？！什么错误呢？最为典型的就是这样的操作直接导致了对于第一个步骤信息的丢失！（如果这样的信息是依靠Request存放的话，当然你可以存放在Session或者更大的上下文环境中，但这不是个好主意！关于信息存放的问题，下次在就这个问题详细的讨论）<br /><br /><br />三。如何处理的问题<br />当然很多的系统（比如订票系统从需求上本身是允许个人重复订票的）是必须要避免重复刷新、重复提交、以及防止后退的问题的，但即使是这样的问题，也要区分如何处理以及在哪里处理的（网上只是告诉你如何处理，但很少去区分在哪里处理的），显然处理的方式无非是客户端或者服务器端两种，而面对不同的位置处理的方式也是不同的，但有一点要事先声明：任何客户端（尤其是B/S端）的处理都是不可信任的，最好的也是最应该的是服务器端的处理方法。<br /><br />客户端处理：<br />面对客户端我们可以使用Javascript脚本来解决，如下<br /><br />1。重复刷新、重复提交<br />Ways One：设置一个变量，只允许提交一次。<br />&lt;script language="javascript"> <br />    var checkSubmitFlg = false; <br />    function checkSubmit() { <br />      if (checkSubmitFlg == true) { <br />         return false; <br />      } <br />      checkSubmitFlg = true; <br />      return true; <br />   } <br />   document.ondblclick = function docondblclick() { <br />    window.event.returnValue = false; <br />   } <br />   document.onclick = function doconclick() { <br />       if (checkSubmitFlg) { <br />         window.event.returnValue = false; <br />       } <br />   } <br />&lt;/script> <br />&lt;html:form action="myAction.do" method="post" onsubmit="return checkSubmit();"><br /><br />Way Two : 将提交按钮或者image置为disable<br />  &lt;html:form action="myAction.do" method="post"  <br />    onsubmit="getElById('submitInput').disabled = true; return true;">   <br />  &lt;html:image styleId="submitInput" src="images/ok_b.gif" border="0" /> <br />  &lt;/html:form>  <br /><br />2。防止用户后退<br />这里的方法是千姿百态，有的是更改浏览器的历史纪录的，比如使用window.history.forward()方法;有的是“用新页面的URL替换当前的历史纪录，这样浏览历史记录中就只有一个页面，后退按钮永远不会变为可用。”比如使用javascript:location.replace(this.href); event.returnValue=false; <br /><br /><br />2.服务器端的处理（这里只说Struts框架的处理）<br />利用同步令牌（Token）机制来解决Web应用中重复提交的问题，Struts也给出了一个参考实现。<br /><br />基本原理：<br />服务器端在处理到达的请求之前，会将请求中包含的令牌值与保存在当前用户会话中的令牌值进行比较，<br />看是否匹配。在处理完该请求后，且在答复发送给客户端之前，将会产生一个新的令牌，该令牌除传给<br />客户端以外，也会将用户会话中保存的旧的令牌进行替换。这样如果用户回退到刚才的提交页面并再次<br />提交的话，客户端传过来的令牌就和服务器端的令牌不一致，从而有效地防止了重复提交的发生。<br /><br />if (isTokenValid(request, true)) { <br />    // your code here <br />    return mapping.findForward("success"); <br />} else { <br />    saveToken(request); <br />    return mapping.findForward("submitagain"); <br />} <br /><br />Struts根据用户会话ID和当前系统时间来生成一个唯一（对于每个会话）令牌的，具体实现可以参考<br />TokenProcessor类中的generateToken()方法。<br /><br />1. //验证事务控制令牌,&lt;html:form >会自动根据session中标识生成一个隐含input代表令牌，防止两次提交<br />2. 在action中：<br /><br /><br />       //&lt;input type="hidden" name="org.apache.struts.taglib.html.TOKEN"  <br />       //  value="6aa35341f25184fd996c4c918255c3ae"> <br />       if (!isTokenValid(request)) <br />           errors.add(ActionErrors.GLOBAL_ERROR, <br />                      new ActionError("error.transaction.token")); <br />       resetToken(request); //删除session中的令牌 <br /><br />3. action有这样的一个方法生成令牌<br />   protected String generateToken(HttpServletRequest request) { <br />       HttpSession session = request.getSession(); <br />       try { <br />           byte id[] = session.getId().getBytes(); <br />           byte now[] = <br />               new Long(System.currentTimeMillis()).toString().getBytes(); <br />           MessageDigest md = MessageDigest.getInstance("MD5"); <br />           md.update(id); <br />           md.update(now); <br />           return (toHex(md.digest())); <br />       } catch (IllegalStateException e) { <br />           return (null); <br />       } catch (NoSuchAlgorithmException e) { <br />           return (null); <br />       } <br />   }  <br /><br />总结<br />对于重复提交、重复刷新、防止后退等等都是属于系统为避免重复记录而需要解决的问题，在客户端去处理需要针对每一种的可能提出相应的解决方案，然而在服务器端看来只不过是对于数据真实性的检验问题，基于令牌的处理就是一劳永逸的方法。<br /><br />同时我们也看到，从不同的角度去看待问题，其解决的方法也是不同的。客户端更追求的是用户的操作，而服务端则将注意力放在了数据的处理上，所以在某个对于服务器端看似容易的问题上，用客户端来解决却麻烦了很多！反之依然。所以在某些问题的处理上我们需要综合考虑和平衡，是用客户端来解决？还是用服务器端来处理？
          <br/>
          <span style="color:red;">
            <a href="http://41897179.javaeye.com/blog/174276#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/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/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>Thu, 20 Mar 2008 19:26:03 +0800</pubDate>
        <link>http://41897179.javaeye.com/blog/174276</link>
        <guid>http://41897179.javaeye.com/blog/174276</guid>
      </item>
      <item>
        <title>Quartz Cron Expression </title>
        <author>41897179</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://41897179.javaeye.com">41897179</a>&nbsp;
          链接：<a href="http://41897179.javaeye.com/blog/160943" style="color:red;">http://41897179.javaeye.com/blog/160943</a>&nbsp;
          发表时间: 2008年02月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <table border="0"><tbody><tr><th class="confluenceTh"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-family: Palatino Linotype">Field Name</span> </span></span></span></th><th class="confluenceTh"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-family: Palatino Linotype">Mandatory?</span> </span></span></span></th><th class="confluenceTh"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-family: Palatino Linotype">Allowed Values</span> </span></span></span></th><th class="confluenceTh"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-family: Palatino Linotype">Allowed Special Characters</span> </span></span></span></th></tr><tr><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">Seconds</span> </span></span></span></span></p></td><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">YES</span> </span></span></span></span></p></td><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">0-59</span> </span></span></span></span></p></td><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">, - * /</span> </span></span></span></span></p></td></tr><tr><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">Minutes</span> </span></span></span></span></p></td><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">YES</span> </span></span></span></span></p></td><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">0-59</span> </span></span></span></span></p></td><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">, - * /</span> </span></span></span></span></p></td></tr><tr><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">Hours</span> </span></span></span></span></p></td><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">YES</span> </span></span></span></span></p></td><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">0-23</span> </span></span></span></span></p></td><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">, - * /</span> </span></span></span></span></p></td></tr><tr><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">Day of month</span> </span></span></span></span></p></td><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">YES</span> </span></span></span></span></p></td><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">1-31</span> </span></span></span></span></p></td><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">, - * ? / L W C</span> </span></span></span></span></p></td></tr><tr><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">Month</span> </span></span></span></span></p></td><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">YES</span> </span></span></span></span></p></td><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">1-12 or JAN-DEC</span> </span></span></span></span></p></td><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">, - * /</span> </span></span></span></span></p></td></tr><tr><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">Day of week</span> </span></span></span></span></p></td><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">YES</span> </span></span></span></span></p></td><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">1-7 or SUN-SAT</span> </span></span></span></span></p></td><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">, - * ? / L C #</span> </span></span></span></span></p></td></tr><tr><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">Year</span> </span></span></span></span></p></td><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">NO</span> </span></span></span></span></p></td><td class="confluenceTd"><p align="center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: x-small"><span style="font-size: small"><span style="font-family: Palatino Linotype">empty, 1970-2099</span> </span></span></span></span></p></td><td class="confluenceTd"><p align="center"><span style="font-size: x-small; font-family: Palatino Linotype"><span style="font-size: x-small; font-family: 宋体"><span style="font-size: small">, - * /</span></span></span> </p></td></tr></tbody></table><div align="left"><span style="color: #000080; font-family: Palatino Linotype"><strong>项目实例：</strong> </span></div><div><span style="color: #000080; font-family: Palatino Linotype"><table border="0" style="width: 452px; height: 108px"><tbody><tr><td><p align="center">&nbsp;</p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">&nbsp;<span style="color: #000080; font-family: Palatino Linotype">second</span></span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">&nbsp;<span style="color: #000080; font-family: Palatino Linotype">minute</span></span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">&nbsp;<span style="color: #000080; font-family: Palatino Linotype">hours</span></span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">&nbsp;<span style="color: #000080; font-family: Palatino Linotype">dayOfMonth</span></span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">&nbsp;<span style="color: #000080; font-family: Palatino Linotype">month</span></span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small"><span style="color: #000080; font-family: Palatino Linotype">dayOfWeek</span>&nbsp;</span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">&nbsp;<span style="color: #000080; font-family: Palatino Linotype">year</span></span></span></p></td></tr><tr><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">&nbsp;<span style="color: #000080; font-family: Palatino Linotype">每月</span></span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">&nbsp;<span style="color: #000080; font-family: Palatino Linotype">0&nbsp;</span></span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">&nbsp;<span style="color: #000080; font-family: Palatino Linotype">0&nbsp;</span></span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">&nbsp;<span style="color: #000080; font-family: Palatino Linotype">6</span></span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">&nbsp;<span style="color: #000080; font-family: Palatino Linotype">?&nbsp;</span></span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">&nbsp;<span style="color: #000080; font-family: Palatino Linotype">&nbsp;*&nbsp;</span></span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">&nbsp;<span style="color: #000080; font-family: Palatino Linotype">6#3&nbsp;</span></span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">&nbsp;<span style="color: #000080; font-family: Palatino Linotype">?</span></span></span></p></td></tr><tr><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">&nbsp;<span style="color: #000080">每周</span></span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">59</span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">59</span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">18</span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">?</span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">*</span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">1</span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">?</span></span></p></td></tr><tr><td><p align="center"><span style="font-size: x-small"><span style="font-size: small"><span style="color: #000080">自定义</span>&nbsp;</span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">28</span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">47</span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">9</span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">30</span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">7</span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">?</span></span></p></td><td><p align="center"><span style="font-size: x-small"><span style="font-size: small">2006</span></span></p></td></tr></tbody></table></span></div><div align="left"><span style="color: #000080; font-family: Palatino Linotype">每月：每个月的第三个星期五的上午6:00:00 触发</span> </div><div align="left"><span style="color: #000080; font-family: Palatino Linotype">每周：每周的星期日的下午18:59:59 触发</span> </div><div align="left"><span style="color: #000080; font-family: Palatino Linotype">自定义：2006年7月30日上午9:47:28 触发</span> </div><div align="left"><span style="font-family: Palatino Linotype"><p>所有星号对应的段位置，都可以出现后面的符号（, - * /） <br />（? / L C）这些符号可以出现在&quot;一月哪天&quot;和&quot;星期&quot;段位置 <br />（w）只能出现在&quot;一月哪天&quot;段位置 <br />（#）只能出现在&quot;星期&quot;段位置</p><p>解释符号代表的意思： <br />* 代表任意合法的字段 <br />0 * 17 * * ? ：表示在每天的5 PM 到 5:59之间的每一分钟启动scheduler <br /><br />? 表示没值被指定 <br />如果同时指定&quot;一月哪天&quot;和&quot;星期&quot;，可能两者对应不起来 <br />0 0,15,30,45 * * * ? ：表示每刻钟启动scheduler <br />所以推荐用法是其中一个指定值，另一个用?指定</p><p>/ 表示时间的增量 <br />0 0/15 * * * ? ：表示每刻钟启动scheduler <br /><br />- 表示值的范围 <br />0 45 3-8 ? * * <br /><br />L 如果用在&quot;一月哪天&quot;段上，表示一个月的最后一天；如果用在&quot;星期&quot;段上。表示一个星期的最后一天（星期六） <br />0 0 8 L * ? ：表示每个月最后一天的8点启动scheduler <br /><br />W 表示最靠近给定时间的一天，（必须是星期一到星期五）</p><p># 例如 6#3表示一个月的第三个星期五</p></span></div>
          <br/>
          <span style="color:red;">
            <a href="http://41897179.javaeye.com/blog/160943#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><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/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/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 01 Feb 2008 11:28:06 +0800</pubDate>
        <link>http://41897179.javaeye.com/blog/160943</link>
        <guid>http://41897179.javaeye.com/blog/160943</guid>
      </item>
      <item>
        <title>网络使用最广泛的50款BLOG程序</title>
        <author>41897179</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://41897179.javaeye.com">41897179</a>&nbsp;
          链接：<a href="http://41897179.javaeye.com/blog/126011" style="color:red;">http://41897179.javaeye.com/blog/126011</a>&nbsp;
          发表时间: 2007年09月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><strong>ASP</strong></p>
<p>L-Blog: <a href="http://www.loveyuki.com/" target="_blank">http://www.loveyuki.com</a><br />
由Loveyuki自主开发的基于 ASP+Access 的小型单用户BLOG，目前似乎已经停止更新了，但是用户群相当大，而且是国内相当多的BLOG系统的鼻祖。</p>
<p>oblog: <a href="http://www.oioj.net/" target="_blank">http://www.oioj.net</a><br />
多用户Blog,目前占据ASP多用户BLOG的大部分市场，2.X商业版已经实行免费，很值得继续关注与期待的国内作品。</p>
<p>SLblog：<a href="http://slblog.com/" target="_blank">http://SLblog.com</a><br />
多用户Blog，刚发展起来的，更新很快，感觉像是oblog和missblog的结合体，同时首创了Blog系统无限级分类和用户栏目的无限级分类，多功能在现编辑器。但界面不是很美观，好在模板和程序分离，方便修改。</p>
<p>Misslog: <a href="http://www.misslog.com/blog" target="_blank">http://www.misslog.com/blog</a><br />
多用户blog,每个blog可以有多个用户参与创作与维护，团队功能很强大！</p>
<p>LBS: <a href="http://www.voidland.com/blog" target="_blank">http://www.voidland.com/blog</a><br />
LBS早期基于L-Blog架构，自从LBS2推出以后，大部分属于自己的创作，模板很多，用户群也逐渐庞大。</p>
<p>Z-Blog: <a href="http://www.rainbowsoft.org/zblog/" target="_blank">http://www.rainbowsoft.org/zblog/</a><br />
今年发展相当快的Blog系统，官方提供了想当丰富的支持，也创造了比较好的交流环境，这是他的一大亮点。</p>
<p><a href="http://www.pjhome.net/" target="_blank">PJBlog</a>: <a href="http://www.pjhome.net/" target="_blank">http://www.pjhome.net/</a><br />
基于ASP的单用户BLOG系统，由于其插件异常丰富，可扩展的功能很多，比较适合喜欢功能饱满的朋友。</p>
<p>Alpar's Blog: <a href="http://blog.fz0132.com/" target="_blank">http://blog.fz0132.com</a><br />
基于L-Blog架构，但是作了相当大程度的修改，全面兼容LBS^2 的Style，目前版本模板采用DIV+CSS，很值得期待后续发展。</p>
<p>nblog: <a href="http://blog.nowans.com/" target="_blank">http://blog.nowans.com/</a><br />
一个基于Access的个人Blog程序，全生成静态页面，刚开始起步。</p>
<p>2s-space:<a href="http://www.2s-space.com/">http://www.2s-space.com</a></p>
<p>d2kblog: <a href="http://www.d2ksoft.com/" target="_blank">http://www.d2ksoft.com/</a><br />
D2KSoft公司的redguardtoo基于卫慧杰的<a href="http://www.loveyuki.com/">L-Blog1.06</a>扩展而成，事实上，90％的代码我都重新写过了，支持多国语言页面内容和页面样式分离。 </p>
<p>KeeBlogSystem: <a href="http://keesky.com/blog/" target="_blank">http://keesky.com/blog/</a><br />
XUL后台管理，很有特点的一个BLOG系统。</p>
<p><strong>ASP.NET</strong></p>
<p>.Text: <a href="http://scottwater.com/Dottext/default.aspx" target="_blank">http://scottwater.com/Dottext/default.aspx</a><br />
很有名的ASP的blog系统，官方暂无静态化（对每页生成静态的html页面）版本，国内donews使用该软件。</p>
<p>BlogX: <a href="http://www.simplegeek.com/CategoryView.aspx/BlogX" target="_blank">http://www.simplegeek.com/CategoryView.aspx/BlogX</a><br />
程序是英国人编写的,国内 BLANKSOFT.COM 进行了汉化和修改。</p>
<p>dasBlog: <a href="http://www.dasblog.net/" target="_blank">http://www.dasblog.net</a><br />
功能比较齐全，对FireFox的支持不怎么好。</p>
<p><strong>PHP</strong></p>
<p>Okphp BLOG: <a href="http://cn.okphp.com/" target="_blank">http://cn.okphp.com/</a><br />
基于PHP+MYSQL开发的多用户BLOG系统，部分代码ZEND，主要特点能够很好地和许多论坛程序无缝兼容。</p>
<p>BlogHoster: <a href="http://www.webligo.com/" target="_blank">http://www.webligo.com</a><br />
国外的一个多用户商业BLOG系统，基于PHP+MYSQL，简洁明快的风格。</p>
<p>exBlog: <a href="http://www.exblog.net/" target="_blank">http://www.exblog.net/</a><br />
基于PHP/MySQL平台开发，注重稳定效率和兼容性，使用了 PHPLIB 的模板系统，提供WAP接口。</p>
<p>Pixelpost PhotoBlog: <a href="http://www.pixelpost.org/" target="_blank">http://www.pixelpost.org/</a><br />
国外的由图片系统和博客系统融合来的新型博客，已经由落伍的 星 完成汉化。</p>
<p>bMachine： <a href="http://boastology.com/" target="_blank">http://boastology.com</a><br />
国外老牌BLOG系统，同时支持文本数据库和MySQL数据库，支持中文搜索。</p>
<p>7log: <a href="http://www.7log.com/" target="_blank">http://www.7log.com</a><br />
比较早的能够生成静态页面的BLOG系统，目前开发进度停滞。</p>
<p>O-blog: <a href="http://www.phpblog.cn/" target="_blank">http://www.phpblog.cn/</a><br />
需在PHP+MYSQL环境下运行，主要特色对静态生成有很大的灵活度，作者风色默默无闻地开发也让人钦佩。</p>
<p>pigface blog: <a href="http://www.flashforweb.com/" target="_blank">http://www.flashforweb.com/</a><br />
一个简单的BLOG,具备所有BLOG必须的功能，基于PHP＋MYSQL。</p>
<p>bo-blog: <a href="http://www.bo-blog.com/" target="_blank">http://www.bo-blog.com/</a><br />
文本数据库，现在发展似乎遇到了瓶颈，发展不如年初那么火热，但是一样有很多追随者。</p>
<p>C-Blog: <a href="http://www.saysay.cn/" target="_blank">http://www.saysay.cn</a><br />
由 Coolsky 自主开发的基于 PHP+Smarty模版引擎+ADODB组件 的小型单用户BLOG，目前提供2个版本:php+mysql版本 和php+access版本，能够生成静态页面。</p>
<p>SaBlog: <a href="http://www.4ngel.net/blog/angel/" target="_blank">http://www.4ngel.net/blog/angel/</a><br />
安全天使小组开发的一套BLOG系统，功能不断在完善，优点在于安全性很高。</p>
<p>Simple PHP Blog: <a href="http://www.simplephpblog.com/" target="_blank">http://www.simplephpblog.com/</a><br />
国外一个轻便的blog系统，包含中文语言文件。</p>
<p>yo2blog: <a href="http://www.oneoo.com/" target="_blank">http://www.oneoo.com/</a><br />
一个简单小巧快捷的 blog 程序，使用假性目录结构生成类静态 HTML 页面链接。</p>
<p>sBLOG: <a href="http://www.sblog.cn/" target="_blank">http://www.sblog.cn/</a><br />
国外一款基于PHP+MySQL的BLOG系统，模板遵循W3C规范，并提供mod_rewrite功能支持。</p>
<p>b2： <a href="http://www.cafelog.com/" target="_blank">http://www.cafelog.com</a> php<br />
blog的老祖宗，操作简单，容易上手，现在好像停止了开发。</p>
<p>b2evolution: <a href="http://www.b2evolution.net/" target="_blank">http://www.b2evolution.net</a><br />
B2多用户版，有很多风格和插件。</p>
<p>wordpress： <a href="http://www.wordpress.org/" target="_blank">http://www.wordpress.org</a><br />
架站比MT简单一点，功能也很全面，应该是支持blog的首选。它有最强的模版功能，已经开始有限范围内测试多用户的新版。</p>
<p>pivot： <a href="http://www.pivotlog.net/" target="_blank">http://www.pivotlog.net</a><br />
PHP+XML，没有使用数据库，有中文语言包，</p>
<p>nucleus： <a href="http://www.nucleuscms.org/" target="_blank">http://www.nucleuscms.org</a><br />
这个也是比较老牌的程序了，有中文语言包！</p>
<p>M-logger： <a href="http://miracle.shakeme.net/" target="_blank">http://miracle.shakeme.net</a><br />
文本储存数据。</p>
<p>drupal： <a href="http://www.drupal.org/" target="_blank">http://www.drupal.org</a><br />
功能强大，在多用户支持上尤为突出。它看起来更像一个内容发布系统（CMS）而不是一个纯blog软件，所以仅仅只想使用blog功能的朋友就用不着扛着这门炮了。</p>
<p>Pmschine： <a href="http://www.pmachine.com/" target="_blank">http://www.pmachine.com</a><br />
这个估计是blog的元老了，不过现在已经商业化了，新版本名叫Expression Engine，在国内可以免费下载！</p>
<p>bBlog： <a href="http://dev.bblog.com/" target="_blank">http://dev.bblog.com/</a><br />
一个非常简洁好用的blog，汉化版： <a href="http://www.xptop.com/lei/" target="_blank">http://www.xptop.com/lei/</a></p>
<p>serendipity： <a href="http://www.s9y.org/" target="_blank">http://www.s9y.org</a><br />
功能很多，每个功能以模块方式安装，界面也很容易修改。</p>
<p>Plog <a href="http://www.plogworld.net/" target="_blank">http://www.plogworld.net</a><br />
blog里的最好作品了，真正的多用户，不过目前官方网站打不开，不知道是不是偶的网络问题，呵呵！</p>
<p>Plainslash： <a href="http://www.51zhao.com/plainslash/" target="_blank">http://www.51zhao.com/plainslash/</a><br />
文本blog程序，作者很久没更新了，但现在blog的基本功能都有了。</p>
<p><strong>CGI</strong></p>
<p>movable Type： <a href="http://www.movabletype.org/" target="_blank">http://www.movabletype.org</a><br />
一个cgi程序的blog软件，应用最为广泛，大陆不算十分多，香港台湾的80%以上的独立blog站点都是通过它架设的。插件众多，基本需要的功能都能实现，它支持多用户blog。</p>
<p>Greymatter： <a href="http://www.noahgrey.com/greysoft/" target="_blank">http://www.noahgrey.com/greysoft/</a><br />
是一个类似 Movable Type 的Blog程序非常简单，也是生成静态文件。</p>
<p>HUS Reviv： <a href="http://supermanc.51.net/norman/blog.cgi" target="_blank">http://supermanc.51.net/norman/blog.cgi</a><br />
国人开发的，功能很强大，但由于cgi语言的问题，安装调试比较复杂，而且很占资源。</p>
<p>Blosxom： <a href="http://www.blosxom.com/" target="_blank">http://www.blosxom.com</a><br />
很老的一个程序了，也可能是世界上最小的blog系统了，只有一个文件却实现了blog的大部分功能！ </p>
<p><strong>JSP</strong></p>
<p>Roller：<a href="http://www.rollerweblogger.org/page/project" target="_blank">http://www.rollerweblogger.org/page/project</a><br />
国外运用想当广泛的一套BLOG系统。</p>
<p>DLOG4J： <a href="http://dlog4j.sourceforge.net/" target="_blank">http://dlog4j.sourceforge.net/</a><br />
国人开发的，已经申报SourceForge项目 中文官方站： <a href="http://www.javayou.com/" target="_blank">http://www.javayou.com</a></p>
<p>TM： <a href="http://www.terac.com/" target="_blank">http://www.terac.com</a><br />
一个功能强大的blog，支持文件上传、RSS、评论、WYSIWYG 编辑器等功能，多种语言（含简体中文）</p>
          <br/>
          <span style="color:red;">
            <a href="http://41897179.javaeye.com/blog/126011#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/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/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</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>Sat, 22 Sep 2007 23:28:00 +0800</pubDate>
        <link>http://41897179.javaeye.com/blog/126011</link>
        <guid>http://41897179.javaeye.com/blog/126011</guid>
      </item>
      <item>
        <title>[转]Spring XML配置的12个技巧</title>
        <author>41897179</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://41897179.javaeye.com">41897179</a>&nbsp;
          链接：<a href="http://41897179.javaeye.com/blog/126009" style="color:red;">http://41897179.javaeye.com/blog/126009</a>&nbsp;
          发表时间: 2007年09月21日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>Spring是一个强有力的java程序框架，其被广泛应用于java的程序中。它用POJO提供了企业级服务。Spring利用依赖注入可以获得简单而有效的测试能力。Spring beans，依赖关系，以及服务所需要的bean都将在配置文件中予以描述，配置文件一般采用XML格式。然而XML配置文件冗长而不易使用，在你进行一个使用了大量bean的大项目中它将变得难以阅读和控制。</p>
<div class="entry-more" id="more">
<p>在这篇文章中我将给你展示12种的有关Spring XML配置文件的最佳技巧。它们中的一些具有更多的实际意义，而不仅是最好的技巧。请注意另外一些因素，例如域模型的设计，会影响到XML配置，但是这篇文章更关注于XML配置的可读性和可操控性。<br />
<br />
1． 避免使用自动装配<br />
<br />
Spring可以通过bean类的自省来实现自动装配依赖，这样的话你就不必明确地描述bean的属性或者构造函数的参数。根据属性名称活匹配类型， bean属性可以自动进行装配。而构造函数可以根据匹配类型自动装配。你甚至可以设置自动装配进行自动侦测，这样Spring替你就会选择一个合适的机 制。请看下面的例子：<br />
&nbsp;&nbsp; <br />
Spring可以通过bean类的自省来实现自动装配依赖，这样的话你就不必明确地描述bean的属性或者构造函数的参数。根据属性名称活匹配类型， bean属性可以自动进行装配。而构造函数可以根据匹配类型自动装配。你甚至可以设置自动装配进行自动侦测，这样Spring替你就会选择一个合适的机 制。请看下面的例子：<br />
<br />
&nbsp; &nbsp;&nbsp;&nbsp; <bean id="orderService"></bean><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class=&quot;com.lizjason.spring.OrderService&quot;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; autowire=&quot;byName&quot;/&gt;&nbsp;<br />
<br />
OrderService类的属性名被用来和容器中的一个bean实例进行匹配。自动装配会默默的保存一些类型信息并降低混乱。然而，由于它会牺牲掉这种 配置的直观性和可维护性，你在实际的项目中将不会用到它。许多指南和陈述材料都把它吹捧为Spring的一个非常cool的特性，而没有提到它的这个缺 点。依我之见，就像Spring的对象池一样，它更多了一些商业味道。它看起来好像可以使XML配置文件更精简一些，但实际上却增加其复杂性，尤其是在你 的较大规模的工程中已经定义了很多bean的时候更是如此。Spring允许你混合使用自动和手动装配，但是这种矛盾会使XML配置更加的令人费解。&nbsp;<br />
<br />
2． 使用命名规范<br />
<br />
和Java编码的理念一样，在项目中始终用清晰的，描述性的，一致的命名规范对开发人员理解XML配置非常有用。拿bean ID举例来说，你可以遵循Java类中属性的命名规范。比如说，OrderServiceDAO的bean ID应该是orderServiceDAO。对于大项目来说，在bean ID前加包名来作为前缀。&nbsp;<br />
<br />
3． 使用简化格式<br />
<br />
简化格式有利于减少冗余，因为它把属性值和引用作为属性，而不是子元素。看下面的例子：<br />
<br />
&nbsp;&nbsp;&nbsp; <bean id="orderService"></bean><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class=&quot;com.lizjason.spring.OrderService&quot;&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<property name="companyName"><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <value></value>lizjason<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </property>
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <constructor-arg></constructor-arg><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <ref bean="orderDAO"></ref><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
<br />
&nbsp;&nbsp;&nbsp; <br />
<br />
以上程序可以重新以简化格式书写为：<br />
<br />
&nbsp;&nbsp;&nbsp; <bean id="orderService"></bean><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class=&quot;com.lizjason.spring.OrderService&quot;&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<property name="companyName"></property>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value=&quot;lizjason&quot;/&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <constructor-arg ref="orderDAO"></constructor-arg><br />
<br />
&nbsp;&nbsp;&nbsp; <br />
<br />
简化格式在1.2版本时已经可用了，但请注意不存在<ref local="..."></ref>这种简化格式不仅可以较少你的代码输入量，而且可以使XML配置更加的清晰。当你的配置文件中存在大量的bean定义时，它可以显著地提高可读性。&nbsp;<br />
<br />
4． 尽量使用type而不是index去解决构造函数参数的匹配问题<br />
<br />
当构造函数中有多个同类型的参数时，Spring只允许你使用从0开始的index或者value标签来解决这个问题。请看下面的例子：<br />
<br />
&nbsp;&nbsp;&nbsp; <bean id="billingService"></bean><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class=&quot;com.lizjason.spring.BillingService&quot;&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <constructor-arg value="lizjason" index="0"></constructor-arg><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <constructor-arg value="100" index="1"></constructor-arg><br />
<br />
&nbsp;&nbsp;&nbsp; <br />
<br />
最好用type属性取代上面的做法：<br />
<br />
&nbsp;&nbsp;&nbsp; <bean id="billingService"></bean><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class=&quot;com.lizjason.spring.BillingService&quot;&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <constructor-arg type="java.lang.String"></constructor-arg><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value=&quot;lizjason&quot;/&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <constructor-arg type="int" value="100"></constructor-arg><br />
<br />
&nbsp;&nbsp;&nbsp; &nbsp;<br />
<br />
用index可以稍微减少冗余，但是它更容易出错且不如type属性可读性高。你应该仅在构造函数中有参数冲突时使用index。<br />
<br />
5． 如可能，尽量复用bean定义<br />
<br />
Spring提供了一种类似于继承的机制来降低配置信息的重复并使XML配置更加的简单。一个子bean可以从它的父bean继承配置信息，本质上这个父 bean就像它的子bean的一个模板。这是一个在大型项目中必须使用的特性。所有你要做的就是把父bean的abstract属性置为true，并在子 bean中加以引用。例如：<br />
<br />
&nbsp;&nbsp;&nbsp; <bean abstract="true" id="abstractService"></bean><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class=&quot;com.lizjason.spring.AbstractService&quot;&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<property name="companyName"></property>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value=&quot;lizjason&quot;/&gt;<br />
<br />
&nbsp;&nbsp;&nbsp; &nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp; <bean id="shippingService"></bean><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parent=&quot;abstractService&quot;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class=&quot;com.lizjason.spring.ShippingService&quot;&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<property name="shippedBy" value="lizjason"></property>
<br />
<br />
&nbsp;&nbsp;&nbsp; <br />
<br />
shippingService bean继承了abstractService bean的属性companyName的值lizjason。注意，如果你为bean声名一个class或工厂方法，这个bean将会默认为abstract&nbsp;<br />
<br />
6． 尽量使用ApplicationContext装配bean，而不是用import<br />
<br />
像Ant脚本中imports一样，Spring的import 元素对于模块化bean的装配非常有用，例如：<br />
<br />
&nbsp;&nbsp;&nbsp; <beans></beans><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <bean id="orderService"></bean><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class=&quot;com.lizjason.spring.OrderService&quot;/&gt;<br />
<br />
&nbsp;&nbsp;&nbsp; <beans></beans><br />
<br />
然而，比起在XML中用imports预装配这些bean，利用ApplicationContext来配置它们将更加灵活，也可以使XML配置更加的易于管理。你可以像下面这样传递一个bean定义数组到ApplicationContext的构造函数中：<br />
<br />
&nbsp;&nbsp;&nbsp; String[] serviceResources =<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {&quot;orderServices.xml&quot;,<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;billingServices.xml&quot;,<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;shippingServices.xml&quot;};<br />
<br />
ApplicationContext orderServiceContext = new<br />
<br />
ClassPathXmlApplicationContext(serviceResources);&nbsp;<br />
<br />
7． 用id来标识bean<br />
<br />
你可以用id或名字作为bean的标识。用id可读性较差，但是它可以影响XML分析器使bean的reference有效。如果id由于XML IDREF约束而无法使用，你可以用name作为bean的标识。XML IDREF约束是指id必须以字母开始(或者是在XML声名了的一个标点符号)，后面可以是字母，数字，连字符，下划线，冒号或full stops(不知道怎么翻译好)。在实际应用中很少会遇到XML IDREF约束问题。&nbsp;<br />
<br />
8． 在开发阶段使用依赖检查<br />
<br />
你可以为bean的dependency-check属性设置一个值来取代默认的none，比如说simple，objects或者all，这样的话容器 将替你做依赖有效性的检查。当一个bean的所有属性(或者某些属性目录)都被明确设置，或利用自动装配时将会非常有用。<br />
<br />
&nbsp;&nbsp;&nbsp; <bean id="orderService"></bean><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class=&quot;com.lizjason.spring.OrderService&quot;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dependency-check=&quot;objects&quot;&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<property name="companyName"></property>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value=&quot;lizjason&quot;/&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <constructor-arg ref="orderDAO"></constructor-arg><br />
<br />
&nbsp;&nbsp;&nbsp; <br />
<br />
在这个例子中，容器将确保这些属性不是privitives或者保证collections是为orderService bean设置的。为所有的bean设置默认的依赖检查是可能的，但这个特性由于有些bean的属性不需要设置而很少使用。<br />
&nbsp; <br />
9． 为每个配置文件加一个描述注释<br />
<br />
在XML配置文件中最好使用有描述性的id和name，而不是成堆的注释。另外，加一个文件描述头将会非常有用，这个描述可以概括文件中定义的bean。另一个选择，你可以在description元素中加入描述信息。例如：<br />
<br />
&nbsp;&nbsp;&nbsp; <beans></beans><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <description></description><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; This file defines billing service<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; related beans and it depends on<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; baseServices.xml,which provides<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; service bean templates...<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br />
<br />
&nbsp;&nbsp;&nbsp; <br />
<br />
用description元素的一个好处就是工具可以很容易的把描述信息从这个元素中提取出来。&nbsp;<br />
<br />
10．&nbsp;&nbsp; 和team members沟通变更<br />
<br />
当你修改java源码后，要确保更改了配置文件中的相应部分并把这个情况告知你的team members。XML配置文件也是代码，它们是程序的重要组成部分，但它们很难阅读和维护。大多数时间里，你需要同时看XML配置文件和java代码才能知道是怎么回事。&nbsp;<br />
<br />
11．&nbsp;&nbsp; setter注入和构造函数注入，优先使用前者<br />
<br />
Spring提供了三种注入方式：构造函数注入，setter注入和方法注入。一般我们使用前两种。<br />
<br />
&nbsp;&nbsp;&nbsp; <bean id="orderService"></bean><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class=&quot;com.lizjason.spring.OrderService&quot;&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <constructor-arg ref="orderDAO"></constructor-arg><br />
<br />
&nbsp;&nbsp;&nbsp; &nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp; <bean id="billingService"></bean><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class=&quot;com.lizjason.spring.BillingService&quot;&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<property name="billingDAO"></property>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ref=&quot;billingDAO&quot;&gt;<br />
<br />
&nbsp;&nbsp;&nbsp; <br />
<br />
在这个例子中，orderService bean用了构造函数注入，而BillingService bean用了setter注入。构造函数注入可以确保bean正确地构建，但是setter注入更加的灵活和易于控制，特别是当class有多个属性并且 它们中的一些是可选的情况是更是如此。&nbsp;<br />
<br />
12．&nbsp;&nbsp; 不要滥用注入<br />
<br />
就像前面提到的，Spring的ApplicationContext可以替你创建java对象，但不是所有的java对象都应该通过注入创建。例如，域 对象就不应该通过ApplicationContext创建。Spring是一个优秀的框架，但是考虑到可读性和可操控性，基于XML配置的配置会在定义 很多bean的时候出现麻烦。过渡使用依赖注入将会使XML配置更加的复杂和冗长。切记，当使用高效的IDE时，例如Eclipse and IntelliJ，java代码更加的易于阅读，维护和管理比使XML文件<br />
<br />
结论<br />
<br />
XML是Spring流行的配置格式。存在大量bean定义时，基于XML的配置会变得冗长而不易使用。Spring提供了丰富的配置选项。适当地使用这 些选项可以使XML配置更加的清晰，但其它的一些选项，例如自动装配，可能会降低可读性和可维护性。参考本文中提到的这些技巧可能会帮助你创建干净而易读 的XML配置文件</p>
</div>
          <br/>
          <span style="color:red;">
            <a href="http://41897179.javaeye.com/blog/126009#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/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><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></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 21 Sep 2007 17:46:00 +0800</pubDate>
        <link>http://41897179.javaeye.com/blog/126009</link>
        <guid>http://41897179.javaeye.com/blog/126009</guid>
      </item>
      <item>
        <title>(转载)用web.xml控制Web应用的行为</title>
        <author>41897179</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://41897179.javaeye.com">41897179</a>&nbsp;
          链接：<a href="http://41897179.javaeye.com/blog/124898" style="color:red;">http://41897179.javaeye.com/blog/124898</a>&nbsp;
          发表时间: 2007年09月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          1 定义头和根元素 <br />
<br />
部署描述符文件就像所有XML文件一样，必须以一个XML头开始。这个头声明可以使用的XML版本并给出文件的字符编码。 <br />
DOCYTPE声明必须立即出现在此头之后。这个声明告诉服务器适用的servlet规范的版本（如2.2或2.3）并指定管理此文件其余部分内容的语法的DTD(Document Type Definition，文档类型定义)。 <br />
所有部署描述符文件的顶层（根）元素为web-app。请注意，XML元素不像HTML，他们是大小写敏感的。因此，web-App和WEB-APP都是不合法的，web-app必须用小写。 <br />
<br />
2 部署描述符文件内的元素次序 <br />
<br />
XML元素不仅是大小写敏感的，而且它们还对出现在其他元素中的次序敏感。例如，XML头必须是文件中的第一项，DOCTYPE声明必须是第二项，而web-app元素必须是第三项。在web-app元素内，元素的次序也很重要。服务器不一定强制要求这种次序，但它们允许（实际上有些服务器就是这样做的）完全拒绝执行含有次序不正确的元素的Web应用。这表示使用非标准元素次序的web.xml文件是不可移植的。 <br />
下面的列表给出了所有可直接出现在web-app元素内的合法元素所必需的次序。例如，此列表说明servlet元素必须出现在所有servlet-mapping元素之前。请注意，所有这些元素都是可选的。因此，可以省略掉某一元素，但不能把它放于不正确的位置。 <br />
<br />
&middot; icon icon元素指出IDE和GUI工具用来表示Web应用的一个和两个图像文件的位置。 <br />
&middot; display-name display-name元素提供GUI工具可能会用来标记这个特定的Web应用的一个名称。 <br />
&middot; description description元素给出与此有关的说明性文本。 <br />
&middot; context-param context-param元素声明应用范围内的初始化参数。 <br />
&middot; filter 过滤器元素将一个名字与一个实现javax.servlet.Filter接口的类相关联。 <br />
&middot; filter-mapping 一旦命名了一个过滤器，就要利用filter-mapping元素把它与一个或多个servlet或JSP页面相关联。 <br />
&middot; listener servlet API的版本2.3增加了对事件监听程序的支持，事件监听程序在建立、修改和删除会话或servlet环境时得到通知。Listener元素指出事件监听程序类。 <br />
<br />
&middot; servlet 在向servlet或JSP页面制定初始化参数或定制URL时，必须首先命名servlet或JSP页面。Servlet元素就是用来完成此项任务的。 <br />
<br />
&middot; servlet-mapping 服务器一般为servlet提供一个缺省的URL：http://host/webAppPrefix/servlet/ServletName。但是，常常会更改这个URL，以便servlet可以访问初始化参数或更容易地处理相对URL。在更改缺省URL时，使用servlet-mapping元素。 <br />
<br />
&middot; session-config 如果某个会话在一定时间内未被访问，服务器可以抛弃它以节省内存。可通过使用HttpSession的setMaxInactiveInterval方法明确设置单个会话对象的超时值，或者可利用session-config元素制定缺省超时值。 <br />
&middot; mime-mapping 如果Web应用具有想到特殊的文件，希望能保证给他们分配特定的MIME类型，则mime-mapping元素提供这种保证。 <br />
&middot; welcom-file-list welcome-file-list元素指示服务器在收到引用一个目录名而不是文件名的URL时，使用哪个文件。 <br />
&middot; error-page error-page元素使得在返回特定HTTP状态代码时，或者特定类型的异常被抛出时，能够制定将要显示的页面。 <br />
&middot; taglib taglib元素对标记库描述符文件（Tag Libraryu Descriptor file）指定别名。此功能使你能够更改TLD文件的位置，而不用编辑使用这些文件的JSP页面。 <br />
&middot; resource-env-ref resource-env-ref元素声明与资源相关的一个管理对象。 <br />
&middot; resource-ref resource-ref元素声明一个资源工厂使用的外部资源。 <br />
&middot; security-constraint security-constraint元素制定应该保护的URL。它与login-config元素联合使用 <br />
&middot; login-config 用login-config元素来指定服务器应该怎样给试图访问受保护页面的用户授权。它与sercurity-constraint元素联合使用。 <br />
&middot; security-role security-role元素给出安全角色的一个列表，这些角色将出现在servlet元素内的security-role-ref元素的role-name子元素中。分别地声明角色可使高级IDE处理安全信息更为容易。 <br />
&middot; env-entry env-entry元素声明Web应用的环境项。 <br />
&middot; ejb-ref ejb-ref元素声明一个EJB的主目录的引用。 <br />
&middot; ejb-local-ref ejb-local-ref元素声明一个EJB的本地主目录的应用。 <br />
<br />
3 分配名称和定制的UL <br />
<br />
在web.xml中完成的一个最常见的任务是对servlet或JSP页面给出名称和定制的URL。用servlet元素分配名称，使用servlet-mapping元素将定制的URL与刚分配的名称相关联。 <br />
3.1 分配名称 <br />
为了提供初始化参数，对servlet或JSP页面定义一个定制URL或分配一个安全角色，必须首先给servlet或JSP页面一个名称。可通过servlet元素分配一个名称。最常见的格式包括servlet-name和servlet-class子元素（在web-app元素内），如下所示： <br />
&lt;servlet&gt; <br />
&lt;servlet-name&gt;Test&lt;/servlet-name&gt; <br />
&lt;servlet-class&gt;moreservlets.TestServlet&lt;/servlet-class&gt; <br />
&lt;/servlet&gt; <br />
这表示位于WEB-INF/classes/moreservlets/TestServlet的servlet已经得到了注册名Test。给servlet一个名称具有两个主要的含义。首先，初始化参数、定制的URL模式以及其他定制通过此注册名而不是类名引用此servlet。其次,可在URL而不是类名中使用此名称。因此，利用刚才给出的定义，URL http://host/webAppPrefix/servlet/Test 可用于 http://host/webAppPrefix/servlet/moreservlets.TestServlet 的场所。 <br />
请记住：XML元素不仅是大小写敏感的，而且定义它们的次序也很重要。例如，web-app元素内所有servlet元素必须位于所有servlet-mapping元素（下一小节介绍）之前，而且还要位于5.6节和5.11节讨论的与过滤器或文档相关的元素（如果有的话）之前。类似地，servlet的servlet-name子元素也必须出现在servlet-class之前。5.2节&quot;部署描述符文件内的元素次序&quot;将详细介绍这种必需的次序。 <br />
例如，程序清单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时的结果。 <br />
<br />
程序清单5-1 TestServlet.java <br />
package moreservlets; <br />
<br />
import java.io.*; <br />
import javax.servlet.*; <br />
import javax.servlet.http.*; <br />
<br />
/** Simple servlet used to illustrate servlet naming <br />
* and custom URLs. <br />
* &lt;P&gt; <br />
* Taken from More Servlets and JavaServer Pages <br />
* from Prentice Hall and Sun Microsystems Press, <br />
* <a href="http://www.cndiy8.com/www.moreservlets.com/">http://www.moreservlets.com/. </a><br />
* &copy; 2002 Marty Hall; may be freely used or adapted. <br />
*/ <br />
<br />
public class TestServlet extends HttpServlet { <br />
public void doGet(HttpServletRequest request, <br />
HttpServletResponse response) <br />
throws ServletException, IOException { <br />
response.setContentType(&quot;text/html&quot;); <br />
PrintWriter out = response.getWriter(); <br />
String uri = request.getRequestURI(); <br />
out.println(ServletUtilities.headWithTitle(&quot;Test Servlet&quot;) + <br />
&quot;&lt;BODY BGCOLOR=\&quot;#FDF5E6\&quot;&gt;\n&quot; + <br />
&quot;&lt;H2&gt;URI: &quot; + uri + &quot;&lt;/H2&gt;\n&quot; + <br />
&quot;&lt;/BODY&gt;&lt;/HTML&gt;&quot;); <br />
} <br />
} <br />
<br />
<br />
程序清单5-2 web.xml（说明servlet名称的摘录） <br />
&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt; <br />
&lt;!DOCTYPE web-app <br />
PUBLIC &quot;-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN&quot; <br />
&quot;http://java.sun.com/dtd/web-app_2_3.dtd&quot;&gt; <br />
<br />
&lt;web-app&gt; <br />
&lt;!-- &hellip; --&gt; <br />
&lt;servlet&gt; <br />
&lt;servlet-name&gt;Test&lt;/servlet-name&gt; <br />
&lt;servlet-class&gt;moreservlets.TestServlet&lt;/servlet-class&gt; <br />
&lt;/servlet&gt; <br />
&lt;!-- &hellip; --&gt; <br />
&lt;/web-app&gt; <br />
<p>3.2 定义定制的URL <br />
大多数服务器具有一个缺省的serlvet URL： <br />
<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更简短。 <br />
事实上，有时需要使用定制的URL。比如，你可能想关闭缺省URL映射，以便更好地强制实施安全限制或防止用户意外地访问无初始化参数的servlet。如果你禁止了缺省的URL，那么你怎样访问servlet呢？这时只有使用定制的URL了。 <br />
为了分配一个定制的URL，可使用servlet-mapping元素及其servlet-name和url-pattern子元素。Servlet-name元素提供了一个任意名称，可利用此名称引用相应的servlet；url-pattern描述了相对于Web应用的根目录的URL。url-pattern元素的值必须以斜杠（/）起始。 <br />
下面给出一个简单的web.xml摘录，它允许使用URL http://host/webAppPrefix/UrlTest 而不是http://host/webAppPrefix/servlet/Test或 <br />
<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元素之前。 <br />
&lt;servlet&gt; <br />
&lt;servlet-name&gt;Test&lt;/servlet-name&gt; <br />
&lt;servlet-class&gt;moreservlets.TestServlet&lt;/servlet-class&gt; <br />
&lt;/servlet&gt; <br />
&lt;!-- ... --&gt; <br />
&lt;servlet-mapping&gt; <br />
&lt;servlet-name&gt;Test&lt;/servlet-name&gt; <br />
&lt;url-pattern&gt;/UrlTest&lt;/url-pattern&gt; <br />
&lt;/servlet-mapping&gt; <br />
URL模式还可以包含通配符。例如，下面的小程序指示服务器发送所有以Web应用的URL前缀开始，以..asp结束的请求到名为BashMS的servlet。 <br />
&lt;servlet&gt; <br />
&lt;servlet-name&gt;BashMS&lt;/servlet-name&gt; <br />
&lt;servlet-class&gt;msUtils.ASPTranslator&lt;/servlet-class&gt; <br />
&lt;/servlet&gt; <br />
&lt;!-- ... --&gt; <br />
&lt;servlet-mapping&gt; <br />
&lt;servlet-name&gt;BashMS&lt;/servlet-name&gt; <br />
&lt;url-pattern&gt;/*.asp&lt;/url-pattern&gt; <br />
&lt;/servlet-mapping&gt; <br />
3.3 命名JSP页面 <br />
因为JSP页面要转换成sevlet，自然希望就像命名servlet一样命名JSP页面。毕竟，JSP页面可能会从初始化参数、安全设置或定制的URL中受益，正如普通的serlvet那样。虽然JSP页面的后台实际上是servlet这句话是正确的，但存在一个关键的猜疑：即，你不知道JSP页面的实际类名（因为系统自己挑选这个名字）。因此，为了命名JSP页面，可将jsp-file元素替换为servlet-calss元素，如下所示： <br />
&lt;servlet&gt; <br />
&lt;servlet-name&gt;Test&lt;/servlet-name&gt; <br />
&lt;jsp-file&gt;/TestPage.jsp&lt;/jsp-file&gt; <br />
&lt;/servlet&gt; <br />
命名JSP页面的原因与命名servlet的原因完全相同：即为了提供一个与定制设置（如，初始化参数和安全设置）一起使用的名称，并且，以便能更改激活JSP页面的URL（比方说，以便多个URL通过相同页面得以处理，或者从URL中去掉.jsp扩展名）。但是，在设置初始化参数时，应该注意，JSP页面是利用jspInit方法，而不是init方法读取初始化参数的。 <br />
例如，程序清单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）的一部分。 <br />
<br />
程序清单5-3 TestPage.jsp <br />
&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0 Transitional//EN&quot;&gt; <br />
&lt;HTML&gt; <br />
&lt;HEAD&gt; <br />
&lt;TITLE&gt; <br />
JSP Test Page <br />
&lt;/TITLE&gt; <br />
&lt;/HEAD&gt; <br />
&lt;BODY BGCOLOR=&quot;#FDF5E6&quot;&gt; <br />
&lt;H2&gt;URI: &lt;%= request.getRequestURI() %&gt;&lt;/H2&gt; <br />
&lt;/BODY&gt; <br />
&lt;/HTML&gt; <br />
<br />
<br />
程序清单5-4 web.xml（说明JSP页命名的摘录） <br />
&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt; <br />
&lt;!DOCTYPE web-app <br />
PUBLIC &quot;-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN&quot; <br />
&quot;http://java.sun.com/dtd/web-app_2_3.dtd&quot;&gt; <br />
<br />
&lt;web-app&gt; <br />
&lt;!-- ... --&gt; <br />
&lt;servlet&gt; <br />
&lt;servlet-name&gt;PageName&lt;/servlet-name&gt; <br />
&lt;jsp-file&gt;/TestPage.jsp&lt;/jsp-file&gt; <br />
&lt;/servlet&gt; <br />
&lt;!-- ... --&gt; <br />
&lt;servlet-mapping&gt; <br />
&lt;servlet-name&gt; PageName &lt;/servlet-name&gt; <br />
&lt;url-pattern&gt;/UrlTest2/*&lt;/url-pattern&gt; <br />
&lt;/servlet-mapping&gt; <br />
&lt;!-- ... --&gt; <br />
&lt;/web-app&gt; <br />
<br />
<br />
4 禁止激活器servlet <br />
<br />
对servlet或JSP页面建立定制URL的一个原因是，这样做可以注册从init（servlet）或jspInit（JSP页面）方法中读取得初始化参数。但是，初始化参数只在是利用定制URL模式或注册名访问servlet或JSP页面时可以使用，用缺省URL http://host/webAppPrefix/servlet/ServletName 访问时不能使用。因此，你可能会希望关闭缺省URL，这样就不会有人意外地调用初始化servlet了。这个过程有时称为禁止激活器servlet，因为多数服务器具有一个用缺省的servlet URL注册的标准servlet，并激活缺省的URL应用的实际servlet。 <br />
有两种禁止此缺省URL的主要方法： <br />
l 在每个Web应用中重新映射/servlet/模式。 <br />
l 全局关闭激活器servlet。 <br />
重要的是应该注意到，虽然重新映射每个Web应用中的/servlet/模式比彻底禁止激活servlet所做的工作更多，但重新映射可以用一种完全可移植的方式来完成。相反，全局禁止激活器servlet完全是针对具体机器的，事实上有的服务器（如ServletExec）没有这样的选择。下面的讨论对每个Web应用重新映射/servlet/ URL模式的策略。后面提供在Tomcat中全局禁止激活器servlet的详细内容。 <br />
4.1 重新映射/servlet/URL模式 <br />
在一个特定的Web应用中禁止以http://host/webAppPrefix/servlet/ 开始的URL的处理非常简单。所需做的事情就是建立一个错误消息servlet，并使用前一节讨论的url-pattern元素将所有匹配请求转向该servlet。只要简单地使用： <br />
&lt;url-pattern&gt;/servlet/*&lt;/url-pattern&gt; <br />
作为servlet-mapping元素中的模式即可。 <br />
例如，程序清单5-5给出了将SorryServlet servlet（程序清单5-6）与所有以http://host/webAppPrefix/servlet/ 开头的URL相关联的部署描述符文件的一部分。 <br />
<br />
程序清单5-5 web.xml（说明JSP页命名的摘录） <br />
&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt; <br />
&lt;!DOCTYPE web-app <br />
PUBLIC &quot;-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN&quot; <br />
&quot;http://java.sun.com/dtd/web-app_2_3.dtd&quot;&gt; <br />
<br />
&lt;web-app&gt; <br />
&lt;!-- ... --&gt; <br />
&lt;servlet&gt; <br />
&lt;servlet-name&gt;Sorry&lt;/servlet-name&gt; <br />
&lt;servlet-class&gt;moreservlets.SorryServlet&lt;/servlet-class&gt; <br />
&lt;/servlet&gt; <br />
&lt;!-- ... --&gt; <br />
&lt;servlet-mapping&gt; <br />
&lt;servlet-name&gt; Sorry &lt;/servlet-name&gt; <br />
&lt;url-pattern&gt;/servlet/*&lt;/url-pattern&gt; <br />
&lt;/servlet-mapping&gt; <br />
&lt;!-- ... --&gt; <br />
&lt;/web-app&gt; <br />
<br />
<br />
程序清单5-6 SorryServlet.java <br />
package moreservlets; <br />
<br />
import java.io.*; <br />
import javax.servlet.*; <br />
import javax.servlet.http.*; <br />
<br />
/** Simple servlet used to give error messages to <br />
* users who try to access default servlet URLs <br />
* (i.e., http://host/webAppPrefix/servlet/ServletName ) <br />
* in Web applications that have disabled this <br />
* behavior. <br />
* &lt;P&gt; <br />
* Taken from More Servlets and JavaServer Pages <br />
* from Prentice Hall and Sun Microsystems Press, <br />
* <a href="http://www.cndiy8.com/www.moreservlets.com/">http://www.moreservlets.com/. </a><br />
* &copy; 2002 Marty Hall; may be freely used or adapted. <br />
*/ <br />
<br />
public class SorryServlet extends HttpServlet { <br />
public void doGet(HttpServletRequest request, <br />
HttpServletResponse response) <br />
throws ServletException, IOException { <br />
response.setContentType(&quot;text/html&quot;); <br />
PrintWriter out = response.getWriter(); <br />
String title = &quot;Invoker Servlet Disabled.&quot;; <br />
out.println(ServletUtilities.headWithTitle(title) + <br />
&quot;&lt;BODY BGCOLOR=\&quot;#FDF5E6\&quot;&gt;\n&quot; + <br />
&quot;&lt;H2&gt;&quot; + title + &quot;&lt;/H2&gt;\n&quot; + <br />
&quot;Sorry, access to servlets by means of\n&quot; + <br />
&quot;URLs that begin with\n&quot; + <br />
&quot;http://host/webAppPrefix/servlet/\n&quot; + <br />
&quot;has been disabled.\n&quot; + <br />
&quot;&lt;/BODY&gt;&lt;/HTML&gt;&quot;); <br />
} <br />
<br />
public void doPost(HttpServletRequest request, <br />
HttpServletResponse response) <br />
throws ServletException, IOException { <br />
doGet(request, response); <br />
} <br />
}<br />
</p>
<p>4.2 全局禁止激活器：Tomcat <br />
Tomcat 4中用来关闭缺省URL的方法与Tomcat 3中所用的很不相同。下面介绍这两种方法： <br />
1．禁止激活器： Tomcat 4 <br />
Tomcat 4用与前面相同的方法关闭激活器servlet，即利用web.xml中的url-mapping元素进行关闭。不同之处在于Tomcat使用了放在install_dir/conf中的一个服务器专用的全局web.xml文件，而前面使用的是存放在每个Web应用的WEB-INF目录中的标准web.xml文件。 <br />
因此，为了在Tomcat 4中关闭激活器servlet，只需在install_dir/conf/web.xml中简单地注释出/servlet/* URL映射项即可，如下所示： <br />
&lt;!-- <br />
&lt;servlet-mapping&gt; <br />
&lt;servlet-name&gt;invoker&lt;/servlet-name&gt; <br />
&lt;url-pattern&gt;/servlet/*&lt;/url-pattern&gt; <br />
&lt;/servlet-mapping&gt; <br />
--&gt; <br />
再次提醒，应该注意这个项是位于存放在install_dir/conf的Tomcat专用的web.xml文件中的，此文件不是存放在每个Web应用的WEB-INF目录中的标准web.xml。 <br />
2．禁止激活器：Tomcat3 <br />
在Apache Tomcat的版本3中，通过在install_dir/conf/server.xml中注释出InvokerInterceptor项全局禁止缺省servlet URL。例如，下面是禁止使用缺省servlet URL的server.xml文件的一部分。 <br />
&lt;!-- <br />
&lt;RequsetInterceptor <br />
className=&quot;org.apache.tomcat.request.InvokerInterceptor&quot; <br />
debug=&quot;0&quot; prefix=&quot;/servlet/&quot; /&gt; <br />
--&gt; <br />
<br />
5 初始化和预装载servlet与JSP页面 <br />
<br />
这里讨论控制servlet和JSP页面的启动行为的方法。特别是，说明了怎样分配初始化参数以及怎样更改服务器生存期中装载servlet和JSP页面的时刻。 <br />
5.1 分配servlet初始化参数 <br />
利用init-param元素向servlet提供初始化参数，init-param元素具有param-name和param-value子元素。例如，在下面的例子中，如果initServlet servlet是利用它的注册名（InitTest）访问的，它将能够从其方法中调用getServletConfig().getInitParameter(&quot;param1&quot;)获得&quot;Value 1&quot;，调用getServletConfig().getInitParameter(&quot;param2&quot;)获得&quot;2&quot;。 <br />
&lt;servlet&gt; <br />
&lt;servlet-name&gt;InitTest&lt;/servlet-name&gt; <br />
&lt;servlet-class&gt;moreservlets.InitServlet&lt;/servlet-class&gt; <br />
&lt;init-param&gt; <br />
&lt;param-name&gt;param1&lt;/param-name&gt; <br />
&lt;param-value&gt;value1&lt;/param-value&gt; <br />
&lt;/init-param&gt; <br />
&lt;init-param&gt; <br />
&lt;param-name&gt;param2&lt;/param-name&gt; <br />
&lt;param-value&gt;2&lt;/param-value&gt; <br />
&lt;/init-param&gt; <br />
&lt;/servlet&gt; <br />
在涉及初始化参数时，有几点需要注意： <br />
l 返回值。GetInitParameter的返回值总是一个String。因此，在前一个例子中，可对param2使用Integer.parseInt获得一个int。 <br />
l JSP中的初始化。JSP页面使用jspInit而不是init。JSP页面还需要使用jsp-file元素代替servlet-class。 <br />
l 缺省URL。初始化参数只在通过它们的注册名或与它们注册名相关的定制URL模式访问Servlet时可以使用。因此，在这个例子中，param1和param2初始化参数将能够在使用URL http://host/webAppPrefix/servlet/InitTest 时可用，但在使用URL http://host/webAppPrefix/servlet/myPackage.InitServlet 时不能使用。 <br />
例如，程序清单5-7给出一个名为InitServlet的简单servlet，它使用init方法设置firstName和emailAddress字段。程序清单5-8给出分配名称InitTest给servlet的web.xml文件。 <br />
程序清单5-7 InitServlet.java <br />
package moreservlets; <br />
<br />
import java.io.*; <br />
import javax.servlet.*; <br />
import javax.servlet.http.*; <br />
<br />
/** Simple servlet used to illustrate servlet <br />
* initialization parameters. <br />
* &lt;P&gt; <br />
* Taken from More Servlets and JavaServer Pages <br />
* from Prentice Hall and Sun Microsystems Press, <br />
* <a href="http://www.cndiy8.com/www.moreservlets.com/">http://www.moreservlets.com/. </a><br />
* &copy; 2002 Marty Hall; may be freely used or adapted. <br />
*/ <br />
<br />
public class InitServlet extends HttpServlet { <br />
private String firstName, emailAddress; <br />
<br />
public void init() { <br />
ServletConfig config = getServletConfig(); <br />
firstName = config.getInitParameter(&quot;firstName&quot;); <br />
emailAddress = config.getInitParameter(&quot;emailAddress&quot;); <br />
} <br />
<br />
public void doGet(HttpServletRequest request, <br />
HttpServletResponse response) <br />
throws ServletException, IOException { <br />
response.setContentType(&quot;text/html&quot;); <br />
PrintWriter out = response.getWriter(); <br />
String uri = request.getRequestURI(); <br />
out.println(ServletUtilities.headWithTitle(&quot;Init Servlet&quot;) + <br />
&quot;&lt;BODY BGCOLOR=\&quot;#FDF5E6\&quot;&gt;\n&quot; + <br />
&quot;&lt;H2&gt;Init Parameters:&lt;/H2&gt;\n&quot; + <br />
&quot;&lt;UL&gt;\n&quot; + <br />
&quot;&lt;LI&gt;First name: &quot; + firstName + &quot;\n&quot; + <br />
&quot;&lt;LI&gt;Email address: &quot; + emailAddress + &quot;\n&quot; + <br />
&quot;&lt;/UL&gt;\n&quot; + <br />
&quot;&lt;/BODY&gt;&lt;/HTML&gt;&quot;); <br />
} <br />
} <br />
<br />
<br />
程序清单5-8 web.xml（说明初始化参数的摘录） <br />
&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt; <br />
&lt;!DOCTYPE web-app <br />
PUBLIC &quot;-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN&quot; <br />
&quot;http://java.sun.com/dtd/web-app_2_3.dtd&quot;&gt; <br />
<br />
&lt;web-app&gt; <br />
&lt;!-- ... --&gt; <br />
&lt;servlet&gt; <br />
&lt;servlet-name&gt;InitTest&lt;/servlet-name&gt; <br />
&lt;servlet-class&gt;moreservlets.InitServlet&lt;/servlet-class&gt; <br />
&lt;init-param&gt; <br />
&lt;param-name&gt;firstName&lt;/param-name&gt; <br />
&lt;param-value&gt;Larry&lt;/param-value&gt; <br />
&lt;/init-param&gt; <br />
&lt;init-param&gt; <br />
&lt;param-name&gt;emailAddress&lt;/param-name&gt; <br />
&lt;param-value&gt;Ellison@Microsoft.com&lt;/param-value&gt; <br />
&lt;/init-param&gt; <br />
&lt;/servlet&gt; <br />
&lt;!-- ... --&gt; <br />
&lt;/web-app&gt; <br />
<br />
5.2 分配JSP初始化参数 <br />
给JSP页面提供初始化参数在三个方面不同于给servlet提供初始化参数。 <br />
1）使用jsp-file而不是servlet-class。因此，WEB-INF/web.xml文件的servlet元素如下所示： <br />
&lt;servlet&gt; <br />
&lt;servlet-name&gt;PageName&lt;/servlet-name&gt; <br />
&lt;jsp-file&gt;/RealPage.jsp&lt;/jsp-file&gt; <br />
&lt;init-param&gt; <br />
&lt;param-name&gt;...&lt;/param-name&gt; <br />
&lt;param-value&gt;...&lt;/param-value&gt; <br />
&lt;/init-param&gt; <br />
... <br />
&lt;/servlet&gt; <br />
2)几乎总是分配一个明确的URL模式。对servlet，一般相应地使用以http://host/webAppPrefix/servlet/ 开始的缺省URL。只需记住，使用注册名而不是原名称即可。这对于JSP页面在技术上也是合法的。例如，在上面给出的例子中，可用URL <a href="http://www.cndiy8.com/host/webAppPrefix/servlet/PageName">http://host/webAppPrefix/servlet/PageName </a>访问RealPage.jsp的对初始化参数具有访问权的版本。但在用于JSP页面时，许多用户似乎不喜欢应用常规的servlet的URL。此外，如果JSP页面位于服务器为其提供了目录清单的目录中（如，一个既没有index.html也没有index.jsp文件的目录），则用户可能会连接到此JSP页面，单击它，从而意外地激活未初始化的页面。因此，好的办法是使用url-pattern（5.3节）将JSP页面的原URL与注册的servlet名相关联。这样，客户机可使用JSP页面的普通名称，但仍然激活定制的版本。例如，给定来自项目1的servlet定义，可使用下面的servlet-mapping定义： <br />
&lt;servlet-mapping&gt; <br />
&lt;servlet-name&gt;PageName&lt;/servlet-name&gt; <br />
&lt;url-pattern&gt;/RealPage.jsp&lt;/url-pattern&gt; <br />
&lt;/servlet-mapping&gt; <br />
3）JSP页使用jspInit而不是init。自动从JSP页面建立的servlet或许已经使用了inti方法。因此，使用JSP声明提供一个init方法是不合法的，必须制定jspInit方法。 <br />
为了说明初始化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相关联。 <br />
<br />
程序清单5-9 InitPage.jsp <br />
&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0 Transitional//EN&quot;&gt; <br />
&lt;HTML&gt; <br />
&lt;HEAD&gt;&lt;TITLE&gt;JSP Init Test&lt;/TITLE&gt;&lt;/HEAD&gt; <br />
&lt;BODY BGCOLOR=&quot;#FDF5E6&quot;&gt; <br />
&lt;H2&gt;Init Parameters:&lt;/H2&gt; <br />
&lt;UL&gt; <br />
&lt;LI&gt;First name: &lt;%= firstName %&gt; <br />
&lt;LI&gt;Email address: &lt;%= emailAddress %&gt; <br />
&lt;/UL&gt; <br />
&lt;/BODY&gt;&lt;/HTML&gt; <br />
&lt;%! <br />
private String firstName, emailAddress; <br />
<br />
public void jspInit() { <br />
ServletConfig config = getServletConfig(); <br />
firstName = config.getInitParameter(&quot;firstName&quot;); <br />
emailAddress = config.getInitParameter(&quot;emailAddress&quot;); <br />
} <br />
%&gt; <br />
<br />
<br />
程序清单5-10 web.xml（说明JSP页面的init参数的摘录） <br />
&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt; <br />
&lt;!DOCTYPE web-app <br />
PUBLIC &quot;-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN&quot; <br />
&quot;http://java.sun.com/dtd/web-app_2_3.dtd&quot;&gt; <br />
<br />
&lt;web-app&gt; <br />
&lt;!-- ... --&gt; <br />
&lt;servlet&gt; <br />
&lt;servlet-name&gt;InitPage&lt;/servlet-name&gt; <br />
&lt;jsp-file&gt;/InitPage.jsp&lt;/jsp-file&gt; <br />
&lt;init-param&gt; <br />
&lt;param-name&gt;firstName&lt;/param-name&gt; <br />
&lt;param-value&gt;Bill&lt;/param-value&gt; <br />
&lt;/init-param&gt; <br />
&lt;init-param&gt; <br />
&lt;param-name&gt;emailAddress&lt;/param-name&gt; <br />
&lt;param-value&gt;gates@oracle.com&lt;/param-value&gt; <br />
&lt;/init-param&gt; <br />
&lt;/servlet&gt; <br />
&lt;!-- ... --&gt; <br />
&lt;servlet-mapping&gt; <br />
&lt;servlet-name&gt; InitPage&lt;/servlet-name&gt; <br />
&lt;url-pattern&gt;/InitPage.jsp&lt;/url-pattern&gt; <br />
&lt;/servlet-mapping&gt; <br />
&lt;!-- ... --&gt; <br />
&lt;/web-app&gt; </p>
<p>5.3 提供应用范围内的初始化参数 <br />
一般，对单个地servlet或JSP页面分配初始化参数。指定的servlet或JSP页面利用ServletConfig的getInitParameter方法读取这些参数。但是，在某些情形下，希望提供可由任意servlet或JSP页面借助ServletContext的getInitParameter方法读取的系统范围内的初始化参数。 <br />
可利用context-param元素声明这些系统范围内的初始化值。context-param元素应该包含param-name、param-value以及可选的description子元素，如下所示： <br />
&lt;context-param&gt; <br />
&lt;param-name&gt;support-email&lt;/param-name&gt; <br />
&lt;param-value&gt;blackhole@mycompany.com&lt;/param-value&gt; <br />
&lt;/context-param&gt; <br />
可回忆一下，为了保证可移植性，web.xml内的元素必须以正确的次序声明。但这里应该注意，context-param元素必须出现任意与文档有关的元素（icon、display-name或description）之后及filter、filter-mapping、listener或servlet元素之前。 <br />
5.4 在服务器启动时装载servlet <br />
假如servlet或JSP页面有一个要花很长时间执行的init（servlet）或jspInit（JSP）方法。例如，假如init或jspInit方法从某个数据库或ResourceBundle查找产量。这种情况下，在第一个客户机请求时装载servlet的缺省行为将对第一个客户机产生较长时间的延迟。因此，可利用servlet的load-on-startup元素规定服务器在第一次启动时装载servlet。下面是一个例子。 <br />
&lt;servlet&gt; <br />
&lt;servlet-name&gt; &hellip; &lt;/servlet-name&gt; <br />
&lt;servlet-class&gt; &hellip; &lt;/servlet-class&gt; &lt;!-- Or jsp-file --&gt; <br />
&lt;load-on-startup/&gt; <br />
&lt;/servlet&gt; <br />
可以为此元素体提供一个整数而不是使用一个空的load-on-startup。想法是服务器应该在装载较大数目的servlet或JSP页面之前装载较少数目的servlet或JSP页面。例如，下面的servlet项（放置在Web应用的WEB-INF目录下的web.xml文件中的web-app元素内）将指示服务器首先装载和初始化SearchServlet，然后装载和初始化由位于Web应用的result目录中的index.jsp文件产生的servlet。 <br />
&lt;servlet&gt; <br />
&lt;servlet-name&gt;Search&lt;/servlet-name&gt; <br />
&lt;servlet-class&gt;myPackage.SearchServlet&lt;/servlet-class&gt; &lt;!-- Or jsp-file --&gt; <br />
&lt;load-on-startup&gt;1&lt;/load-on-startup&gt; <br />
&lt;/servlet&gt; <br />
&lt;servlet&gt; <br />
&lt;servlet-name&gt;Results&lt;/servlet-name&gt; <br />
&lt;servlet-class&gt;/results/index.jsp&lt;/servlet-class&gt; &lt;!-- Or jsp-file --&gt; <br />
&lt;load-on-startup&gt;2&lt;/load-on-startup&gt; <br />
&lt;/servlet&gt; </p>
<p>6 声明过滤器 </p>
<p>servlet版本2.3引入了过滤器的概念。虽然所有支持servlet API版本2.3的服务器都支持过滤器，但为了使用与过滤器有关的元素，必须在web.xml中使用版本2.3的DTD。 <br />
过滤器可截取和修改进入一个servlet或JSP页面的请求或从一个servlet或JSP页面发出的相应。在执行一个servlet或JSP页面之前，必须执行第一个相关的过滤器的doFilter方法。在该过滤器对其FilterChain对象调用doFilter时，执行链中的下一个过滤器。如果没有其他过滤器，servlet或JSP页面被执行。过滤器具有对到来的ServletRequest对象的全部访问权，因此，它们可以查看客户机名、查找到来的cookie等。为了访问servlet或JSP页面的输出，过滤器可将响应对象包裹在一个替身对象（stand-in object）中，比方说把输出累加到一个缓冲区。在调用FilterChain对象的doFilter方法之后，过滤器可检查缓冲区，如有必要，就对它进行修改，然后传送到客户机。 <br />
例如，程序清单5-11帝国难以了一个简单的过滤器，只要访问相关的servlet或JSP页面，它就截取请求并在标准输出上打印一个报告（开发过程中在桌面系统上运行时，大多数服务器都可以使用这个过滤器）。 </p>
<p>程序清单5-11 ReportFilter.java <br />
package moreservlets; </p>
<p>import java.io.*; <br />
import javax.servlet.*; <br />
import javax.servlet.http.*; <br />
import java.util.*; </p>
<p>/** Simple filter that prints a report on the standard output <br />
* whenever the associated servlet or JSP page is accessed. <br />
* &lt;P&gt; <br />
* Taken from More Servlets and JavaServer Pages <br />
* from Prentice Hall and Sun Microsystems Press, <br />
* http://www.moreservlets.com/. <br />
* &copy; 2002 Marty Hall; may be freely used or adapted. <br />
*/ </p>
<p>public class ReportFilter implements Filter { <br />
public void doFilter(ServletRequest request, <br />
ServletResponse response, <br />
FilterChain chain) <br />
throws ServletException, IOException { <br />
HttpServletRequest req = (HttpServletRequest)request; <br />
System.out.println(req.getRemoteHost() + <br />
&quot; tried to access &quot; + <br />
req.getRequestURL() + <br />
&quot; on &quot; + new Date() + &quot;.&quot;); <br />
chain.doFilter(request,response); <br />
} </p>
<p>public void init(FilterConfig config) <br />
throws ServletException { <br />
} </p>
<p>public void destroy() {} <br />
} </p>
<p>一旦建立了一个过滤器，可以在web.xml中利用filter元素以及filter-name（任意名称）、file-class（完全限定的类名）和（可选的）init-params子元素声明它。请注意，元素在web.xml的web-app元素中出现的次序不是任意的；允许服务器（但不是必需的）强制所需的次序，并且实际中有些服务器也是这样做的。但这里要注意，所有filter元素必须出现在任意filter-mapping元素之前，filter-mapping元素又必须出现在所有servlet或servlet-mapping元素之前。 <br />
例如，给定上述的ReportFilter类，可在web.xml中作出下面的filter声明。它把名称Reporter与实际的类ReportFilter（位于moreservlets程序包中）相关联。 <br />
&lt;filter&gt; <br />
&lt;filter-name&gt;Reporter&lt;/filter-name&gt; <br />
&lt;filter-class&gt;moresevlets.ReportFilter&lt;/filter-class&gt; <br />
&lt;/filter&gt; <br />
一旦命名了一个过滤器，可利用filter-mapping元素把它与一个或多个servlet或JSP页面相关联。关于此项工作有两种选择。 <br />
首先，可使用filter-name和servlet-name子元素把此过滤器与一个特定的servlet名（此servlet名必须稍后在相同的web.xml文件中使用servlet元素声明）关联。例如，下面的程序片断指示系统只要利用一个定制的URL访问名为SomeServletName的servlet或JSP页面，就运行名为Reporter的过滤器。 <br />
&lt;filter-mapping&gt; <br />
&lt;filter-name&gt;Reporter&lt;/filter-name&gt; <br />
&lt;servlet-name&gt;SomeServletName&lt;/servlet-name&gt; <br />
&lt;/filter-mapping&gt; <br />
其次，可利用filter-name和url-pattern子元素将过滤器与一组servlet、JSP页面或静态内容相关联。例如，相面的程序片段指示系统只要访问Web应用中的任意URL，就运行名为Reporter的过滤器。 <br />
&lt;filter-mapping&gt; <br />
&lt;filter-name&gt;Reporter&lt;/filter-name&gt; <br />
&lt;url-pattern&gt;/*&lt;/url-pattern&gt; <br />
&lt;/filter-mapping&gt; <br />
例如，程序清单5-12给出了将ReportFilter过滤器与名为PageName的servlet相关联的web.xml文件的一部分。名字PageName依次又与一个名为TestPage.jsp的JSP页面以及以模式http://host/webAppPrefix/UrlTest2/ 开头的URL相关联。TestPage.jsp的源代码已经JSP页面命名的谈论在前面的3节&quot;分配名称和定制的URL&quot;中给出。事实上，程序清单5-12中的servlet和servlet-name项从该节原封不动地拿过来的。给定这些web.xml项，可看到下面的标准输出形式的调试报告（换行是为了容易阅读）。 <br />
audit.irs.gov tried to access <br />
<a href="http://mycompany.com/deployDemo/UrlTest2/business/tax-plan.html" target="_blank">http://mycompany.com/deployDemo/UrlTest2/business/tax-plan.html</a> <br />
on Tue Dec 25 13:12:29 EDT 2001. </p>
<p>程序清单5-12 Web.xml（说明filter用法的摘录） <br />
&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt; <br />
&lt;!DOCTYPE web-app <br />
PUBLIC &quot;-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN&quot; <br />
&quot;http://java.sun.com/dtd/web-app_2_3.dtd&quot;&gt; </p>
<p>&lt;web-app&gt; <br />
&lt;filter&gt; <br />
&lt;filter-name&gt;Reporter&lt;/filter-name&gt; <br />
&lt;filter-class&gt;moresevlets.ReportFilter&lt;/filter-class&gt; <br />
&lt;/filter&gt; <br />
&lt;!-- ... --&gt; <br />
&lt;filter-mapping&gt; <br />
&lt;filter-name&gt;Reporter&lt;/filter-name&gt; <br />
&lt;servlet-name&gt;PageName&lt;/servlet-name&gt; <br />
&lt;/filter-mapping&gt; <br />
&lt;!-- ... --&gt; <br />
&lt;servlet&gt; <br />
&lt;servlet-name&gt;PageName&lt;/servlet-name&gt; <br />
&lt;jsp-file&gt;/RealPage.jsp&lt;/jsp-file&gt; <br />
&lt;/servlet&gt; <br />
&lt;!-- ... --&gt; <br />
&lt;servlet-mapping&gt; <br />
&lt;servlet-name&gt; PageName &lt;/servlet-name&gt; <br />
&lt;url-pattern&gt;/UrlTest2/*&lt;/url-pattern&gt; <br />
&lt;/servlet-mapping&gt; <br />
&lt;!-- ... --&gt; <br />
&lt;/web-app&gt; <br />
</p>
<p>7 指定欢迎页 </p>
<p>假如用户提供了一个像http://host/webAppPrefix/directoryName/ 这样的包含一个目录名但没有包含文件名的URL，会发生什么事情呢？用户能得到一个目录表？一个错误？还是标准文件的内容？如果得到标准文件内容，是index.html、index.jsp、default.html、default.htm或别的什么东西呢？ <br />
Welcome-file-list元素及其辅助的welcome-file元素解决了这个模糊的问题。例如，下面的web.xml项指出，如果一个URL给出一个目录名但未给出文件名，服务器应该首先试用index.jsp，然后再试用index.html。如果两者都没有找到，则结果有赖于所用的服务器（如一个目录列表）。 <br />
&lt;welcome-file-list&gt; <br />
&lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt; <br />
&lt;welcome-file&gt;index.html&lt;/welcome-file&gt; <br />
&lt;/welcome-file-list&gt; <br />
虽然许多服务器缺省遵循这种行为，但不一定必须这样。因此，明确地使用welcom-file-list保证可移植性是一种良好的习惯。 </p>
<p>&nbsp;</p>
<p>8 指定处理错误的页面 </p>
<p>现在我了解到，你在开发servlet和JSP页面时从不会犯错误，而且你的所有页面是那样的清晰，一般的程序员都不会被它们的搞糊涂。但是，是人总会犯错误的，用户可能会提供不合规定的参数，使用不正确的URL或者不能提供必需的表单字段值。除此之外，其它开发人员可能不那么细心，他们应该有些工具来克服自己的不足。 <br />
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。 <br />
可回忆一下，在web.xml内以正确的次序声明web-app的子元素很重要。这里只要记住，error-page出现在web.xml文件的末尾附近，servlet、servlet-name和welcome-file-list之后即可。 </p>
<p>8.1 error-code元素 <br />
为了更好地了解error-code元素的值，可考虑一下如果不正确地输入文件名，大多数站点会作出什么反映。这样做一般会出现一个404错误信息，它表示不能找到该文件，但几乎没提供更多有用的信息。另一方面，可以试一下在www.microsoft.com、www.ibm.com 处或者特别是在www.bea.com 处输出未知的文件名。这是会得出有用的消息，这些消息提供可选择的位置，以便查找感兴趣的页面。提供这样有用的错误页面对于Web应用来说是很有价值得。事实上rm-error-page子元素）。由form-login-page给出的HTML表单必须具有一个j_security_check的ACTION属性、一个名为j_username的用户名文本字段以及一个名为j_password的口令字段。 <br />
例如，程序清单5-19指示服务器使用基于表单的验证。Web应用的顶层目录中的一个名为login.jsp的页面将收集用户名和口令，并且失败的登陆将由相同目录中名为login-error.jsp的页面报告。 </p>
<p>程序清单5-19 web.xml（说明login-config的摘录） <br />
&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt; <br />
&lt;!DOCTYPE web-app <br />
PUBLIC &quot;-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN&quot; <br />
&quot;http://java.sun.com/dtd/web-app_2_3.dtd&quot;&gt; </p>
<p>&lt;web-app&gt; <br />
&lt;!-- ... --&gt; <br />
&lt;security-constraint&gt; ... &lt;/security-constraint&gt; <br />
&lt;login-config&gt; <br />
&lt;auth-method&gt; FORM &lt;/auth-method&gt; <br />
&lt;form-login-config&gt; <br />
&lt;form-login-page&gt;/login.jsp&lt;/form-login-page&gt; <br />
&lt;form-error-page&gt;/login-error.jsp&lt;/form-error-page&gt; <br />
&lt;/form-login-config&gt; <br />
&lt;/login-config&gt; <br />
&lt;!-- ... --&gt; <br />
&lt;/web-app&gt; <br />
</p>
<p>9.2 限制对Web资源的访问 <br />
现在，可以指示服务器使用何种验证方法了。&quot;了不起，&quot;你说道，&quot;除非我能指定一个来收到保护的URL，否则没有多大用处。&quot;没错。指出这些URL并说明他们应该得到何种保护正是security-constriaint元素的用途。此元素在web.xml中应该出现在login-config的紧前面。它包含是个可能的子元素，分别是：web-resource-collection、auth-constraint、user-data-constraint和display-name。下面各小节对它们进行介绍。 <br />
l web-resource-collection <br />
此元素确定应该保护的资源。所有security-constraint元素都必须包含至少一个web-resource-collection项。此元素由一个给出任意标识名称的web-resource-name元素、一个确定应该保护的URL的url-pattern元素、一个指出此保护所适用的HTTP命令（GET、POST等，缺省为所有方法）的http-method元素和一个提供资料的可选description元素组成。例如，下面的Web-resource-collection项（在security-constratint元素内）指出Web应用的proprietary目录中所有文档应该受到保护。 <br />
&lt;security-constraint&gt; <br />
&lt;web-resource-coolection&gt; <br />
&lt;web-resource-name&gt;Proprietary&lt;/web-resource-name&gt; <br />
&lt;url-pattern&gt;/propritary/*&lt;/url-pattern&gt; <br />
&lt;/web-resource-coolection&gt; <br />
&lt;!-- ... --&gt; <br />
&lt;/security-constraint&gt; <br />
重要的是应该注意到，url-pattern仅适用于直接访问这些资源的客户机。特别是，它不适合于通过MVC体系结构利用RequestDispatcher来访问的页面，或者不适合于利用类似jsp:forward的手段来访问的页面。这种不匀称如果利用得当的话很有好处。例如，servlet可利用MVC体系结构查找数据，把它放到bean中，发送请求到从bean中提取数据的JSP页面并显示它。我们希望保证决不直接访问受保护的JSP页面，而只是通过建立该页面将使用的bean的servlet来访问它。url-pattern和auth-contraint元素可通过声明不允许任何用户直接访问JSP页面来提供这种保证。但是，这种不匀称的行为可能让开发人员放松警惕，使他们偶然对应受保护的资源提供不受限制的访问。 <br />
l auth-constraint <br />
尽管web-resource-collention元素质出了哪些URL应该受到保护，但是auth-constraint元素却指出哪些用户应该具有受保护资源的访问权。此元素应该包含一个或多个标识具有访问权限的用户类别role-name元素，以及包含（可选）一个描述角色的description元素。例如，下面web.xml中的security-constraint元素部门规定只有指定为Administrator或Big Kahuna（或两者）的用户具有指定资源的访问权。 <br />
&lt;security-constraint&gt; <br />
&lt;web-resource-coolection&gt; ... &lt;/web-resource-coolection&gt; <br />
&lt;auth-constraint&gt; <br />
&lt;role-name&gt;administrator&lt;/role-name&gt; <br />
&lt;role-name&gt;kahuna&lt;/role-name&gt; <br />
&lt;/auth-constraint&gt; <br />
&lt;/security-constraint&gt; <br />
重要的是认识到，到此为止，这个过程的可移植部分结束了。服务器怎样确定哪些用户处于任何角色以及它怎样存放用户的口令，完全有赖于具体的系统。 <br />
例如，Tomcat使用install_dir/conf/tomcat-users.xml将用户名与角色名和口令相关联，正如下面例子中所示，它指出用户joe（口令bigshot）和jane（口令enaj）属于administrator和kahuna角色。 <br />
&lt;tomcat-users&gt; <br />
&lt;user name=&quot;joe&quot; password=&quot;bigshot&quot; roles=&quot;administrator,kahuna&quot; /&gt; <br />
&lt;user name=&quot;jane&quot; password=&quot;enaj&quot; roles=&quot;kahuna&quot; /&gt; <br />
&lt;/tomcat-users&gt; <br />
l user-data-constraint <br />
这个可选的元素指出在访问相关资源时使用任何传输层保护。它必须包含一个transport-guarantee子元素（合法值为NONE、INTEGRAL或CONFIDENTIAL），并且可选地包含一个description元素。transport-guarantee为NONE值将对所用的通讯协议不加限制。INTEGRAL值表示数据必须以一种防止截取它的人阅读它的方式传送。虽然原理上（并且在未来的HTTP版本中），在INTEGRAL和CONFIDENTIAL之间可能会有差别，但在当前实践中，他们都只是简单地要求用SSL。例如，下面指示服务器只允许对相关资源做HTTPS连接： <br />
&lt;security-constraint&gt; <br />
&lt;!-- ... --&gt; <br />
&lt;user-data-constraint&gt; <br />
&lt;transport-guarantee&gt;CONFIDENTIAL&lt;/transport-guarantee&gt; <br />
&lt;/user-data-constraint&gt; <br />
&lt;/security-constraint&gt; <br />
l display-name <br />
security-constraint的这个很少使用的子元素给予可能由GUI工具使用的安全约束项一个名称。 <br />
9.3 分配角色名 <br />
迄今为止，讨论已经集中到完全由容器（服务器）处理的安全问题之上了。但servlet以及JSP页面也能够处理它们自己的安全问题。 <br />
例如，容器可能允许用户从bigwig或bigcheese角色访问一个显示主管人员额外紧贴的页面，但只允许bigwig用户修改此页面的参数。完成这种更细致的控制的一种常见方法是调用HttpServletRequset的isUserInRole方法，并据此修改访问。 <br />
Servlet的security-role-ref子元素提供出现在服务器专用口令文件中的安全角色名的一个别名。例如，假如编写了一个调用request.isUserInRole（&quot;boss&quot;）的servlet，但后来该servlet被用在了一个其口令文件调用角色manager而不是boss的服务器中。下面的程序段使该servlet能够使用这两个名称中的任何一个。 <br />
&lt;servlet&gt; <br />
&lt;!-- ... --&gt; <br />
&lt;security-role-ref&gt; <br />
&lt;role-name&gt;boss&lt;/role-name&gt; &lt;!-- New alias --&gt; <br />
&lt;role-link&gt;manager&lt;/role-link&gt; &lt;!-- Real name --&gt; <br />
&lt;/security-role-ref&gt; <br />
&lt;/servlet&gt; <br />
也可以在web-app内利用security-role元素提供将出现在role-name元素中的所有安全角色的一个全局列表。分别地生命角色使高级IDE容易处理安全信息。 </p>
<p>10 控制会话超时 </p>
<p>如果某个会话在一定的时间内未被访问，服务器可把它扔掉以节约内存。可利用HttpSession的setMaxInactiveInterval方法直接设置个别会话对象的超时值。如果不采用这种方法，则缺省的超时值由具体的服务器决定。但可利用session-config和session-timeout元素来给出一个适用于所有服务器的明确的超时值。超时值的单位为分钟，因此，下面的例子设置缺省会话超时值为三个小时（180分钟）。 <br />
&lt;session-config&gt; <br />
&lt;session-timeout&gt;180&lt;/session-timeout&gt; <br />
&lt;/session-config&gt; </p>
<p>11 Web应用的文档化 </p>
<p>越来越多的开发环境开始提供servlet和JSP的直接支持。例子有Borland Jbuilder Enterprise Edition、Macromedia UltraDev、Allaire JRun Studio（写此文时，已被Macromedia收购）以及IBM VisuaAge for Java等。 <br />
大量的web.xml元素不仅是为服务器设计的，而且还是为可视开发环境设计的。它们包括icon、display-name和discription等。 <br />
可回忆一下，在web.xml内以适当地次序声明web-app子元素很重要。不过，这里只要记住icon、display-name和description是web.xml的web-app元素内的前三个合法元素即可。 <br />
l icon <br />
icon元素指出GUI工具可用来代表Web应用的一个和两个图像文件。可利用small-icon元素指定一幅16 x 16的GIF或JPEG图像，用large-icon元素指定一幅32 x 32的图像。下面举一个例子： <br />
&lt;icon&gt; <br />
&lt;small-icon&gt;/images/small-book.gif&lt;/small-icon&gt; <br />
&lt;large-icon&gt;/images/tome.jpg&lt;/large-icon&gt; <br />
&lt;/icon&gt; <br />
l display-name <br />
display-name元素提供GUI工具可能会用来标记此Web应用的一个名称。下面是个例子。 <br />
&lt;display-name&gt;Rare Books&lt;/display-name&gt; <br />
l description <br />
description元素提供解释性文本，如下所示： <br />
&lt;description&gt; <br />
This Web application represents the store developed for <br />
rare-books.com, an online bookstore specializing in rare <br />
and limited-edition books. <br />
&lt;/description&gt; </p>
<p>12 关联文件与MIME类型 </p>
<p>服务器一般都具有一种让Web站点管理员将文件扩展名与媒体相关联的方法。例如，将会自动给予名为mom.jpg的文件一个image/jpeg的MIME类型。但是，假如你的Web应用具有几个不寻常的文件，你希望保证它们在发送到客户机时分配为某种MIME类型。mime-mapping元素（具有extension和mime-type子元素）可提供这种保证。例如，下面的代码指示服务器将application/x-fubar的MIME类型分配给所有以.foo结尾的文件。 <br />
&lt;mime-mapping&gt; <br />
&lt;extension&gt;foo&lt;/extension&gt; <br />
&lt;mime-type&gt;application/x-fubar&lt;/mime-type&gt; <br />
&lt;/mime-mapping&gt; <br />
或许，你的Web应用希望重载（override）标准的映射。例如，下面的代码将告诉服务器在发送到客户机时指定.ps文件作为纯文本（text/plain）而不是作为PostScript（application/postscript）。 <br />
&lt;mime-mapping&gt; <br />
&lt;extension&gt;ps&lt;/extension&gt; <br />
&lt;mime-type&gt;application/postscript&lt;/mime-type&gt; <br />
&lt;/mime-mapping&gt; <br />
</p>
<p>13 定位TLD </p>
<p>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元素内包含下列内容。 <br />
&lt;taglib&gt; <br />
&lt;taglib-uri&gt;/charts.tld&lt;/taglib-uri&gt; <br />
&lt;taglib-location&gt; <br />
/WEB-INF/tlds/chart-tags-1.3beta.tld <br />
&lt;/taglib-location&gt; <br />
&lt;/taglib&gt; <br />
给出这个说明后，JSP页面可通过下面的简化形式使用标签库。 <br />
&lt;%@ taglib uri=&quot;/charts.tld&quot; prefix=&quot;somePrefix&quot; %&gt; </p>
<p>14 指定应用事件监听程序 </p>
<p>应用事件监听器程序是建立或修改servlet环境或会话对象时通知的类。它们是servlet规范的版本2.3中的新内容。这里只简单地说明用来向Web应用注册一个监听程序的web.xml的用法。 <br />
注册一个监听程序涉及在web.xml的web-app元素内放置一个listener元素。在listener元素内，listener-class元素列出监听程序的完整的限定类名，如下所示： <br />
&lt;listener&gt; <br />
&lt;listener-class&gt;package.ListenerClass&lt;/listener-class&gt; <br />
&lt;/listener&gt; <br />
虽然listener元素的结构很简单，但请不要忘记，必须正确地给出web-app元素内的子元素的次序。listener元素位于所有的servlet元素之前以及所有filter-mapping元素之后。此外，因为应用生存期监听程序是serlvet规范的2.3版本中的新内容，所以必须使用web.xml DTD的2.3版本，而不是2.2版本。 <br />
例如，程序清单5-20给出一个名为ContextReporter的简单的监听程序，只要Web应用的Servlet-Context建立（如装载Web应用）或消除（如服务器关闭）时，它就在标准输出上显示一条消息。程序清单5-21给出此监听程序注册所需要的web.xml文件的一部分。 </p>
<p>程序清单5-20 ContextReporterjava <br />
package moreservlets; </p>
<p>import javax.servlet.*; <br />
import java.util.*; </p>
<p>/** Simple listener that prints a report on the standard output <br />
* when the ServletContext is created or destroyed. <br />
* &lt;P&gt; <br />
* Taken from More Servlets and JavaServer Pages <br />
* from Prentice Hall and Sun Microsystems Press, <br />
* http://www.moreservlets.com/. <br />
* &copy; 2002 Marty Hall; may be freely used or adapted. <br />
*/ </p>
<p>public class ContextReporter implements ServletContextListener { <br />
public void contextInitialized(ServletContextEvent event) { <br />
System.out.println(&quot;Context created on &quot; + <br />
new Date() + &quot;.&quot;); <br />
} </p>
<p>public void contextDestroyed(ServletContextEvent event) { <br />
System.out.println(&quot;Context destroyed on &quot; + <br />
new Date() + &quot;.&quot;); <br />
} <br />
} <br />
</p>
<p>程序清单5-21 web.xml（声明一个监听程序的摘录） <br />
&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt; <br />
&lt;!DOCTYPE web-app <br />
PUBLIC &quot;-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN&quot; <br />
&quot;http://java.sun.com/dtd/web-app_2_3.dtd&quot;&gt; </p>
<p>&lt;web-app&gt; <br />
&lt;!-- ... --&gt; <br />
&lt;filter-mapping&gt; &hellip; &lt;/filter-mapping&gt; <br />
&lt;listener&gt; <br />
&lt;listener-class&gt;package.ListenerClass&lt;/listener-class&gt; <br />
&lt;/listener&gt; <br />
&lt;servlet&gt; ... &lt;/servlet&gt; <br />
&lt;!-- ... --&gt; <br />
&lt;/web-app&gt; <br />
</p>
<p>15 J2EE元素 </p>
<p>本节描述用作J2EE环境组成部分的Web应用的web.xml元素。这里将提供一个简明的介绍，详细内容可以参阅http://java.sun.com/j2ee/j2ee-1_3-fr-spec.pdf的Java 2 Plantform Enterprise Edition版本1.3规范的第5章。 <br />
l distributable <br />
distributable元素指出，Web应用是以这样的方式编程的：即，支持集群的服务器可安全地在多个服务器上分布Web应用。例如，一个可分布的应用必须只使用Serializable对象作为其HttpSession对象的属性，而且必须避免用实例变量（字段）来实现持续性。distributable元素直接出现在discription元素之后，并且不包含子元素或数据，它只是一个如下的标志。 <br />
&lt;distributable /&gt; <br />
l resource-env-ref <br />
resource-env-ref元素声明一个与某个资源有关的管理对象。此元素由一个可选的description元素、一个resource-env-ref-name元素（一个相对于java:comp/env环境的JNDI名）以及一个resource-env-type元素（指定资源类型的完全限定的类），如下所示： <br />
&lt;resource-env-ref&gt; <br />
&lt;resource-env-ref-name&gt; <br />
jms/StockQueue <br />
&lt;/resource-env-ref-name&gt; <br />
&lt;resource-env-ref-type&gt; <br />
javax.jms.Queue <br />
&lt;/resource-env-ref-type&gt; <br />
&lt;/resource-env-ref&gt; <br />
l env-entry <br />
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等）组成。下面是一个例子： <br />
&lt;env-entry&gt; <br />
&lt;env-entry-name&gt;minAmout&lt;/env-entry-name&gt; <br />
&lt;env-entry-value&gt;100.00&lt;/env-entry-value&gt; <br />
&lt;env-entry-type&gt;minAmout&lt;/env-entry-type&gt; <br />
&lt;/env-entry&gt; <br />
l ejb-ref <br />
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的名称）组成。 <br />
l ejb-local-ref <br />
ejb-local-ref元素声明一个EJB的本地主目录的引用。除了用local-home代替home外，此元素具有与ejb-ref元素相同的属性并以相同的方式使用。</p>
          <br/>
          <span style="color:red;">
            <a href="http://41897179.javaeye.com/blog/124898#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/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/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></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 18 Sep 2007 10:14:34 +0800</pubDate>
        <link>http://41897179.javaeye.com/blog/124898</link>
        <guid>http://41897179.javaeye.com/blog/124898</guid>
      </item>
  </channel>
</rss>