<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>我心沉浮</title>
    <description></description>
    <link>http://xiaofeng.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>发现一个很有新意的壁纸站</title>
        <author>hilliate</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://xiaofeng.javaeye.com">hilliate</a>&nbsp;
          链接：<a href="http://xiaofeng.javaeye.com/blog/211848" style="color:red;">http://xiaofeng.javaeye.com/blog/211848</a>&nbsp;
          发表时间: 2008年07月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          就是做了些小动作，将访问者的屏幕分辨率与壁纸的分辨率匹配，但是在壁纸站里显得很贴切.<br />http://www.enterdesk.com
          <br/>
          <span style="color:red;">
            <a href="http://xiaofeng.javaeye.com/blog/211848#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></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 05 Jul 2008 13:10:24 +0800</pubDate>
        <link>http://xiaofeng.javaeye.com/blog/211848</link>
        <guid>http://xiaofeng.javaeye.com/blog/211848</guid>
      </item>
      <item>
        <title>开发者版本：你属于哪个版本的程序员？</title>
        <author>hilliate</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://xiaofeng.javaeye.com">hilliate</a>&nbsp;
          链接：<a href="http://xiaofeng.javaeye.com/blog/210782" style="color:red;">http://xiaofeng.javaeye.com/blog/210782</a>&nbsp;
          发表时间: 2008年07月02日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          【6月25日 CSDN 付江/编译】国外开发者博客中有一篇有趣的文章，将程序员按水平像软件版本号那样划分为不同的版本。相对于在招聘时分为初级，中级，高级程序员，直接表明需要某种语言N版本的程序员或许更方便直接。根据作者的观点，可将WEB开发者大致分为以下几个版本：<br /><br />Alpha：阅读过一些专业书籍，大多数能用Dreamweaver或者FrontPage帮朋友制作一些Web页面。但在他们熟练掌握HTML代码以前，你大概不会雇佣他们成为职业的WEB制作人员。<br /><br />Beta：已经比较擅长整合站点页面了，在HTML技巧方面也有一定造诣，但还是用Tables来制作页面，不了解CSS，在面对动态页面或数据库连接时还是底气不足。<br /><br />Pre Version 1 (0.1)：比Beta版的开发者水平要高。熟悉HTML，开始了解CSS是如何运作的，懂一点JavaScript，但还是基于业余水准，逐步开始关心动态站点搭建和数据库连接的知识。这个版本的WEB开发人员还远不能成为雇主眼中的香饽饽。<br /><br />1.0: 能够基本把控整个站点开发，针对每个问题尽可能的找到最直接的解决办法。但对可测性，可扩展性以及在不同(层)框架下如何选择最合适的WEB设计工具尚无概念。这个版本的WEB开发者有良好的技术基础，需要有进一步的帮助和指导。<br /><br /><br /><br />2.0：懂面向对象的编程语言，理解分层开发的必要性，关注代码分离，对问题寻找更完美的解决方法，偶然也会考虑设计模式的问题，但对此仍然概念不清。属于优秀的初级开发者，能完成较松散的代码开发(相对大型严谨的站点开发而言)，在面对较复杂问题寻找解决办法时需要周边人的帮助。<br /><br />3.0：开始较为深入的理解面向对象编程和设计模式，了解他们的用途，当看到好的设计模式时能看透其本质，逐步关注分层的架构解决办法和可测试性。理解不同的开发语言并能说出他们的异同(例如各自的优势)。属于优秀的中级别开发者，雇主也确信他们最终能找到问题的解决办法，这个版本的人可以给1.0和2.0的开发者以指导。但他们对架构的理解仍然不够清晰，值得一提的是，只要给予一些指导，他们能很快理解并熟记做出的决定，以及选定方案的优势所在。<br /><br />4.0：理解模式，重视用户的反馈。着手研究方法论，架构设计和软件开发的最佳入口。头脑中已经形成了超越开发语言，技术架构的整体方案，可根据需求解构程序。能从理论的角度，不同模式如何融合成最佳形态，将多种X-驱动的模式应用到不同的方案中。是精通多语言的高手，理解不同系统和方法论的细微差别，属于高级程序员。这个级别的人能够轻易的辅导2.0和3.0的程序员，将他们推向更高的级别。<br /><br />5.0：从系统的角度考虑问题。对各种系统结构有深入研究，能对整个代码架构中的问题进行改进。在团队粘合性以及代码安全性方面有杰出贡献。对1.0到4.0版本的开发人员出现的问题能及时察觉，让整个团队保持积极性且保持兴奋的状态创建软件解决办法。举例来说，他们总是对新的技术和信息保持饥渴状态，试图用最简便的方案解决开发任务。在整个IT团队中获得信任，属于高级程序员和架构师。<br /><br />那么，您属于哪个版本的程序员呢？
          <br/>
          <span style="color:red;">
            <a href="http://xiaofeng.javaeye.com/blog/210782#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></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 02 Jul 2008 21:16:46 +0800</pubDate>
        <link>http://xiaofeng.javaeye.com/blog/210782</link>
        <guid>http://xiaofeng.javaeye.com/blog/210782</guid>
      </item>
      <item>
        <title>附上jquery-formvalidator</title>
        <author>hilliate</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://xiaofeng.javaeye.com">hilliate</a>&nbsp;
          链接：<a href="http://xiaofeng.javaeye.com/blog/207302" style="color:red;">http://xiaofeng.javaeye.com/blog/207302</a>&nbsp;
          发表时间: 2008年06月24日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          表单验证用，具体介绍看他的博客就好了<br />http://www.javaeye.com/topic/156644
          <br/>
          <span style="color:red;">
            <a href="http://xiaofeng.javaeye.com/blog/207302#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></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 24 Jun 2008 08:37:47 +0800</pubDate>
        <link>http://xiaofeng.javaeye.com/blog/207302</link>
        <guid>http://xiaofeng.javaeye.com/blog/207302</guid>
      </item>
      <item>
        <title>Struts2利用stream直接输出Excel (转)</title>
        <author>hilliate</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://xiaofeng.javaeye.com">hilliate</a>&nbsp;
          链接：<a href="http://xiaofeng.javaeye.com/blog/207296" style="color:red;">http://xiaofeng.javaeye.com/blog/207296</a>&nbsp;
          发表时间: 2008年06月24日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>在利用网页展示查询结果，经常会遇到要求导出成Excel的需求。采用这种方法可以定制输出的格式和内容（还不支持合并单元格和公式），生成真正的Excel格式（不是csv）的Excel。<br />一、struts.xml<br />&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />&lt;!DOCTYPE struts PUBLIC<br />&nbsp;&nbsp;&nbsp; "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"<br />&nbsp;&nbsp;&nbsp; "http://struts.apache.org/dtds/struts-2.0.dtd"&gt;<br />&nbsp;&nbsp; <br />&lt;struts&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;constant name="struts.i18n.encoding" value="UTF-8"/&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;package name="demo" extends="struts-default"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;action name="excel" method="execute" class="demo.ExcelAction"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;result name="excel" type="stream"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param name="contentType"&gt;application/vnd.ms-excel&lt;/param&gt;&nbsp;&nbsp;&nbsp; &lt;!-- 注意这里的ContentType --&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param name="inputName"&gt;excelStream&lt;/param&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- 这里需要和Action里的变量名一致 --&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param name="contentDisposition"&gt;filename="standard.xls"&lt;/param&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param name="bufferSize"&gt;1024&lt;/param&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/result&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/action&gt;<br />&nbsp;&nbsp;&nbsp; &lt;/package&gt;<br />&lt;/struts&gt;</p>
<p>二、Struts2的 Action</p>
<p>package demo;<br />public class ExcelAction {<br />&nbsp;&nbsp;&nbsp; private InputStream excelStream; // 需要生成getter和setter</p>
<p>&nbsp;&nbsp;&nbsp; public String execute() throws Exception {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; StringBuffer excelBuf = new StringBuffer();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; excelBuf.append("BookName").append("\t").append("Year").append("\t").append("author").append("\n");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; excelBuf.append("Thinking in Java").append("\t").append("2001").append("\t").append("Eckel").append("\n");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; excelBuf.append("Spring in action").append("\t").append("2005").append("\t").append("Rod").append("\n");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String excelString = excelBuf.toString();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.debug("result excel String: " + excelString);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; excelStream = new ByteArrayInputStream(excelString.getBytes(), 0, excelString.length());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return "excel";<br />&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; // getter and setter<br />&nbsp;&nbsp;&nbsp; ...<br />}</p>
<p>三、Jsp页面</p>
<p>&lt;%@ taglib prefix="s" uri="/struts-tags"%&gt;<br />&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"&gt;<br />&lt;html&gt;<br />&nbsp;&lt;head&gt;<br />&nbsp; &lt;s:head /&gt;<br />&nbsp;&lt;/head&gt;</p>
<p>&nbsp;&lt;body&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;s:form action="" method="post"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;s:submit key="button.submit"/&gt;<br />&nbsp;&nbsp;&nbsp; &lt;/s:form&gt;<br />&nbsp;&lt;/body&gt;<br />&lt;/html&gt;</p>
<p>&nbsp;</p>
<p>转自：<a href="http://www.blogjava.net/usherlight/archive/2008/06/23/210135.html">http://www.blogjava.net/usherlight/archive/2008/06/23/210135.html</a></p>
          <br/>
          <span style="color:red;">
            <a href="http://xiaofeng.javaeye.com/blog/207296#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></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 24 Jun 2008 07:34:28 +0800</pubDate>
        <link>http://xiaofeng.javaeye.com/blog/207296</link>
        <guid>http://xiaofeng.javaeye.com/blog/207296</guid>
      </item>
      <item>
        <title>Web cache 说明[翻译](转)</title>
        <author>hilliate</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://xiaofeng.javaeye.com">hilliate</a>&nbsp;
          链接：<a href="http://xiaofeng.javaeye.com/blog/201445" style="color:red;">http://xiaofeng.javaeye.com/blog/201445</a>&nbsp;
          发表时间: 2008年06月09日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div class="postcontent">
<div class="entry-body">
<p>原文（英文）地址： <a href="http://www.mnot.net/cache_docs/"><span style="color: #8d8c8c;">http://www.mnot.net/cache_docs/</span></a>&nbsp; 版权声明：<a href="http://creativecommons.org/licenses/by-nc-nd/2.0/deed.zh"><span style="color: #8d8c8c;">署名-非商业性使用-禁止演绎 2.0</span></a></p>
<p>这是一篇知识性的文档，主要目的是为了让Web缓存相关概念更容易被开发者理解并应用于实际的应用环境中。为了简要起见，某些实现方面的细节被简化或省略了。如果你更关心细节实现则完全不必耐心看完本文，后面参考文档和更多深入阅读部分可能是你更需要的内容。</p>
<ol>
<li>什么是Web缓存，为什么要使用它？ </li>
<li>缓存的类型： <ol>
<li>浏览器缓存； </li>
<li>代理服务器缓存； </li>
</ol></li>
<li>Web缓存无害吗？为什么要鼓励缓存？ </li>
<li>Web缓存如何工作： </li>
<li>如何控制（控制不）缓存： <ol>
<li>HTML Meta标签 vs. HTTP头信息； </li>
<li>Pragma HTTP头信息（为什么不起作用）； </li>
<li>使用Expires（过期时间）HTTP头信息控制保鲜期； </li>
<li>Cache-Control（缓存控制） HTTP头信息；<br /></li>
<li>校验参数和校验； </li>
</ol></li>
<li>创建利于缓存网站的窍门； </li>
<li>编写利于缓存的脚本； </li>
<li>常见问题解答； </li>
<li>缓存机制的实现：Web服务器端配置； </li>
<li>缓存机制的实现：服务器端脚本； </li>
<li>参考文档和深入阅读； </li>
<li>关于本文档； </li>
</ol></div>
<div class="entry-more" id="more">
<h3>什么是Web缓存，为什么要使用它？</h3>
Web缓存位于Web服务器之间（1个或多个，内容源服务器）和客户端之间（1个或多个）：缓存会根据进来的请求保存输出内容的副本，例如html页面， 图片，文件（统称为副本），然后，当下一个请求来到的时候：如果是相同的URL，缓存直接使用副本响应访问请求，而不是向源服务器再次发送请求。<br /><br />使用缓存主要有2大理由：<br />
<ul>
<li><strong>减少相应延迟</strong>：因为请求从缓存服务器（离客户端更近）而不是源服务器被相应，这个过程耗时更少，让web服务器看上去相应更快； </li>
<li><strong>减少网络带宽消耗</strong>：当副本被重用时会减低客户端的带宽消耗；客户可以节省带宽费用，控制带宽的需求的增长并更易于管理。 </li>
</ul>
<h3><span style="font-weight: bold;">缓存的类型</span></h3>
<h4>浏览器缓存 </h4>
<p>对于新一代的Web浏览器来说（例如：IE，Firefox）：一般都能在设置对话框中发现关于缓存的设置，通过在你的电脑上僻处一块硬盘空间用于存储你已经看过的网站的副本。浏览器缓存根据非常简单的规则进行工作：在同一个会话过程中（在当前浏览器没有被关闭之前）会检查一次并确定缓存的副本足够新。这个缓存对于用户点击&ldquo;后退&rdquo;或者点击刚访问过的链接特别有用，如果你浏览过程中访问到同一个图片，这些图片可以从浏览器缓存中调出而即时显现。</p>
<h4>代理服务器缓存</h4>
<p>Web代理服务器使用同样的缓存原理，只是规模更大。代理服务器群为成百上千用户服务使用同样的机制；大公司和ISP经常在他们的防火墙上架设代理缓存或者单独的缓存设备；</p>
<p>由于带路服务器缓存并非客户端或者源服务器的一部分，而是位于原网络之外，请求必须路由到他们才能起作用。一个方法是手工设置你的浏览器：告诉浏览器使用 那个代理，另外一个是通过中间服务器：这个中间服务器处理所有的web请求，并将请求转发到后台网络，而用户不必配置代理，甚至不必知道代理的存在；</p>
<p>代理服务器缓存：是一个共享缓存，不只为一个用户服务，经常为大量用户使用，因此在减少相应时间和带宽使用方面很有效：因为同一个副本会被重用多次。</p>
<h4>网关缓存</h4>
<p>也被称为反向代理缓存或间接代理缓存，网关缓存也是一个中间服务器，和内网管理员部署缓存用于节省带宽不同：网关缓存一般是网站管理员自己部署：让他们的网站更容易扩展并获得更好的性能；<br />请求有几种方法被路由到网关缓存服务器上：其中典型的是让用一台或多台负载均衡服务器从客户端看上去是源服务器；<br /><br />网络内容发布商&nbsp; (Content delivery networks CDNs)分布网关缓存到整个（或部分）互联网上，并出售缓存服务给需要的网站，<a href="http://www.speedera.com/"><span style="color: #8d8c8c;">Speedera</span></a>和<a href="http://www.akamai.com/"><span style="color: #8d8c8c;">Akamai</span></a>&nbsp;,<a href="http://www.bt285.cn/"><span style="color: #8d8c8c;">BT</span></a>就是典型的网络内容发布商(下文简称CDN)。<br /><br />本问主要关注于浏览器和代理缓存，当然，有些信息对于网关缓存也同样有效；</p>
<h3>Web缓存无害吗？为什么要鼓励缓存？</h3>
<p>Web缓存在互联网上最容易被误解的技术之一：网站管理员经常怕对网站失去控制，由于代理缓存会&ldquo;隐藏&rdquo;他们的用户，让他们感觉难以监控谁在使用他们的网站。<br />不幸的是：就算不考虑Web缓存，互联网上也有很多网站使用非常多的参数以便管理员精确地跟踪用户如何使用他们的网站；如果这类问题也是你关心的，本文将告诉你如何获得精确的统计而不必将网站设计的非常缓存不友好。<br />另外一个抱怨是缓存会给用户过期或失效的数据；无论如何：本文可以告诉你怎样配置你的服务器来控制你的内容将被如何缓存。<br /><br />CDN是另外一个有趣的方向，和其他代理缓存不同：CDN的网关缓存为希望被缓存的网站服务，没有以上顾虑。即使你使用了CDN，你也要考虑后续的代理服务器缓存和浏览器缓存问题。</p>
<p>另外一方面：如果良好地规划了你的网站，缓存会有助于网站服务更快，并节省服务器负载和互联网的链接请求。这个改善是显著的：一个难以缓存的网站可能需要几秒去载入页面，而对比有缓存的网站页面几乎是即时显现：用户更喜欢速度快的网站并更经常的访问；</p>
<p>这样想：很多大型互联网公司为全世界服务器群投入上百万资金，为的就是让用户访问尽可能快，客户端缓存也是这个目的，只不过更靠近用户一端，而且最好的一点是你甚至根本不用为此付费。</p>
<p>事实上，无论你是否喜欢，代理服务器和浏览器都回启用缓存。如果你没有配置网站正确的缓存，他们会按照缺省或者缓存管理员的策略进行缓存。<br /></p>
<h3>缓存如何工作</h3>
<p>所有的缓存都用一套规则来帮助他们决定什么时候使用缓存中的副本提供服务（假设有副本可用的情况下）；一些规则在协议中有定义（HTTP协议1.0和1.1），一些规则由缓存的管理员设置（浏览器的用户或者代理服务器的管理员）；<br />一般说来：遵循以下基本的规则（不必担心，你不必知道所有的细节，细节将随后说明）</p>
<ol>
<li>如果响应头信息：告诉缓存器不要保留缓存，缓存器就不会缓存相应内容； </li>
<li>如果请求信息是需要认证或者安全加密的，相应内容也不会被缓存； </li>
<li>如果在回应中不存在校验器（ETag或者Last-Modified头信息），缓存服务器会认为缺乏直接的更新度信息，内容将会被认为不可缓存。 </li>
<li>一个缓存的副本如果含有以下信息：内容将会被认为是足够新的 
<ul>
<li>含有完整的过期时间和寿命控制头信息，并且内容仍在保鲜期内； </li>
<li>浏览器已经使用过缓存副本，并且在一个会话中已经检查过内容的新鲜度； </li>
<li>缓存代理服务器近期内已经使用过缓存副本，并且内容的最后更新时间在上次使用期之前； </li>
<li>够新的副本将直接从缓存中送出，而不会向源服务器发送请求； </li>
</ul>
</li>
<li>如果缓存的副本已经太旧了，缓存服务器将向源服务器发出请求校验请求，用于确定是否可以继续使用当前拷贝继续服务； </li>
</ol>总之：<strong><em>新鲜度</em></strong>和<strong>校验</strong>是确定内容是否可用的最重要途径：
<p>&nbsp;</p>
<p>如果副本足够新，从缓存中提取就立刻能用了；<br />而经缓存器校验后发现副本的原件没有变化，系统也会避免将副本内容从源服务器整个重新传输一遍。<br /></p>
<h3>如何控制（控制不）缓存</h3>
<p>有很多工具可以帮助设计师和网站管理员调整缓存服务器对待网站的方式，这也许需要你亲自下手对服务器的配置进行一些调整，但绝对值得；了解如何使用这些工具请参考后面的实现章节；</p>
<h4>HTML meta标签和HTTP 头信息</h4>
<p>HTML的编写者会在文档的&lt;HEAD&gt;区域中加入描述文档的各种属性，这些META标签常常被用于标记文档不可以被缓存或者标记多长时间后过期；<br />META标签使用很简单：但是效率并不高，因为只有几种浏览器会遵循这个标记（那些真正会&ldquo;读懂&rdquo;HTML的浏览器），没有一种缓存代理服务器能遵循这个 规则（因为它们几乎完全不解析文档中HTML内容）；有事会在Web页面中增加：Pragma: no-cache这个META标记，如果要让页面保持刷新，这个标签其实完全没有必要。<br />如果你的网站托管在ISP机房中，并且机房可能不给你权限去控制HTTP的头信息（如：Expires和Cache-Control），大声控诉：这些机制对于你的工作来说是必须的；<br />另外一方面： HTTP头信息可以让你对浏览器和代理服务器如何处理你的副本进行更多的控制。他们在HTML代码中是看不见的，一般由Web服务器自动生成。但是，根据 你使用的服务，你可以在某种程度上进行控制。在下文中：你将看到一些有趣的HTTP头信息，和如何在你的站点上应用部署这些特性。<br /><br />HTTP头信息发送在HTML代码之前，只有被浏览器和一些中间缓存能看到，一个典型的HTTP 1.1协议返回的头信息看上去像这样：</p>
<div style="margin-left: 40px;"><span style="font-style: italic;">HTTP/1.1 200 OK</span><br /><span style="font-style: italic;">Date: Fri, 30 Oct 1998 13:19:41 GMT</span><br /><span style="font-style: italic;">Server: Apache/1.3.3 (Unix)</span><br /><span style="font-style: italic;">Cache-Control: max-age=3600, must-revalidate</span><br /><span style="font-style: italic;">Expires: Fri, 30 Oct 1998 14:19:41 GMT</span><br /><span style="font-style: italic;">Last-Modified: Mon, 29 Jun 1998 02:28:12 GMT</span><br /><span style="font-style: italic;">ETag: "3e86-410-3596fbbc"</span><br /><span style="font-style: italic;">Content-Length: 1040</span><br /><span style="font-style: italic;">Content-Type: text/html</span><br /></div>
<p><br />在头信息空一行后是HTML代码的输出，关于如何设置HTTP头信息请参考实现章节；</p>
<h4>Pragma HTTP头信息 (为什么它不起作用)</h4>
<p>很多人认为在HTTP头信息中设置了Pragma: no-cache后会让内容无法被缓存。但事实并非如此：HTTP的规范中，响应型头信息没有任何关于Pragma属性的说明，而讨论了的是请求型头信息 Pragma属性（头信息也由浏览器发送给服务器），虽然少数集中缓存服务器会遵循这个头信息，但大部分不会。用了Pragma也不起什么作用，要用就使 用下列头信息：</p>
<h4>使用Expires（过期时间）HTTP头信息来控制保鲜期</h4>
<p>Expires（过期时间） 属性是HTTP控制缓存的基本手段，这个属性告诉缓存器：相关副本在多长时间内是新鲜的。过了这个时间，缓存器就会向源服务器发送请求，检查文档是否被修改。几乎所有的缓存服务器都支持Expires（过期时间）属性；<br /><br />大部分Web服务器支持你用几种方式设置Expires属性；一般的：可以设计一个绝对时间间隔：基于客户最后查看副本的时间（最后访问时间）或者根据服务器上文档最后被修改的时间；</p>
<p>Expires头信息：对于设置静态图片文件（例如导航栏和图片按钮）可缓存特别有用；因为这些图片修改很少，你可以给它们设置一个特别长的过期时间，这会使你的网站对用户变得相应非常快；他们对于控制有规律改变的网页也很有用，例如：你每天早上6点更新新闻页，你可以设置副本的过期时间也是这个时间，这样缓存 服务器就知道什么时候去取一个更新版本，而不必让用户去按浏览器的&ldquo;刷新&rdquo;按钮。</p>
<p>过期时间头信息属性值<strong>只能</strong>是HTTP格式的日期时间，其他的都会被解析成当前时间&ldquo;之前&rdquo;，副本会过期，记住：HTTP的日期时间必须是格林威治时间（GMT），而不是本地时间。举例：</p>
<div style="margin-left: 40px;"><span style="font-style: italic;">Expires: Fri, 30 Oct 1998 14:19:41 GMT</span><br /></div>
<p>所以使用过期时间属性一定要确认你的Web服务器时间设置正确，一个途径是通过网络时间同步协议（Network Time Protocol NTP），和你的系统管理员那里你可以了解更多细节。<br />虽然过期时间属性非常有用，但是它还是有些局限，首先：是牵扯到了日期，这样Web服务器的时间和缓存服务器的时间必须是同步的，如果有些不同步，要么是应该缓存的内容提前过期了，要么是过期结果没及时更新。<br />还有一个过期时间设置的问题也不容忽视：如果你设置的过期时间是一个固定的时间，如果你返回内容的时候又没有连带更新下次过期的时间，那么之后所有访问请求都会被发送给源Web服务器，反而增加了负载和响应时间；</p>
<h4>Cache-Control（缓存控制） HTTP头信息</h4>
<p>HTTP 1.1介绍了另外一组头信息属性：Cache-Control响应头信息，让网站的发布者可以更全面的控制他们的内容，并定位过期时间的限制。<br />有用的 Cache-Control响应头信息包括：</p>
<ul>
<li><strong>max-age</strong>=[秒] &mdash; 执行缓存被认为是最新的最长时间。类似于过期时间，这个参数是基于请求时间的相对时间间隔，而不是绝对过期时间，[秒]是一个数字，单位是秒：从请求时间开始到过期时间之间的秒数。 </li>
<li><strong>s-maxage</strong>=[秒] &mdash; 类似于max-age属性，除了他应用于共享（如：代理服务器）缓存 </li>
<li><strong>public </strong>&mdash; 标记认证内容也可以被缓存，一般来说： 经过HTTP认证才能访问的内容，输出是自动不可以缓存的； </li>
<li><strong>no-cache</strong> &mdash; 强制每次请求直接发送给源服务器，而不经过本地缓存版本的校验。这对于需要确认认证应用很有用（可以和public结合使用），或者严格要求使用最新数据的应用（不惜牺牲使用缓存的所有好处）； </li>
<li><strong>no-store</strong> &mdash; 强制缓存在任何情况下都不要保留任何副本 </li>
<li><strong>must-revalidate</strong> &mdash; 告诉缓存必须遵循所有你给予副本的新鲜度的，HTTP允许缓存在某些特定情况下返回过期数据，指定了这个属性，你高速缓存，你希望严格的遵循你的规则。 </li>
<li><strong>proxy-revalidate</strong> &mdash; 和 must-revalidate类似，除了他只对缓存代理服务器起作用 </li>
</ul>
<p>举例:</p>
<div style="margin-left: 40px; font-style: italic;">Cache-Control: max-age=3600, must-revalidate<br /></div>
<p>如果你计划试用Cache-Control属性，你应该看一下这篇HTTP文档，详见参考和深入阅读；<br /></p>
<h4>校验参数和校验</h4>
<p>在Web缓存如何工作： 我们说过：校验是当副本已经修改后，服务器和缓存之间的通讯机制；使用这个机制：缓存服务器可以避免副本实际上仍然足够新的情况下重复下载整个原件。<br />校验参数非常重要，如果1个不存在，并且没有任何信息说明保鲜期（Expires或Cache-Control）的情况下，缓存将不会存储任何副本；<br />最常见的校验参数是文档的最后修改时间，通过最后Last-Modified头信息可以，当一份缓存包含Last-Modified信息，他基于此信息，通过添加一个If-Modified-Since请求参数，向服务器查询：这个副本从上次查看后是否被修改了。<br />HTTP 1.1介绍了另外一个校验参数： ETag，服务器是服务器生成的唯一标识符ETag，每次副本的标签都会变化。由于服务器控制了ETag如何生成，缓存服务器可以通过If-None-Match请求的返回没变则当前副本和原件完全一致。<br />所有的缓存服务器都使用Last-Modified时间来确定副本是否够新，而ETag校验正变得越来越流行；<br />所有新一代的Web服务器都对静态内容（如：文件）自动生成ETag和Last-Modified头信息，而你不必做任何设置。但是，服务器对于动态内容（例如：CGI,ASP或数据库生成的网站）并不知道如何生成这些信息，参考一下编写利于缓存的脚本章节；<br /></p>
<h3>创建利于缓存网站的窍门</h3>
<p>除了使用新鲜度信息和校验，你还有很多方法使你的网站缓存友好。</p>
<ul>
<li><strong>保持URL稳定</strong>： 这是缓存的金科玉律，如果你给在不同的页面上，给不同用户或者从不同的站点上提供相同的内容，应该使用相同的URL，这是使你的网站缓存友好最简单，也是 最高效的方法。例如：如果你在页面上使用 "/index.html" 做为引用，那么就一直用这个地址； </li>
<li><strong>使用一个共用的库</strong>存放每页都引用的图片和其他页面元素； </li>
<li><strong>对于不经常改变的图片/页面启用缓存</strong>，并使用Cache-Control: max-age属性设置一个较长的过期时间； </li>
<li><strong>对于定期更新的内容</strong>设置一个缓存服务器可识别的max-age属性或过期时间； </li>
<li><strong>如果数据源（特别是下载文件）变更，修改名称</strong>，这样：你可以让其很长时间不过期，并且保证服务的是正确的版本；而链接到下载文件的页面是一个需要设置较短过期时间的页面。 </li>
<li><strong>万不得已不要改变文件</strong>，否则你会提供一个非常新的Last-Modified日期；例如：当你更新了网站，不要复制整个网站的所有文件，只上传你修改的文件。 </li>
<li><strong>只在必要的时候使用Cookie</strong>，cookie是非常难被缓存的，而且在大多数情况下是不必要的，如果使用cookie，控制在动态网页上； </li>
<li><strong>减少试用SSL</strong>，加密的页面不会被任何共享缓存服务器缓存，只在必要的时候使用，并且在SSL页面上减少图片的使用； </li>
<li><strong>使用可缓存性评估引擎</strong>，这对于你实践本文的很多概念都很有帮助； </li>
</ul>
<h3>编写利于缓存的脚本</h3>
<p>脚本缺省不会返回校验参数（返回Last-Modified或ETag头信息）或其他新鲜度信息（Expires或Cache-Control），有些动态脚本的确是动态内容（每次相应内容都不一样），但是更多（搜索引擎，数据库引擎网站）网站还是能从缓存友好中获益的。<br />一般说来，如果脚本生成的输出在未来一段时间（几分钟或者几天）都是可重复复制的，那么就是可缓存的。如果脚本输出内容只随URL变化而变化，也是可缓存的；但如果输出会根据cookie，认证信息或者其他外部条件变化，则还是不可缓存的。</p>
<ul>
<li>最利于缓存的脚本就是将内容改变时导出成静态文件，Web服务器可以将其当作另外一个网页并生成和试用校验参数，让一些都变得更简单，只需要写入文件即可，这样最后修改时间也有了； </li>
<li>另外一个让脚本可缓存的方法是对一段时间内能保持较新的内容设置一个相对寿命的头信息，虽然通过Expires头信息也可以实现，但更容易的是用Cache-Control: max-age属性，它会让首次请求后一段时间内缓存保持新鲜； </li>
<li>如果以上做法你都做不到，你可以让脚本生成一个校验属性，并对 If-Modified-Since 和/或If-None-Match请求作出反应，这些属性可以从解析HTTP头信息得到，并对符合条件的内容返回304 Not Modified（内容未改变），可惜的是，这种做法比不上前2种高效； </li>
</ul>
<p>其他窍门： </p>
<ul>
<li>尽量避免使用POST，除非万不得已，POST模式的返回内容不会被大部分缓存服务器保存，如果你发送内容通过URL和查询（通过GET模式）的内容可以缓存下来供以后使用； </li>
<li>不要在URL中加入针对每个用户的识别信息：除非内容是针对每个用户不同的； </li>
<li>不要统计一个用户来自一个地址的所有请求，因为缓存常常是一起工作的； </li>
<li>生成并返回Content-Length头信息，如果方便的话，这个属性让你的脚本在可持续链接模式时：客户端可以通过一个TCP/IP链接同时请求多个副本，而不是为每次请求单独建立链接，这样你的网站相应会快很多； </li>
</ul>
具体定义请参考实现章节。
<h3>常见问题解答</h3>
<h4>让网站变得可缓存的要点是什么？</h4>
<p>好的策略是确定那些内容最热门，大量的复制（特别是图片）并针对这些内容先部署缓存。</p>
<h4>如何让页面通过缓存达到最快相应？</h4>
<p>缓存最好的副本是那些可以长时间保持新鲜的内容；基于校验虽然有助于加快相应，但是它不得不和源服务器联系一次去检查内容是否够新，如果缓存服务器上就知道内容是新的，内容就可以直接相应返回了。</p>
<h4>我理解缓存是好的，但是我不得不统计多少人访问了我的网站！</h4>
<p>如果你必须知道每次页面访问的，选择【一】个页面上的小元素，或者页面本身，通过适当的头信息让其不可缓存，例如： 可以在每个页面上部署一个1x1像素的透明图片。Referer头信息会有包含这个图片的每个页面信息；<br />明确一点：这个并不会给你一个关于你用户精确度很高的统计，而且这对互联网和你的用户这都不太好，消耗了额外的带宽，强迫用户去访问无法缓存的内容。了解更多信息，参考访问统计资料。</p>
<h4>我如何能看到HTTP头信息的内容？</h4>
<p>很多浏览器在页面属性或类似界面中可以让你看到Expires 和Last-Modified信息；如果有的话：你会找到页面信息的菜单和页面相关的文件（如图片），并且包含他们的详细信息；<br />看到完整的头信息，你可以用telnet手工连接到Web服务器；<br />为此：你可能需要用一个字段指定端口（缺省是80），或者链接到<a href="http://www.5a520.cn/"><span style="color: #8d8c8c;">www.5a520.cn:80</span></a> 或者 <a href="http://www.todou.cn/"><span style="color: #8d8c8c;">www.todou.cn</span></a> &nbsp;80(注意是空格)，更多设置请参考一下telnet客户端的文档；<br />打开网站链接：请求一个查看链接，如果你想看到http://www.example.com/foo.html 连接到www.example.com的80端口后，键入：</p>
<div style="margin-left: 40px;"><span style="font-style: italic;">GET /foo.html HTTP/1.1 [回车]</span><br /><span style="font-style: italic;">GET /foo.html HTTP/1.1 [return]</span><br /><span style="font-style: italic;">Host: <a href="http://www.5a520.cn/"><span style="color: #8d8c8c;">www.5a520.cn</span></a>[回车][回车] </span><br /><span style="font-style: italic;">Host: <a href="http://www.todou.cn/"><span style="color: #8d8c8c;">www.todou.cn [return][return</span></a>] </span><br /></div>
<p>在[回车]处按键盘的回车键；在最后，要按2次回车，然后，就会输出头信息及完整页面，如果只想看头信息，将GET换成HEAD。<br /></p>
<h4>我的页面是密码保护的，代理缓存服务器如何处理他们？</h4>
<p>缺省的，网页被HTTP认证保护的都是私密内容，它们不会被任何共享缓存保留。但是，你可以通过设置Cache-Control: public让认证页面可缓存，HTTP 1.1标准兼容的缓存服务器会认出它们可缓存。<br />如果你认为这些可缓存的页面，但是需要每个用户认证后才能看，可以组合使用Cache-Control: public和no-cache头信息，高速缓存必须在提供副本之前，将将新客户的认证信息提交给源服务器。设置就是这样：</p>
<blockquote><em>Cache-Control: public, no-cache</em><br /></blockquote>
<p>无论如何：这是减少认证请求的最好方法，例如： 你的图片是不机密的，将它们部署在另外一个目录，并对此配置服务器不强制认证。这样，那些图片会缺省都缓存。</p>
<h4>我们是否要担心用户通过cache访问我的站点？</h4>
<p>代理服务器上SSL页面不会被缓存（不推荐被缓存），所以你不必为此担心。但是，由于缓存保存了非SSL请求和从他们抓取的URL，你要意识到没有安全保护的网站，可能被不道德的管理员可能搜集用户隐私，特别是通过URL。<br />实际上，位于服务器和客户端之间的管理员可以搜集这类信息。特别是通过CGI脚本在通过URL传递用户名和密码的时候会有很大问题；这对泄露用户名和密码是一个很大的漏洞；<br />如果你初步懂得互联网的安全机制，你不会对缓存服务器有任何。</p>
<h4>我在寻找一个包含在Web发布系统解决方案，那些是比较有缓存意识的系统？</h4>
<p>这很难说，一般说来系统越复杂越难缓存。最差就是全动态发布并不提供校验参数；你无发缓存任何内容。可以向系统提供商的技术人员了解一下，并参考后面的实现说明。</p>
<h4>我的图片设置了1个月后过期，但是我现在需要现在更新。</h4>
<p>过期时间是绕不过去的，除非缓存（浏览器或者代理服务器）空间不足才会删除副本，缓存副本在过期之间会被一直使用。<br />最好的办法是改变它们的链接，这样，新的副本将会从源服务器上重新下载。记住：引用它们的页面本身也会被缓存。因此，使用静态图片和类似内容是很容易缓存的，而引用他们的HTML页面则要保持非常更新；<br />如果你希望对指定的缓存服务器重新载入一个副本，你可以强制使用&ldquo;刷新&rdquo;（在FireFox中在reload的时候按住shift键：就会有前面提到恶Pragma: no-cache头信息发出）。或者你可以让缓存的管理员从他们的界面中删除相应内容；</p>
<h4>我运行一个Web托管服务，如何让我的用户发布缓存友好的网页？</h4>
<p>如果你使用apahe，可以考虑允许他们使用.htaccess文件并提供相应的文档；<br />另外一方面： 你也可以考虑在各种虚拟主机上建立各种缓存策略。例如： 你可以设置一个目录 /cache-1m 专门用于存放访问1个月的访问，另外一个 /no-cache目录则被用提供不可存储副本的服务。<br />无论如何：对于大量用户访问还是应该用缓存。对于大网站，这方面的节约很明显（带宽和服务器负载）；</p>
<h4>我标记了一些网页是可缓存的，但是浏览器仍然每次发送请求给服务。如何强制他们保存副本？</h4>
<p>缓存服务器并不会总保存副本并重用副本；他们只是在特定情况下会不保存并使用副本。所有的缓存服务器都回基于文件的大小，类型（例如：图片 页面），或者服务器空间的剩余来确定如何缓存。你的页面相比更热门或者更大的文件相比，并不值得缓存。<br />所以有些缓存服务器允许管理员根据文件类型确定缓存副本的优先级，允许某些副本被永久缓存并长期有效；</p>
<h3>缓存机制的实现 - Web服务器端配置</h3>
<p>一般说来，应该选择最新版本的Web服务器程序来部署。不仅因为它们包含更多利于缓存的功能，新版本往往在性能和安全性方面都有很多的改善。</p>
<h4>Apache HTTP服务器</h4>
<p>Apache有些可选的模块来包含这些头信息： 包括Expires和Cache-Control。 这些模块在1.2版本以上都支持；<br />这些模块需要和apache一起编译；虽然他们已经包含在发布版本中，但缺省并没有启用。为了确定相应模块已经被启用：找到httpd程序并运行httpd -l 它会列出可用的模块，我们需要用的模块是mod_expires和mod_headers</p>
<ul>
<li>如果这些模块不可用，你需要联系管理员，重新编译并包含这些模块。这些模块有时候通过配置文件中把注释掉的配置启用，或者在编译的时候增加-enable -module=expires和-enable-module=headers选项（在apache 1.3和以上版本）。 参考Apache发布版中的INSTALL文件； </li>
</ul>
<p>Apache一旦启用了相应的模块，你就可以在.htaccess文件或者在服务器的access.conf文件中通过mod_expires设置副本什 么时候过期。你可设置过期从访问时间或文件修改时间开始计算，并且应用到某种文件类型上或缺省设置，参考<a href="http://httpd.apache.org/docs/1.3/mod/mod_expires.html"><span style="color: #8d8c8c;">模块的文档</span></a>获得更多信息，或者遇到问题的时候向你身边的apache专家讨教。<br />应用Cache-Control头信息，你需要使用mod_headers,它将允许你设置任意的HTTP头信息，参考<a href="http://httpd.apache.org/docs/1.3/mod/mod_headers.html"><span style="color: #8d8c8c;">mod_headers的文档</span></a>可以获得更多资料；<br />这里有个例子说明如何使用头信息：</p>
<ul>
<li>.htaccess文件允许web发布者使用命令只在配置文件中用到的命令。他影响到所在目录及其子目录；问一下你的服务器管理员确认这个功能是否启用了。 <br /></li>
</ul>
<div style="margin-left: 40px;"><span style="font-style: italic;">### 启用 mod_expires</span><br /><span style="font-style: italic;">ExpiresActive On</span><br /><span style="font-style: italic;">### 设置 .gif 在被访问过后1个月过期。</span><br /><span style="font-style: italic;">ExpiresByType image/gif A2592000</span><br /><span style="font-style: italic;">### 其他文件设置为最后修改时间1天后过期</span><br /><span style="font-style: italic;">### (用了另外的语法)</span><br /><span style="font-style: italic;">ExpiresDefault "modification plus 1 day"</span><br /><span style="font-style: italic;">### 在index.html文件应用 Cache-Control头属性</span><br /><span style="font-style: italic;">&lt;Files index.html&gt;</span><br /><span style="font-style: italic;">Header append Cache-Control "public, must-revalidate"</span><br /><span style="font-style: italic;">&lt;/Files&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br /></div>
<ul>
<li>注意： 在适当情况下mod_expires会自动计算并插入Cache-Control:max-age 头信息 </li>
</ul>
<p>Apache 2.0的配置和1.3类似，更多信息可以参考2.0的<a href="http://httpd.apache.org/docs/2.2/mod/mod_expires.html"><span style="color: #8d8c8c;">mod_expires</span></a>和<a href="http://httpd.apache.org/docs/2.2/mod/mod_headers.html"><span style="color: #8d8c8c;">mod_headers文档</span></a>；<br /></p>
<h4>Microsoft IIS服务器</h4>
<p>Microsoft的IIS可以非常容易的设置头信息，注意：这只针对IIS 4.0服务器，并且只能在NT服务器上运行。<br />为网站的一个区域设置头信息，先要到管理员工具界面中，然后设置属性。选择HTTP Header选单，你会看到2个有趣的区域：启用内容过期和定制HTTP头信息。头一个设置会自动配置，第二个可以用于设置Cache-Control头信息；<br />设置asp页面的头信息可以参考后面的ASP章节，也可以通过ISAPI模块设置头信息，细节请参考MSDN。<br /></p>
<h4>Netscape/iPlanet企业服务器</h4>
<p>3.6版本以后，Netscape/iPlanet已经不能设置Expires头信息了，他从3.0版本开始支持HTTP 1.1的功能。这意味着HTTP 1.1的缓存（代理服务器/浏览器）优势都可以通过你对Cache-Control设置来获得。<br />使用Cache-Control头信息，在管理服务器上选择内容管理|缓存设置目录。然后：使用资源选择器，选择你希望设置头信息的目录。设置完头信息后，点击&ldquo;OK&rdquo;。更多信息请参考<a href="http://developer.netscape.com/docs/manuals/enterprise/admnunix/content.htm#1006282"><span style="color: #8d8c8c;">Netscape/iPlanet企业服务器的手册</span></a>。<br /></p>
<h4>缓存机制的实现：服务器端脚本</h4>
<p>需要注意的一点是：也许服务器设置HTTP头信息比脚本语言更容易，但是两者你都应该使用。<br />因为服务器端的脚本主要是为了动态内容，他本身不产生可缓存的文件页面，即使内容实际是可以缓存的。如果你的内容经常改变，但是不是每次页面请求都改变， 考虑设置一个Cache-Control: max-age头信息；大部分用户会在短时间内多次访问同一页面。例如： 用户点击&ldquo;后退&rdquo;按钮，即使没有新内容，他们仍然要再次从服务器下载内容查看。<br /></p>
<h4>CGI程序</h4>
<p>CGI脚本是生成内容最流行的方式之一，你可以很容易在发送内容之前的扩展HTTP头信息；大部分CGI实现都需要你写 Content-Type头信息，例如这个Perl脚本：</p>
<div style="margin-left: 40px;"><span style="font-style: italic;">#!/usr/bin/perl</span><br /><span style="font-style: italic;">print "Content-type: text/html\n";</span><br /><span style="font-style: italic;">print "Expires: Thu, 29 Oct 1998 17:04:19 GMT\n";</span><br /><span style="font-style: italic;">print "\n";</span><br /><span style="font-style: italic;">### 后面是内容体...</span><br /></div>
<p>由于都是文本，你可以很容易通过内置函数生成Expires和其他日期相关的头信息。如果你使用Cache-Control: max-age;会更简单；</p>
<div style="margin-left: 40px;"><span style="font-style: italic;">print "Cache-Control: max-age=600\n";</span><br /></div>
<p>这样脚本可以在被请求后缓存10分钟；这样用户如果按&ldquo;后退&rdquo;按钮，他们不会重新提交请求；<br />CGI的规范同时也允许客户端发送头信息，每个头信息都有一个&lsquo;HTTP_&rsquo;的前缀；这样如果一个客户端发送一个If-Modified-Since请求，就是这样的：</p>
<div style="margin-left: 40px; font-style: italic;">HTTP_IF_MODIFIED_SINCE = Fri, 30 Oct 1998 14:19:41 GMT <br /></div>
<p><br />参考一下<a href="http://www.mnot.net/cgi_buffer/"><span style="color: #8d8c8c;">cgi_buffer</span></a>库，一个自动处理ETag的生成和校验的库，生成Content-Length属性和对内容进行gzip压缩。在Python脚本中也只需加入一行；<br /></p>
<h4>服务器端包含 Server Side Includes</h4>
<p>SSI（经常使用.shtml扩展名）是网站发布者最早可以生成动态内容的方案。通过在页面中设置特别的标记，也成为一种嵌入HTML的脚本；<br />大部分SSI的实现无法设置校验器，于是无法缓存。但是Apache可以通过对特定文件的组执行权限设置实现允许用户设置那种SSI可以被缓存；结合XbitHack调整整个目录。更多文档请参考<a href="http://httpd.apache.org/docs/1.3/mod/mod_include.html"><span style="color: #8d8c8c;">mod_include文档</span></a>。</p>
<h4>PHP</h4>
<p>PHP是一个内建在web服务器中的服务器端脚本语言，当做为HTML嵌入式脚本，很像SSI，但是有更多的选项，PHP可以在各种Web服务器上设置为CGI模式运行，或者做为Apache的模块；<br />缺省PHP生成副本没有设置校验器，于是也无法缓存，但是开发者可以通过Header()函数来生成HTTP的头信息；<br />例如：以下代码会生成一个Cache-Control头信息，并设置为3天以后过期的Expires头信息；</p>
<div style="margin-left: 40px;"><span style="font-style: italic;">&lt;?php</span><br /><span style="font-style: italic;">&nbsp;Header("Cache-Control: must-revalidate");</span><br /><br /><span style="font-style: italic;">&nbsp;$offset = 60 * 60 * 24 * 3;</span><br /><span style="font-style: italic;">&nbsp;$ExpStr = "Expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";</span><br /><span style="font-style: italic;">&nbsp;Header($ExpStr);</span><br /><span style="font-style: italic;">?&gt;</span><br /></div>
<p>记住： Header()的输出必须先于所有其他HTML的输出；<br />正如你看到的：你可以手工创建HTTP日期；PHP没有为你提供专门的函数（新版本已经让这个越来越容易了，请参考PHP的<a href="http://php.net/date"><span style="color: #8d8c8c;">日期相关函数文档</span></a>），当然，最简单的还是设置Cache-Control: max-age头信息，而且对于大部分情况都比较适用；<br />更多信息，请参考<a href="http://www.php.net/manual/function.header.php3"><span style="color: #8d8c8c;">header相关的文档</span></a>；<br />也请参考一下<a href="http://www.mnot.net/cgi_buffer/"><span style="color: #8d8c8c;">cgi_buffer</span></a>库，自动处理ETag的生成和校验，Content-Length生成和内容的gzip压缩，PHP脚本只需包含1行代码；</p>
<h4>Cold Fusion</h4>
<p><a href="http://www.adobe.com/products/coldfusion/"><span style="color: #8d8c8c;">Cold Fusion</span></a>是Macromedia的商业服务器端脚本引擎，并且支持多种Windows平台，Linux平台和多种Unix平台。Cold Fusion通过CFHEADER标记设置HTTP头信息相对容易。可惜的是：以下的Expires头信息的设置有些容易误导；</p>
<div style="margin-left: 40px;"><span style="font-style: italic;">&lt;CFHEADER NAME="Expires" VALUE="#Now()#"&gt;</span><br /></div>
<p>它并不像你想像的那样工作，因为时间（本例中为请求发起的时间）并不会被转换成一个符合HTTP时间，而且打印出副本的Cold fusion的日期/时间对象，大部分客户端会忽略或者将其转换成1970年1月1日。<br />但是：Cold Fusion另外提供了一套日期格式化函数， GetHttpTimeSTring. 结合DateAdd函数，就很容易设置过期时间了，这里我们设置一个Header声明副本在1个月以后过期；</p>
<div style="margin-left: 40px;"><span style="font-style: italic;">&lt;cfheader name="Expires" value="#GetHttpTimeString(DateAdd('m', 1, Now()))#"&gt;</span><br /></div>
<p>你也可以使用CFHEADER标签来设置Cache-Control: max-age等其他头信息；<br />记住：Web服务器也会将头信息设置转给Cold Fusion(做为CGI运行的时候)，检查你的服务器设置并确定你是否可以利用服务器设置代替Cold Fusion。 <br /></p>
<h4>ASP和ASP.NET</h4>
<p>在asp中设置HTTP头信息是：确认Response方法先于HTML内容输出前被调用，或者使用 Response.Buffer暂存输出；同样的：注意某些版本的IIS缺省设置会输出Cache-Control: private 头信息，必须声明成public才能被共享缓存服务器缓存。<br />IIS的ASP和其他web服务器都允许你设置HTTP头信息，例如： 设置过期时间，你可以设置Response对象的属性；</p>
<div style="margin-left: 40px;"><span style="font-style: italic;">&lt;% Response.Expires=1440 %&gt;</span><br /></div>
<p>设置请求的副本在输出的指定分钟后过期，类似的：也可以设置绝对的过期时间（确认你的HTTP日期格式正确）</p>
<div style="margin-left: 40px;"><span style="font-style: italic;">&lt;% Response.ExpiresAbsolute=#May 31,1996 13:30:15 GMT# %&gt;</span><br /></div>
<p>Cache-Control头信息可以这样设置：</p>
<div style="margin-left: 40px; font-style: italic;">&lt;% Response.CacheControl="public" %&gt;<br /></div>
<p>在ASP.NET中，Response.Expires 已经不推荐使用了，正确的方法是通过Response.Cache设置Cache相关的头信息；</p>
<div style="margin-left: 40px;"><span style="font-style: italic;">Response.Cache.SetExpires ( DateTime.Now.AddMinutes ( 60 ) ) ;</span><br /><span style="font-style: italic;">Response.Cache.SetCacheability ( HttpCacheability.Public ) ;</span><br /></div>
<p>参考<a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconaspoutputcache.asp"><span style="color: #8d8c8c;">MSDN文档</span></a>可以找到更多相关新年系；<br /></p>
<h3>参考文档和深入阅读</h3>
<h4><a href="http://www.ietf.org/rfc/rfc2616.txt" target="_blank"><span style="color: #8d8c8c;">HTTP 1.1 规范定义</span></a></h4>
<p>HTTP 1.1的规范有大量的扩展用于页面缓存，以及权威的接口实现指南，参考章节：13, 14.9, 14.21, 以及 14.25.<br /></p>
<h4><a href="http://www.web-caching.com/" target="_blank"><span style="color: #8d8c8c;">Web-Caching.com</span></a></h4>
<p>非常精彩的介绍缓存相关概念，并介绍其他在线资源。<br /><a href="http://www.goldmark.org/netrants/webstats/" target="_blank"><br /></a></p>
<h4><a href="http://www.goldmark.org/netrants/webstats/" target="_blank"><span style="color: #8d8c8c;">关于非连续性访问统计</span></a></h4>
<p>Jeff Goldberg内容丰富的演说告诉你为什么不应该过度依赖访问统计和计数器；<br /></p>
<h4><a href="http://www.mnot.net/cacheability/"><span style="color: #8d8c8c;">可缓存性检测引擎</span></a></h4>
<p>可缓存的引擎设计，检测网页并确定其如何与Web缓存服务器交互， 这个引擎配合这篇指南是一个很好的调试工具，<br /></p>
<h4><a href="http://www.mnot.net/cgi_buffer/"><span style="color: #8d8c8c;">cgi_buffer库</span></a></h4>
<p>包含库：用于CGI模式运行的Perl/Python/PHP脚本，自动处理ETag生成/校验，Content-Length生成和内容压缩。正确地。 Python版本也被用作其他大量的CGI脚本。<br /></p>
<h3>关于本文档</h3>
<p>本文版权属于Mark Nottingham &lt;<a href="mailto:mnot@pobox.com"><span style="color: #8d8c8c;">mnot@pobox.com</span></a>&gt;，本作品遵循<a href="http://creativecommons.org/licenses/by-nc-nd/2.0/deed.zh"><span style="color: #8d8c8c;">创作共用版权</span></a>。<br />如果你镜像本文，请通过以上邮件告知，这样你可以在更新时被通知；<br />所有的商标属于其所有人。<br />虽然作者确信内容在发布时的正确性，但不保证其应用或引申应用的正确性，如有误传，错误或其他需要澄清的问题请尽快告知作者；<br />本文最新版本可以从 <a href="http://www.mnot.net/cache_docs/"><span style="color: #8d8c8c;">http://www.mnot.net/cache_docs/</span></a> 获得；<br />翻译版本包括： <a href="http://www.jakpsatweb.cz/clanky/caching-tutorial-czech-translation.html"><span style="color: #8d8c8c;">捷克语版</span></a>，<a href="http://www.mnot.net/cache_docs/index.fr.html"><span style="color: #8d8c8c;">法语版</span></a>和<a href="http://www.chedong.com/tech/cache_docs.html"><span style="color: #8d8c8c;">中文版</span></a>。<br />版本： 1.81 - 2007年3月16日</p>
<p><a href="http://creativecommons.org/licenses/by-nc-nd/2.0/deed.zh"><span style="color: #8d8c8c;">创作共用版权声明</span></a><br />翻译： 车东 2007年9月6日</p>
</div>
</div>
          <br/>
          <span style="color:red;">
            <a href="http://xiaofeng.javaeye.com/blog/201445#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></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 09 Jun 2008 08:39:50 +0800</pubDate>
        <link>http://xiaofeng.javaeye.com/blog/201445</link>
        <guid>http://xiaofeng.javaeye.com/blog/201445</guid>
      </item>
      <item>
        <title>dreamweaver cs3---流氓软件卸载指南</title>
        <author>hilliate</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://xiaofeng.javaeye.com">hilliate</a>&nbsp;
          链接：<a href="http://xiaofeng.javaeye.com/blog/194218" style="color:red;">http://xiaofeng.javaeye.com/blog/194218</a>&nbsp;
          发表时间: 2008年05月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>要了命了，终于给cs3卸载了，虽然同时把photoshop给搞没了，但是心里还是比较惬意的。</p>
<p>用dreamweaver自带卸载绝对搞不定，用网上推荐的WinCS3Clean（好像是adobe出的专为卸载cs3套件的）也没搞定。</p>
<p>先卸载完，然后搜索注册表，遇到adobe就全删，然后去c:\program files\Common Files下，把adobe文件夹删除</p>
<p>然后去C:\Documents and Settings\Administrator\Application Data把adobe文件夹删除。</p>
<p>搞定。</p>
          <br/>
          <span style="color:red;">
            <a href="http://xiaofeng.javaeye.com/blog/194218#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></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 19 May 2008 07:42:38 +0800</pubDate>
        <link>http://xiaofeng.javaeye.com/blog/194218</link>
        <guid>http://xiaofeng.javaeye.com/blog/194218</guid>
      </item>
      <item>
        <title>Compass学习文档(3) (转)</title>
        <author>hilliate</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://xiaofeng.javaeye.com">hilliate</a>&nbsp;
          链接：<a href="http://xiaofeng.javaeye.com/blog/194077" style="color:red;">http://xiaofeng.javaeye.com/blog/194077</a>&nbsp;
          发表时间: 2008年05月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下面讲一下高级部分Compass与Hibernate，Spring的集成。Compass内部有对Hibernate,Spring的支持，如果配置好了，可以在建立和更新索引的时候不用Compass写一句代码。爽吧！～不过集成它们比较麻烦那就看我一步一步的来吧： <br />1.首先把Hibernate和Spring集成：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 来个例子吧，先看数据库脚本(MySql)：</p>
<pre name="code" class="sql">CREATE TABLE `article` (

 `Id` int(11) NOT NULL auto_increment,

 `title` varchar(40) NOT NULL default '',

 `author` int(11) default '0',

 `publish_date` date NOT NULL default '0000-00-00',

 PRIMARY KEY (`Id`)

) TYPE=MyISAM;

 

CREATE TABLE `author` (

 `Id` int(11) NOT NULL auto_increment,

 `username` varchar(20) NOT NULL default '',

 `password` varchar(20) NOT NULL default '',

 `age` smallint(6) default '0',

 PRIMARY KEY (`Id`)

) TYPE=MyISAM;</pre>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 建立一个工程叫CompassHibernateSpring</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 说明一下开发环境：eclipse3.2+myeclipse5.0+springtide+middlegen(注意要在工程上加入MyEcilpse的Hibernate和Spring能力。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 然后用Hibernate进行装配，Hibernate有三个配置文件：hibernate.cfg.xml, Article.hbm.xml,Author.hbm.xml</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 具体的结构请看Hibernate.cfg.xml:</p>
<pre name="code" class="xml">&lt;?xml version='1.0' encoding='utf-8'?&gt;

&lt;!DOCTYPE hibernate-configuration PUBLIC 

    "-//Hibernate/Hibernate Configuration DTD//EN"

    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"&gt;

&lt;hibernate-configuration&gt;

    &lt;session-factory&gt;

        &lt;property name="dialect"&gt;org.hibernate.dialect.MySQLDialect&lt;/property&gt;

        &lt;property name="connection.driver_class"&gt;com.mysql.jdbc.Driver&lt;/property&gt;

        &lt;property name="connection.username"&gt;root&lt;/property&gt;

        &lt;property name="connection.password"&gt;java&lt;/property&gt;

        &lt;property name="connection.url"&gt;jdbc:mysql://localhost:3306/test&lt;/property&gt;

        &lt;property name="show_sql"&gt;true&lt;/property&gt;

        &lt;mapping resource="org/li/compass/shibernate/Article.hbm.xml" /&gt;

        &lt;mapping resource="org/li/compass/shibernate/Author.hbm.xml" /&gt;

    &lt;/session-factory&gt;

&lt;/hibernate-configuration&gt;

Article.hbm.xml:

&lt;?xml version="1.0"?&gt;

&lt;!DOCTYPE hibernate-mapping PUBLIC

    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" &gt;

&lt;hibernate-mapping&gt;

&lt;!-- 

    Created by the Middlegen Hibernate plugin 2.2

    http://boss.bekk.no/boss/middlegen/

    http://www.hibernate.org/

--&gt;

&lt;class 

    name="org.li.compass.shibernate.Article" 

    table="article"

    lazy="false"

&gt; 

    &lt;id

        name="id"

        type="java.lang.Integer"

        column="Id"

    &gt;

            &lt;meta attribute="field-description" inherit="false"&gt;

               auto_increment

            &lt;/meta&gt;

        &lt;generator class="increment" /&gt;

    &lt;/id&gt;

    &lt;property

        name="title"

        type="java.lang.String"

        column="title"

        not-null="true"

        length="40"

    /&gt;

    &lt;property

        name="author"

        type="java.lang.String"

        column="author"

        length="11"

    /&gt;

    &lt;property

        name="publishDate"

        type="java.util.Date"

        column="publish_date"

        not-null="true"

        length="10"

    /&gt;

    &lt;!-- Associations --&gt;

 

&lt;/class&gt;

&lt;/hibernate-mapping&gt;

Author.hbm.xml:

&lt;?xml version="1.0"?&gt;

&lt;!DOCTYPE hibernate-mapping PUBLIC

    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" &gt;

&lt;hibernate-mapping&gt;

&lt;!-- 

    Created by the Middlegen Hibernate plugin 2.2

    http://boss.bekk.no/boss/middlegen/

    http://www.hibernate.org/

--&gt;

&lt;class 

    name="org.li.compass.shibernate.Author" 

    table="author"

    lazy="false"

&gt; 

    &lt;id

        name="id"

        type="java.lang.Integer"

        column="Id"

    &gt;

            &lt;meta attribute="field-description" inherit="false"&gt;

               auto_increment

            &lt;/meta&gt;

    

        &lt;generator class="increment" /&gt;

    &lt;/id&gt;

    &lt;property

        name="username"

        type="java.lang.String"

        column="username"

        not-null="true"

        length="20"

    /&gt;

    &lt;property

        name="password"

        type="java.lang.String"

        column="password"

        not-null="true"

        length="20"

    /&gt;

    &lt;property

        name="age"

        type="java.lang.Short"

        column="age"

        length="6"

    /&gt;

    &lt;!-- Associations --&gt;


&lt;/class&gt;

&lt;/hibernate-mapping&gt;</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 具本的POJO类看源代码吧：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由于这里是讲Compass的，有关Hibernate和Spring的内容网上很多中文资料的这里就不介绍了。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下面讲的是跟着我一步一步用Spring把Hibernate和Compass集成起来。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在applicationContext.xml中：</p>
<pre name="code" class="xml">&lt;bean id="sessionFactory"

        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"&gt;

        &lt;property name="dataSource"&gt;

            &lt;ref local="dataSource" /&gt;

        &lt;/property&gt;

        &lt;property name="hibernateProperties"&gt;

            &lt;props&gt;

                &lt;prop key="dialect"&gt;

                    org.hibernate.dialect.MySQLDialect

                &lt;/prop&gt;

                &lt;prop key="show_sql"&gt;true&lt;/prop&gt;

            &lt;/props&gt;

        &lt;/property&gt;

        &lt;property name="mappingDirectoryLocations"&gt;

            &lt;list&gt;

                &lt;value&gt;org/li/compass/shibernate&lt;/value&gt;

            &lt;/list&gt;

        &lt;/property&gt;

    &lt;/bean&gt;

&lt;bean id="dataSource"

        class="org.springframework.jdbc.datasource.DriverManagerDataSource"&gt;

        &lt;property name="driverClassName"&gt;

            &lt;value&gt;com.mysql.jdbc.Driver&lt;/value&gt;

        &lt;/property&gt;

        &lt;property name="url"&gt;

            &lt;value&gt;jdbc:mysql://localhost:3306/test&lt;/value&gt;

        &lt;/property&gt;

        &lt;property name="username"&gt;

            &lt;value&gt;root&lt;/value&gt;

        &lt;/property&gt;

        &lt;property name="password"&gt;

            &lt;value&gt;java&lt;/value&gt;

        &lt;/property&gt;

    &lt;/bean&gt;

    &lt;bean id="hibernateTemplate"

        class="org.springframework.orm.hibernate3.HibernateTemplate"&gt;

        &lt;property name="sessionFactory"&gt;

            &lt;ref local="sessionFactory" /&gt;

        &lt;/property&gt;

    &lt;/bean&gt;

&lt;bean id="articleDAO" class="org.li.compass.shibernate.dao.ArticleDAO"&gt;

        &lt;property name="hibernateTemplate"&gt;

            &lt;ref local="hibernateTemplate"/&gt;

        &lt;/property&gt;

    &lt;/bean&gt;

    &lt;bean id="authorDAO" class="org.li.compass.shibernate.dao.AuthorDAO"&gt;

        &lt;property name="hibernateTemplate"&gt;

            &lt;ref local="hibernateTemplate"/&gt;

        &lt;/property&gt;

    &lt;/bean&gt;

&lt;bean id="transactionManager"

        class="org.springframework.orm.hibernate3.HibernateTransactionManager"&gt;

        &lt;property name="sessionFactory"&gt;

            &lt;ref local="sessionFactory" /&gt;

        &lt;/property&gt;

    &lt;/bean&gt;</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 以上的配置是将Spring和Hibernate集成起来。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下面我们将加入Compass的配置：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由于我们只对文章进行搜索所以只对文章建立索引</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Article.cpm.xml:</p>
<pre name="code" class="xml">&lt;!DOCTYPE compass-core-mapping PUBLIC 

    "-//Compass/Compass Core Mapping DTD 1.0//EN"

    "http://www.opensymphony.com/compass/dtd/compass-core-mapping.dtd"&gt;

&lt;compass-core-mapping package="org.li.compass.shibernate"&gt;

    &lt;class name="Article" alias="article"&gt;

        &lt;!-- 这是必须有的 --&gt;

        &lt;id name="id"/&gt;

        &lt;!-- 你可以通过这个配置来在底层给这个对象加一个Field("type","java") --&gt;

        &lt;constant&gt;

            &lt;meta-data&gt;type&lt;/meta-data&gt;

            &lt;meta-data-value&gt;java&lt;/meta-data-value&gt;

        &lt;/constant&gt;

        &lt;!-- 配置一下属性 --&gt;

        &lt;property name="title"&gt;

            &lt;meta-data&gt;titleIndex&lt;/meta-data&gt;

        &lt;/property&gt;

        &lt;property name="publishDate"&gt;

            &lt;meta-data&gt;publishDateIndex&lt;/meta-data&gt;

        &lt;/property&gt;

        &lt;property name="author"&gt;

            &lt;meta-data&gt;author&lt;/meta-data&gt;

        &lt;/property&gt;

    &lt;/class&gt;

&lt;/compass-core-mapping&gt;</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 然后回到applicationContext.xml里：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 看看怎么集成的，在Compass中有个org.compass.gps.impl.SingleCompassGps是对Compass进行实时更新的，而org.compass.spring.device.hibernate.SpringHibernate3GpsDevice</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 它是和Hibernate集成并且对Hibernate的insert,delete,update进行自动的更新，所以说这样就不</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们为Compass写一句代码了。不过这两个类对Compass和Hibernate的实时功能也可以用Spring的AOP来实现（这里也不讨论了）。剩下的就是用Spring的IoC来支Compass的初始化功能进行注入，第一个是：</p>
<pre name="code" class="xml">&lt;bean id="compassConfiguration"

        class="org.compass.core.config.CompassConfiguration" /&gt;</pre>
<p>&nbsp;第二个是：</p>
<pre name="code" class="xml">&lt;bean id="compass" class="org.compass.spring.LocalCompassBean"&gt;

        &lt;!-- 这里配置只用作建立索引的类 --&gt;

        &lt;property name="classMappings"&gt;

            &lt;list&gt;

                &lt;value&gt;org.li.compass.shibernate.Article&lt;/value&gt;

            &lt;/list&gt;

        &lt;/property&gt;


        &lt;property name="resourceDirectoryLocations"&gt;

            &lt;list&gt;

                &lt;value&gt;org/li/compass/shibernate&lt;/value&gt;

            &lt;/list&gt;

        &lt;/property&gt;

        &lt;property name="compassConfiguration"

            ref="compassConfiguration" /&gt;

        &lt;property name="compassSettings"&gt;

            &lt;props&gt;

                &lt;prop key="compass.engine.connection"&gt;target/test&lt;/prop&gt;

                &lt;prop key="compass.transaction.factory"&gt;

                    org.compass.spring.transaction.SpringSyncTransactionFactory

                &lt;/prop&gt;

            &lt;/props&gt;

        &lt;/property&gt;

        &lt;property name="transactionManager" ref="transactionManager" /&gt;

    &lt;/bean&gt;</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在上面配置只用作建立索引的类就可以</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 还有与Hibernate和Spring集成差不多。有个CompassTemplate的DAO模板也要注入</p>
<pre name="code" class="xml">&lt;bean id="compassTemplate" class="org.compass.core.CompassTemplate"&gt;

        &lt;property name="compass"&gt;

            &lt;ref local="compass"/&gt;

        &lt;/property&gt;

    &lt;/bean&gt;</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 还有关键的两个类的注入：</p>
<pre name="code" class="xml">&lt;bean id="hibernateGpsDevice"

        class="org.compass.spring.device.hibernate.SpringHibernate3GpsDevice"&gt;

        &lt;property name="name"&gt;

            &lt;value&gt;hibernateDevice&lt;/value&gt;

        &lt;/property&gt;

        &lt;property name="sessionFactory" ref="sessionFactory" /&gt;

    &lt;/bean&gt;

&lt;bean id="compassGps" class="org.compass.gps.impl.SingleCompassGps"

        init-method="start" destroy-method="stop"&gt;

        &lt;property name="compass" ref="compass" /&gt;

        &lt;property name="gpsDevices"&gt;

            &lt;list&gt;

                &lt;ref local="hibernateGpsDevice" /&gt;

            &lt;/list&gt;

        &lt;/property&gt;

    &lt;/bean&gt;</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最后呢就是要在articleDAO上注入CompassTemplate因为我们要搜索的时候用到CompassTemplate了（CompassTemplate是支持事务的）</p>
<pre name="code" class="xml">&lt;property name="compassImplements"&gt;

            &lt;ref local="compassImplements"/&gt;

        &lt;/property&gt;</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这样配置就ok了</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下面测试一下吧：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 新建JUnit测试用例：</p>
<pre name="code" class="java">public class TestCompass extends TestCase

{

    private ClassPathXmlApplicationContext context = null;

    protectedvoid setUp() throws Exception

    {

        context = new ClassPathXmlApplicationContext("applicationContext.xml");

    }

    protected void tearDown() throws Exception

    {

    }

    public void insertTest()

    {

        ArticleDAO articleDao = (ArticleDAO) context.getBean("articleDAO");

        AuthorDAO authorDao = (AuthorDAO) context.getBean("authorDAO");

        Article article = new Article();

        Author author = new Author();

        author.setAge((short)21);

        author.setUsername("javafish");

        author.setPassword("java");

        article.setTitle("Compass学习文档");

        article.setPublishDate(new Date());

        article.setAuthor("javafish");

        authorDao.save(author);

        articleDao.save(article);

        

    }

    public void find()

    {

        ArticleDAO articleDao = (ArticleDAO) context.getBean("articleDAO");

        Article article = articleDao.find("文档");

        System.out.println(article.getPublishDate());

    }

}</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 看到没有在insertTest()里根本看不出用Compass来全是Hibernate和Spring的代码。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在对像article和author被写入数据库的同时，article也被写入索引了。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 看到了Compass与Hibernate,Spring集成的威力了吧。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们可以用Lucene测试一下。</p>
<pre name="code" class="java">publicvoid lucene() throws IOException, ParseException

    {

        IndexSearcher indexSearcher = new IndexSearcher("D:""workspace""CompassSpringHibernate""target""test""index""article");

        QueryParser queryParser = new QueryParser("titleIndex",new StandardAnalyzer());

        Query query = queryParser.parse("学习");

        Hits hits = indexSearcher.search(query);

        Document doc = null;

        for(int i=0;i&lt;hits.length();i++)

        {

            doc=hits.doc(i);

            System.out.println(doc.get("titleIndex"));

            System.out.println(doc.get("publishDateIndex"));

        }

    }</pre>
<p>&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 会发现结果搜索成功了～～</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 而我们查询的时候就可以在DAO类里封装CompassQuery的操作。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其它具体还是看帮助文档吧。^_^</p>
          <br/>
          <span style="color:red;">
            <a href="http://xiaofeng.javaeye.com/blog/194077#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></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 18 May 2008 14:57:44 +0800</pubDate>
        <link>http://xiaofeng.javaeye.com/blog/194077</link>
        <guid>http://xiaofeng.javaeye.com/blog/194077</guid>
      </item>
      <item>
        <title>Compass学习文档(2) (转)</title>
        <author>hilliate</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://xiaofeng.javaeye.com">hilliate</a>&nbsp;
          链接：<a href="http://xiaofeng.javaeye.com/blog/194076" style="color:red;">http://xiaofeng.javaeye.com/blog/194076</a>&nbsp;
          发表时间: 2008年05月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 上面的只讲了Compass的建立索引也就是存储对象和加载对象,这里讲一下Compass的搜索查询功能。上面说了Compass和Hibernate是非常像的。Hibernate查询的时候用的是Criteriat和Query而Compass里用的是CompassQuery具有以上两个的功能。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 还是拿上面的例子做例子吧： </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在上面的JUnit测试用例里加入： </p>
<pre name="code" class="java">public void InsertCompass() 

    { 

        CompassConfiguration comConfig = new
CompassConfiguration().configure().addClass(Article.class); 

        Compass com = comConfig.buildCompass(); 

        CompassSession comSession =
com.openSession(); 

        CompassTransaction comTx =
comSession.beginTransaction(); 

         

        Article article = new Article(); 

        article.setId((long)0); 

        article.setContent("Compass学习文档"); 

        article.setTitle("学习Compass查询"); 

        article.setPublishDate(new Date()); 

        comSession.save(article); 

        article = new Article(); 

        article.setId((long)1); 

        article.setContent("Compass是第一个基于lucene的java开源框架"); 

        article.setTitle("学习Compass"); 

        article.setPublishDate(new Date()); 

        comSession.save(article); 

        comTx.commit(); 

    } </pre>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 就是插入两个对象数据。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下面我们就搜搜体验一下吧： </p>
<pre name="code" class="java">public void TestQuery() 

    { 

CompassConfiguration comConfig = new
CompassConfiguration().configure().addClass(Article.class); 

        Compass com = comConfig.buildCompass(); 

        CompassSession session =
com.openSession(); 

        CompassTransaction tx =
session.beginTransaction(); 

        CompassHits hits =
session.queryBuilder() 

         
.queryString("titleIndex:学习") 

         
.toQuery() 

       
.addSort("title",
CompassQuery.SortPropertyType.STRING) 

       
.addSort("publishDate",CompassQuery.SortPropertyType.INT) 

         
.hits(); 

        for(int
i=0;i&lt;hits.getLength();i++) 

        { 

            System.out.println(((Article)hits.data(i)).getTitle()); 

        } 

    } </pre>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 输出结果是 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 学习Compass查询 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 学习Compass </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其实Compass完全没毕要那么罗嗦，它就是为了依照Hibernate来的。让会Hibernate的程序员可以很容易的掌握Compass。搜索的前一部分就不说了，和Hibernate的初始化一样且前面也讲了，从CompassHits开始吧。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以看到：搜索就用到CompassHits,Query，CompassQueryBuilder这一点又和lucene很像。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; session.queryBuilder()返回CompassQueryBuilder的对象，再调用queryString来查询搜索字串。可这个构造字串就有学问了：&ldquo;titleIndex:学习&rdquo;表示指明字段名搜索，如果想指明多个字段呢可以用空格和&ldquo;+&rdquo;隔开如：&ldquo;titleIndex:学习 +contentIndex:第&rdquo; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注意：查询字串里的标识不是对象的属性，而是对象的属性映射成索引的名字，这个是可以在Article.cmp.xml里看到的。还有就是一定要在两个搜索内容之间加空格要不然什么都搜不到。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; addSort就是对搜索出的结果按一定的顺序排序。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Hits()呢就是返回hits结果集吧。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最后用个for循环利用hits.data(i)将结果遍历输出。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 上面的例子达到了Hibernate中Query的功能。而CompassQuery还有和Criteriat功能一样的：再看个搜索的例子吧： </p>
<pre name="code" class="java">CompassConfiguration comConfig = new
CompassConfiguration().configure().addClass(Article.class); 

        Compass com
= comConfig.buildCompass(); 

        CompassSession
session = com.openSession(); 

        CompassTransaction
comTx = session.beginTransaction(); 

        CompassQueryBuilder
queryBuilder= session.queryBuilder(); 

        CompassQuery
compassQuery = queryBuilder.bool().addMust(queryBuilder.le("titleIndex", "学习")).toQuery(); 

        CompassHits
hits = compassQuery.addSort("title", CompassQuery.SortPropertyType.STRING).hits(); 

        for(int
i=0;i&lt;hits.getLength();i++) 

        { 

            System.out.println(((Article)hits.data(i)).getTitle()); 

        } 

        comTx.commit();</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CompassQuery里有lt,le,gt,ge和Criteriat是一个样的。不过Compass的jar包里没有eq这个函数，但是在Compass1.1M1的帮助文档中写着： </p>
<pre name="code" class="java">CompassQueryBuilder queryBuilder = session.createQueryBuilder();
 queryBuilder.bool().addMust(queryBuilder.eq("name", "jack")).addMust(queryBuilder.lt("birthdate", "19500101"))
      .toQuery().hits();</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这个可能是Compass的一个bug。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 既然没有eq我们就用： </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queryBuilder.bool().addMust(queryBuilder.le("titleIndex", "学习")).toQuery();做个演示吧。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 结果理想的。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 具体的用法和Hibernate一样，也可以查看Compass的帮助文档。<br />&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://xiaofeng.javaeye.com/blog/194076#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></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 18 May 2008 14:50:09 +0800</pubDate>
        <link>http://xiaofeng.javaeye.com/blog/194076</link>
        <guid>http://xiaofeng.javaeye.com/blog/194076</guid>
      </item>
      <item>
        <title>Compass学习文档(1) (转)</title>
        <author>hilliate</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://xiaofeng.javaeye.com">hilliate</a>&nbsp;
          链接：<a href="http://xiaofeng.javaeye.com/blog/194074" style="color:red;">http://xiaofeng.javaeye.com/blog/194074</a>&nbsp;
          发表时间: 2008年05月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Compass是第一个实现java搜索引擎的开源框架,它是基于Lucene之上的，提供更简单的搜索引擎API，事务支持，对象到搜索引擎映射（Annotations &amp; XML），Xml到搜索引擎映射，可以和Hibernate,Spring集成，功能非常的强大。如果用Hibernate,Spring做的项目需要搜索引擎的话，Compass是个非常好的选择。个人认为：如果说Lucene是搜索引擎中的JDBC，那么Compass就是Hibernate。而Compass和Hibernate不仅仅是比喻的像，它们的类和用法，和作用也非常的像。Compass是用面向对象编程方法来实现搜索。如果会Hibernate的话学Compass是非常容易的。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 大家可以到<a href="http://www.opensymphony.com/compass/download.action">http://www.opensymphony.com/compass/download.action</a>去下载最新的版本。2006年8月28日Compass 1.1 M1 发布，用的是Lucene2.0，现在讲的就是这个版本。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 虽然有人说Hibernate3.1以后版本自带了对Lucene的支持，Compass好像没用，但是只要看一下Hibernate源代码可以看出Hibernate对Lucene的支持很简陋，且不支持事务并且Hibernate3.2用的还是Lucene版本是Lucene1.4.3，所以说当做大的项目的时候Compass还是非常有必要的。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 还是先看个HelloWorld程序：（这里的测试功能的例子都是用的JUnit测试用例，为方便阅读异常全部抛出）</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一共4个文件Article.java， compass.cfg.xml，Article.cpm.xml，JUnit插入测试。</p>
<p>1.Article.java：</p>
<pre name="code" class="java">package org.li.compass;

import java.util.Date;

public class Article

{

    private long id;

    private String title;

    private String content;

    private Date publishDate;

    public String getContent()

    {

        return content;

    }

    public void setContent(String content)

    {

        this.content = content;

    }

    public Date getPublishDate()

    {

        return publishDate;

    }

    public void setPublishDate(Date publishDate)

    {

        this.publishDate = publishDate;

    }

    public String getTitle()

    {

        return title;

    }

    public void setTitle(String title)

    {

        this.title = title;

    }

    public long getId()

    {

        return id;

    }

    public void setId(long id)

    {

        this.id = id;

    }

}</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 上面就是一个Article的POJO类上面有文章题目，内容，发布时间，这里的id的compass必须的（有点和数据库一样了）。</p>
<p>2.compass.cfg.xml</p>
<pre name="code" class="xml">&lt;!DOCTYPE compass-core-configuration PUBLIC

    "-//Compass/Compass Core Configuration DTD 1.0//EN"

    "http://www.opensymphony.com/compass/dtd/compass-core-configuration.dtd"&gt;

&lt;compass-core-configuration&gt;

    &lt;compass&gt;

        &lt;setting name="compass.engine.connection"&gt;target/test&lt;/setting&gt;&lt;!-- 这里配置的是索引的相对路径 --&gt;

        &lt;mapping resource="org/li/compass/Article.cpm.xml"/&gt;&lt;!-- 这里是每个对象的映射文件 --&gt;

    &lt;/compass&gt;

&lt;/compass-core-configuration&gt;</pre>
<p>&nbsp;这是Compass的配置文件上面标明了索引目录和映射文件。映射好文件了就看看这个映射的什么吧</p>
<p>3. Article.cpm.xml</p>
<pre name="code" class="xml">&lt;!DOCTYPE compass-core-mapping PUBLIC 

    "-//Compass/Compass Core Mapping DTD 1.0//EN"

    "http://www.opensymphony.com/compass/dtd/compass-core-mapping.dtd"&gt;

&lt;compass-core-mapping package="org.li.compass"&gt;

    &lt;class name="Article" alias="article"&gt;

        &lt;!-- 这是必须有的 --&gt;

        &lt;id name="id"/&gt;

        &lt;!-- 你可以通过这个配置来在底层给这个对象加一个Field("type","java") --&gt;

        &lt;constant&gt;

            &lt;meta-data&gt;type&lt;/meta-data&gt;

            &lt;meta-data-value&gt;java&lt;/meta-data-value&gt;

        &lt;/constant&gt;

        &lt;!-- 配置一下属性 --&gt;

        &lt;property name="title"&gt;

            &lt;meta-data&gt;titleIndex&lt;/meta-data&gt;

        &lt;/property&gt;

        &lt;property name="content"&gt;

            &lt;meta-data&gt;contentIndex&lt;/meta-data&gt;

        &lt;/property&gt;

        &lt;property name="publishDate"&gt;

            &lt;meta-data&gt;publishDateIndex&lt;/meta-data&gt;

        &lt;/property&gt;

    &lt;/class&gt;

&lt;/compass-core-mapping&gt;</pre>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这个配置应该可以看的懂吧可能会有人问meta-data是干什么用的？？</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 它的值是作为底层Field的名字，如果没有配置的话Compass用$article/&hellip;来代替。而它的作用是配置对象的属性的储存形式，Compass就是读取它来new Field()的:</p>
<pre name="code" class="xml">&lt;!ELEMENT meta-data (
    #PCDATA
)&gt;
    &lt;!ATTLIST meta-data store (no|yes|compress) "yes"&gt;
    &lt;!ATTLIST meta-data index (no|tokenized|un_tokenized) "tokenized"&gt;
    &lt;!ATTLIST meta-data term-vector (no|yes|positions|offsets|positions_offsets) "no"&gt;
    &lt;!ATTLIST meta-data reverse (no|reader|string) "no"&gt;
    &lt;!ATTLIST meta-data analyzer CDATA #IMPLIED&gt;
    &lt;!ATTLIST meta-data exclude-from-all (true|false) #IMPLIED&gt;
    &lt;!ATTLIST meta-data converter CDATA #IMPLIED&gt;
    &lt;!ATTLIST meta-data format CDATA #IMPLIED&gt;
    &lt;!ATTLIST meta-data boost CDATA #IMPLIED&gt;</pre>
<p>&nbsp;4.JUnit插入测试</p>
<pre name="code" class="java">public void InsertCompass()

    {

CompassConfiguration comConfig = new CompassConfiguration().configure().addClass(Article.class);

        Compass com = comConfig.buildCompass();

        CompassSession comSession = com.openSession();

        CompassTransaction comTx = comSession.beginTransaction();

        

        Article article = new Article();

        article.setContent("Compass是第一个基于lucene的java开源框架");

        article.setTitle("学习Compass");

        article.setPublishDate(new Date());

        comSession.save(article);

        comTx.commit();

    }</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当大家看到这里的时候就看出来Compass和Hibernate太像了。如果会Hibernate的话，学Compass将是非常容易的。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 看看效果如何：</p>
<pre name="code" class="java">public void LoadCompass()

    {

        CompassConfiguration comConfig = new CompassConfiguration().configure().addClass(Article.class);

        Compass com = comConfig.buildCompass();

        CompassSession comSession = com.openSession();

        CompassTransaction comTx = comSession.beginTransaction();

        

        Article article = (Article)comSession.load(Article.class, 0);

        System.out.println(article.getTitle());

        System.out.println(article.getContent());

        System.out.println(article.getPublishDate());

    }</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 结果:</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 学习Compass</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Compass是第一个基于lucene的java开源框架</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Sat Sep 23 00:51:35 CST 2006</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注意：和其它的框架一样，Compass也是需要一定的配置的，而Compass的数据配置可分为Annotations，DTD验证的XML和Schema验证的XML。这里用的是dtd验证的XML配置。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们可以用Lucene做一下检测嘛</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JUnit测试用例：</p>
<pre name="code" class="java">public void TestArticle() throws ParseException, IOException

    {

        QueryParser queryParser = new QueryParser("titleIndex",new StandardAnalyzer());

        Query query = queryParser.parse("compass");

        IndexSearcher indexSearcher = new IndexSearcher("target/test/index/article");

        Hits hits = indexSearcher.search(query);

        for(int i=0;i&lt;hits.length();i++)

        {

            Document doc = hits.doc(i);

            System.out.println(doc.get("contentIndex"));//大家可以在这里设置个断点看一下doc里各个Field是什么。就会学到很多的东西

        }

}</pre>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://xiaofeng.javaeye.com/blog/194074#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></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 18 May 2008 14:46:57 +0800</pubDate>
        <link>http://xiaofeng.javaeye.com/blog/194074</link>
        <guid>http://xiaofeng.javaeye.com/blog/194074</guid>
      </item>
      <item>
        <title>Java上的PHP，两者共赢？</title>
        <author>hilliate</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://xiaofeng.javaeye.com">hilliate</a>&nbsp;
          链接：<a href="http://xiaofeng.javaeye.com/blog/187142" style="color:red;">http://xiaofeng.javaeye.com/blog/187142</a>&nbsp;
          发表时间: 2008年04月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Jerry Cuomo（IBM的WebSphere CTO）和Scott Ferguson（Resin Java Application Server及最近的Quercus PHP引擎）与我们一起讨论了PHP如何融入Java的世界。目前IBM在Java/PHP混合系统方面最直接的投入是Zero项目，一个开发中的新的Web框架，支持Groovy和PHP脚本语言。当被问到为何IBM选择在Project Zero项目里支持PHP，Jerry有些话要说： <br /><br />Jerry：三个词——敏捷性（Agility）、内容（Content）、训练（Educated）。是的，PHP是我们的ACE。 <br />敏捷性（Agility）。J2EE应用是为了“永久的价值”而优化的……也就是说，写出来的程序是打算要一直运行下去。PHP脚本是为了“在周五之前投入运行”而优化的。也就是说，PHP让你快速简洁地编写代码，这对于许多应景而生的应用是合适的。 <br />内容（Content）。我们叫它“剪贴式编程”。网上有不计其数的PHP资源。你很少需要从头开始编写什么东西。搜索，剪切，粘贴，你就可以收工了……（这又涉及到敏捷性）。 <br />训练（Educated）。PHP很容易自学。编写PHP脚本对很多人来说都非常容易，即使是没有受过正规计算机科学教育的人。例如，像内存管理和线程这种复杂的东西，在你编写PHP脚本的时候绝不会成为注意力的中心。而且就如我在上一点所说，大多数时候你都是在修改利用别人的代码。 <br />Caucho采取的途径与IBM不同。Project Zero看起来好像是一个Java/Groovy框架，只不过刚好也支持PHP语言。而Quercus，是能够与mod_php竞争的完整的PHP语言实现。它是一个令人印象深刻的实现。事实上整个PHP解释器都是用Java编写的，因此不仅能够提供原生的Java/PHP集成，还有效利用了JVM的强大能力来达到极高的效率和安全性。对于从技术的角度看，Java如何令Quercus脱颖而出，Scott如是说： <br /><br />Scott：Java平台的线程、缓存和池技术是Quercus成功的关键。大多数Quercus库的实现都只是对相应Java功能的包装。例如，数据库访问就是对JDBC的包装。因为Java平台已经提供了坚实的基础，Quercus不费吹灰之力就得到了那些强大的能力。 <br /><br />而且反射、内存管理、JDK 1.5 Annotation和动态编译/类装载，这些都是Quercus所需的。虽然我们不能像C PHP一样使用智能指针来编程，我们却可以获得干净的OO设计，并依赖Java去处理内存的问题。 <br /><br />当然还有运行分析（profiling）。Quercus自动从JVM的CPU和堆运行分析中得益。因为编译后的Quercus函数实际上就是Java方法，我们可以准确地从运行分析中看出哪一块代码运行得太慢或者消耗了太多内存。 <br />快速、轻量并且广泛接受的Web层框架一直是Java平台难以完成的目标，我们向Jerry和Scott两人都提出了同一个问题：他们投入于PHP运行时的领域，是否由于感觉到Java社区已经放弃了使用基于Java的框架来完成高效Web层开发，转而在这一层使用动态脚本语言。他们都认为我的提问夸大了弃用Java的趋势，他们如此描述使用Java和使用PHP之间的平衡： <br /><br />Jerry：“转移”和“放弃”的说法有点过了。我觉得应该说我们正“把Java提升到更高级的行政职位上”。Java自己赢得了这样的位置。这并不是一个非黑即白的问题。除了Java目前的角色，我相信它可以成为这些动态脚本语言的“系统编程”环境。就像Java与C/C++的关系。现在Java（以及JVM）需要成长（和退缩）来支持各种DSL。例如，当今的Java是为长期运行的应用和进程而优化的。DSL则是短命的，经常来来去去。 <br />Scott：我们不建议完全抛弃Java。Web应用框架底下的基础设施如Spring、JPA/Hibernate，工具如Coherence，测试框架如JUnit，Java在这些方面是无与伦比的，远胜过脚本世界中任何东西。除此之外，应用级缓存、服务、事件和线程这些不为人所见的东西用Java会好得多。如果你看看像Mediawiki（维基百科所用的程序）这样的PHP应用，可以明显地看出底层代码如果用Java编写会好很多。 <br /><br />Quercus/PHP的成功之处是在它的表现层，脚本可以满足许多特别要求灵活性的情况。Java表现框架如JSF、JSP/JSTL、Struts、Velocity，没有一个能达到完整的脚本语言的灵活性和库能力。许多框架，如JSP/JSTL，都是部分的语言实现。为什么不干脆用一个完整的脚本语言，再加上一个庞大的库呢？已经有巨大数量的网站证明了这种脚本语言的成功。 <br /><br />因此我们认为结合Java（用在后台、模型和底层服务），把PHP/Quercus用于表现层以及任何需要脚本的地方（如取代BPEL），会是最佳的选择。 <br />我们还问到如何比较PHP和其他语言，如Ruby和Groovy。我们请Scott告诉我们为什么他写了一个PHP而不是Ruby解释器？ <br /><br />Scott：我们希望选择一门已经在Web开发社区里证明了自身的语言，而PHP是占统治地位的语言。Ruby目前仍然是一门实验性的语言。Ruby语言虽然有很多令人喜爱之处，但也有一些问题。Ruby使用了一些高级语言结构如闭包和Continuation，从这个方面来说很像Scheme。我个人很喜欢这些特性，但我的经历告诉我很多程序员都会被这些东西吓倒，因此会损害接受程度。PHP就像BASIC，任何人都可以学会。我会捧Ruby的场，我希望它成功，但当我们必须选择如何分配有限的时间，我们不得不先让Ruby等等看。 <br />我们问Jerry是否认为PHP会继续成长，特别是在面临Ruby on Rails的竞争之下。我们还询问了PHP5中引入的面向对象是否让PHP更适合Project Zero这样的框架。最后，由于Project Zero同时支持Groovy和PHP，我们问Jerry一个新接触Project Zero并且不懂Groovy也不懂PHP的开发者，应该选择哪种语言： <br /><br />Jerry：PHP是和Ruby或者Groovy不一样的动态脚本语言……这话大概没错。不过，要想让世界上最受欢迎的应用（想想看Wordpress、PHPBB……）都用这些语言编写，它们还有很长的路要走。只要PHP应用还在发挥作用，就会有新的开发者学习PHP。考虑到大学生中流行的大多数工具都是用PHP写的，将会继续出现新一代的PHP程序员。 <br /><br />虽然如此，PHP是否会继续成长还不清楚……它已经很庞大了，而且还存在很多竞争者，它们的语法更加清晰更加简洁。到时候再看。 <br /><br />不过，（PHP语言有或没有OO特性）这并不是PHP被包括进Project Zero的原因。包括它是因为ACE。……如果你是一名Java程序员，应该从Groovy开始。Java程序员已经期盼了很久Project Zero所提供的那种敏捷特征。我们希望这对你“百利而无一害”。你既可以接着用Java，又可以做动态脚本编程。然而，如果你没有深厚的Java背景，或者你打算利用网上已经存在的资源——PHP是创造敏捷应用的好手段。
          <br/>
          <span style="color:red;">
            <a href="http://xiaofeng.javaeye.com/blog/187142#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></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 26 Apr 2008 20:24:25 +0800</pubDate>
        <link>http://xiaofeng.javaeye.com/blog/187142</link>
        <guid>http://xiaofeng.javaeye.com/blog/187142</guid>
      </item>
      <item>
        <title>spry，刚刚用，记下来一点</title>
        <author>hilliate</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://xiaofeng.javaeye.com">hilliate</a>&nbsp;
          链接：<a href="http://xiaofeng.javaeye.com/blog/185658" style="color:red;">http://xiaofeng.javaeye.com/blog/185658</a>&nbsp;
          发表时间: 2008年04月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>DW的spry，一直没试着用过，今天尝试了一下，还好啦。有一点需要现在记下来，搞了半天也没找到办法，就是做表单时候的密码确认的功能。很简单，需要拿一个文本框跟另外一个文本框的值进行比对，找来找去也没有找到spry上面怎么来弄。最后从网上找到了办法。首先，有两个文本框 password和repassword 分别添加spry验证文本域然后去代码试图，将原来的repassword的js代码（在页面最下方）改为如下： </p>
<pre name="code" class="js">var sprytextfield3 = new Spry.Widget.ValidationTextField("spryRePassWord", "custom", {validation: passwordTheSame,validateOn:["blur"]});</pre>
<p>&nbsp;</p>
<p>你的和我的可能不同在红色字体处，棕色字体处是我们要写的一点js代码，看来还是没有进化完全啊。 js代码如下：</p>
<pre name="code" class="js">var passwordTheSame = function(value, options){ 

var other_value = document.getElementById('passWord').value; 

if (value != other_value){ 
document.getElementById('error_repassword').innerHTML="请与密码保持一致" 
return false; 

} 
else{ 
document.getElementById('error_repassword').innerHTML="" 
return true; 
} 

}

</pre>
<p>&nbsp;<br />说明： error_repassword 是我写了一个 是用来写提示信息的。搞定。</p>
          <br/>
          <span style="color:red;">
            <a href="http://xiaofeng.javaeye.com/blog/185658#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></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 22 Apr 2008 22:20:57 +0800</pubDate>
        <link>http://xiaofeng.javaeye.com/blog/185658</link>
        <guid>http://xiaofeng.javaeye.com/blog/185658</guid>
      </item>
      <item>
        <title>编程和足球的关系，给一些尚不知未来的人</title>
        <author>hilliate</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://xiaofeng.javaeye.com">hilliate</a>&nbsp;
          链接：<a href="http://xiaofeng.javaeye.com/blog/184615" style="color:red;">http://xiaofeng.javaeye.com/blog/184615</a>&nbsp;
          发表时间: 2008年04月20日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          应该很多人爱玩实况或者足球经理一系列游戏吧，程序员里，曾经喜欢或者现在仍然喜欢足球的也不少吧，那这个话题就可以继续了。<br />    在坛子里经常看到这个小公司我该不该去类似的话，或者对未来的迷茫，或许我们换个角度来看，你能看的更清楚。<br />    好，我们假定：<br />    你，未来的程序员，是足球界的业余选手，现在想打职业比赛，正在找球队。<br />    如果你技术很烂，你会去足球学校或是球队的青训营锻炼培养（很多欧洲球员的成功法），或者踢野球让**教练突然发现你是个人才（很多巴西球员的成功法），那么现实中的你，或者可以北大青鸟一下？或者自己去买本书去练去，准备自己的技术基础。<br />    当你到了一定的时候，比如说毕业，比如说想去公司实习，你就应该出去找找合适的公司了，而各个球队俱乐部也是需要新人的，尤其是大俱乐部，他们有长期的人才梯对计划，而小俱乐部喜欢来球队就能上场踢球的人，很简单，因为他们没那么多闲钱养闲人，如果你报怨，那请你回青训营或者是继续回去踢野球去，有时候也是可以混到一点出场费的。至于刚刚成为新人的你，应该怎么去找俱乐部呢？首先你需要衡量自己的实力，第二你需要想一想以你的实力，以后能踢到什么样的联赛，是中超还是英超，这需要你自己去判断，这里我们先谈谈小球队和大球队的不同心态。<br />    小球队不会有那么长期的培养计划，你来了就是要上场的，而且一开始工资不会拿太高，毕竟是小球会，没有多少钱。但是在小球队你能锻炼地比较均衡，有可能你还得经常去替补一些你不熟的位置（像继海那样）。<br />    大球队会有长期的培养计划，有的大球队甚至跟一些小球队有些关系，可以把你租借给小球队去打比赛锻炼，而且大球队是每个球员的梦想（当然了，谁不想多赚点混好点啊，从这点来说，我一直支持国际米兰，呵呵），可是大球队的上场机会不是那么多，虽然培训很系统，可是你的职责相对单一，而且如果在你身上得不到回报，你会很快被抛弃，在这里出人头地可不容易，更衣室的关系你也得处理好。<br />    不管什么样的球队，其实适合你就好，而且你不用太着急，人这一辈子怎么着也有几次转会的机会，牛人如唐骏者，转会费10亿，比较惨的可能是自掏转会费（垫付违约金）。<br />    至于如何去找适合你的球队，我想大家也都玩过游戏，知道作为一个足球经理到底想要什么样的球员，可是很郁闷的地方是，招聘人的单位，也就是我们的每个足球经理，想法是不一样的，他们组织球队的目标和想法都是不一样的，而你到底要找什么样的球队呢？<br />    首先你要知道你哪方面比较强，是适合踢前锋还是中场还是后卫，我们也知道前锋中场后卫每种角色的要求不一样，这个你断不可弄错了，否则适合打前锋的你却弄成了守门员，着实不好。所以首先我们需要确定我们在公司里在项目团队里是成为哪种角色，你要做那种开发，是Java，c++还是.NET？<br />    第二，你得知道现在各个球队的情况，有的球队会在转会市场上声明，所以招聘会上我们能看到大大小小形形色色的企业；有的球队有持续的计划，所以我们经常看到很多公司招实习生，有实习生计划；当然有的球队不是那么缺人，而这时候咱就别硬往里挤了，公司很多，别非哪个不去，当你成功的那一天，有资本了再说。在这个阶段内，你应该到处去撒简历，网上投也好，招聘会上投也好，机会越多越好。这时候有很多的公司不会给你回复，很简单，你不符合他们的要求，他们要一个前腰，而你是后腰；他们要一个强力中锋，而你是一个成长中的强力中锋或者是影子前锋，这时候你不应该郁闷，你应该感谢他们没有浪费你更多的时间或是省下了你的简历复印费。<br />    第三，如果有多个电话打给你，说有意向，这时候你应该考察一下这几个俱乐部，到底是否符合你的发展，你是想接受青训营的再培训还是想上场踢球？你在乎你的薪水么？你在意以后经常性的一周双赛么？抑或者是这个俱乐部以球场上作恶为名，你能接受这个公司么？这你应该都考虑好，给自己一张白纸，把你想到的考察对象都写到纸上，一条一条比对他们的优势或者劣势，请亲戚朋友帮你参考，这都是必要的。<br />    第四，给公司回复，一般你会回复好几个公司，并准备面试，我们知道如果俱乐部想考察一个球员，试训是经常的，所以你得去俱乐部试训去，大概等于去面试吧，其实就是表现你的水平而已，第一二次的难免紧张，多试训几次你心态就好了，当然个人最喜欢的俱乐部是那种能激发你的水平那张，而不是制造一些压抑紧张的气氛那种。<br />    第五，签约，还好还好，没有过多可说的，有机会多看看劳动法，再看看你的合同里是不是有陷阱。<br />    个人感觉流程差不太多，本人现在在小球队呆着，虽然报着大球队的梦想，但是水平是不够的，努力是需要的。<br />    不过可能有些公司也喜欢那种能抵挡多面的人（例如继海），当球队缺人时你可以替补上，但是薪水拿的比较高的，足球生涯比较长的，不仅仅得有天赋，还得有你日复一日地努力，如果你生活糜烂成肥罗一样，估计也是会比较早退役的。<br />    希望大家都能找到适合自己的地方，希望大家拍砖
          <br/>
          <span style="color:red;">
            <a href="http://xiaofeng.javaeye.com/blog/184615#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></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 20 Apr 2008 18:09:29 +0800</pubDate>
        <link>http://xiaofeng.javaeye.com/blog/184615</link>
        <guid>http://xiaofeng.javaeye.com/blog/184615</guid>
      </item>
      <item>
        <title>CSS突然不能控制字体的大小，问题解决</title>
        <author>hilliate</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://xiaofeng.javaeye.com">hilliate</a>&nbsp;
          链接：<a href="http://xiaofeng.javaeye.com/blog/184338" style="color:red;">http://xiaofeng.javaeye.com/blog/184338</a>&nbsp;
          发表时间: 2008年04月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          给原来的页面增加了一点代码，加进去一个asp的cms的相关代码，结果加完之后，字号由原来的12px变为默认的那种难看的字体了&hellip;&hellip;找了许久，发现
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
这句话必须加到所有网页代码的最顶上，才不会出问题，都纳闷了
最后找来找去，找到了这个：http://www.it.com.cn/f/edu/079/26/482867.htm
具体内容转载如下：
XHTML头部Doctype声明必不可少
　　HTML遵循一定的规则。这些规则包含在一个文档类型定义（Document Type Definition）文件中，或者如大家所知的DTD。DTD是一个XML文档，解释了哪些标签、属性或值对于HTML的一个特定类型是有效的。每一个HTML版本，都有一个对应的DTD。现在你可能会问：&ldquo;所有这些和CSS又有什么关系呢？&rdquo;　　如果想让网页中的所有内容都在网页浏览器上正确、一致地显示，就得告诉网页浏览器你正使用HTML或者XHTML的哪个版本，包括一个网页开头处的文档类型声明（doctype declaration）是什么意思。这个文档类型声明是在HTML文件的第一行，不仅定义你正使用的HTML版本（比如HTML 4.01 Transitional），而且指向网页中适当的DTD文件。当键错文档声明时，你会使大部分浏览器进入一个叫怪异模式（Quirks Mode）（译注1）的警告状态。　　怪异模式（Quirks Mode）是浏览器制造商为使他们的软件运行起来就像大约1999年（Netscape 4和Internet Explorer 5时代）时的浏览器所采用的方法。如果一个现代浏览器遇到一张没有正确文档类型的网页，它就会以为：&ldquo;嗯，这张网页一定是很早很早以前用HTML编辑器写的。我得假装自己是一个真正很旧的浏览器来显示网页，就像那些bug重重的旧浏览器所显示的那样。&rdquo;这就是为什么当没有一个正确的文档类型时，你用CSS进行样式设置的可爱网页，可能看起来并不像它根据当前的标准所应该显示的样子。当你在浏览器上检测时，无意中用怪异模式（Quirks Mode）浏览到你的网页，你可能会停止尝试去修正与不正确的文档类型有关、而不是不正当使用HTML或者CSS所引起的显示问题。　　注意：想了解更多关于怪异模式的相关信息，请访问www.quirksmode.org/index. html?/css/quirksmode.html 和 http://hsivonen.iki.fi/doctype/。　　所幸的是，获得正确的文档类型很简单。你所要知道的就是正在使用哪个HTML版本。最可能的是，你已经用HTML 4创建了网页。你甚至可能已经开始给你的网站使用XHTML（见第5页）。　　目前最流行的HTML和XHTML的版本是HTML 4.01 Transitional和XHTML 1.0 Transitional。这些HTML类型仍然让你使用展示型的标签，如标签，在这方面还提供一个从旧版HTML到新版HTML的过渡：更严格的HTML和XHTML　　标签。虽然最好不要使用这些标签，但它们在Transitional版中仍然起作用，因此你可以根据自己的情况，逐步淘汰这些旧式标签。在严格版的HTML和XHTML中，有些旧式标签根本不起作用。　　注意：一般来说，HTML和XHTML的严格版均不接受仅使网页展现效果好看的标签和属性，如标签和一个段落的置中属性。它们也不接受一些曾经流行的属性，比如一个链接的目标属性&mdash;&mdash;让你在一个新窗口中打开链接。　　如果你正使用HTML 4.01 Transitional，就要在创建的每张网页的开头处键入下列文档类型声明：　　　　XHTML 1.0 Transitional的文档声明也与此相似，但它指向一个不同的DTD。给开始的标签添加一些代码来识别网页所用的语言，这也是个好主意，就像这样：　　　　　　注意：如果你正在给网页使用框架（frame），那么你就要给框架设置使用一个文档类型。请见W3C网站中正确的文档类型列表清单：www.w3.org/QA/ 2002/04/valid-dtd-list.html。　　如果这整个讨论正让你头疼且累得合不上眼，那么只要确保使用以上所列的正确的文档类型，并且始终将它放在HTML文件的第一行（恰好在标签的前面）就行了。如果你想要一个基本的模板，便于在创建HTML或者XHTML网页时使用，请访问本书的网站：www.sawmac.com/css/。事实上，使用正确文档类型来创建一个空白的HTML网页并保存在你的计算机上，是一个好主意。这样每当你需要创建一个新网页的时候就从它那里进行拷贝。使用一个HTML检验器，就像在第22页方框中所述的那样，也是确保你正确键入文档类型声明的一个好办法。　　注意：大部分可视的网页工具如Dreamweaver、GoLive和FrontPage，在创建一张新网页时都会自动添加一个文档类型声明。许多智能型的HTML文本编辑器都有添加文档类型的快捷方式。
          <br/>
          <span style="color:red;">
            <a href="http://xiaofeng.javaeye.com/blog/184338#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></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 19 Apr 2008 09:59:38 +0800</pubDate>
        <link>http://xiaofeng.javaeye.com/blog/184338</link>
        <guid>http://xiaofeng.javaeye.com/blog/184338</guid>
      </item>
      <item>
        <title>Vector 和 ArrayList的不同(转)</title>
        <author>hilliate</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://xiaofeng.javaeye.com">hilliate</a>&nbsp;
          链接：<a href="http://xiaofeng.javaeye.com/blog/183440" style="color:red;">http://xiaofeng.javaeye.com/blog/183440</a>&nbsp;
          发表时间: 2008年04月16日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>　　有的时候 Vector更好一些;有的时候ArrayList 更好一些;有的时候你一个也不想用。但愿，你不是在期望一个简单明了的答案，因为答案因你在用他们做什么而定。下面是要考虑的四个方面：<br />　　<br />　　API<br />　　<br />　　同步-Synchronization<br />　　<br />　　数据增长-Data growth<br />　　<br />　　使用方法-Usage patterns<br />　　<br />　　让我一个一个来解释吧。<br />　　<br />　　<strong>API</strong><br />　　<br />　　在The Java Programming Language (Addison-Wesley, June 2000) 中Ken Arnold, James Gosling, 和 David Holmes 是这样描述Vector的，它是更ArrayList类似的一个东西，所以从API的观点来看，它们俩是很相似的。但是，它们之间还是有些微的差别的。<br />　　<br />　　<strong>Synchronization</strong><br />　　<br />　　Vectors是可同步化的，意思就是说，任何操作Vector的内容的方法都是线程安全的，相反的，另一方面，ArrayList是不可同步化的，所以也不是线程安全的。如果你知道了这些的话，你就会发现，Vector的同步会让它在性能发方面有一些小问题。所以，如果你不需要线程安全的话，那么就使用ArrayList吧。为什么要为没有必要的同步付出代价呢？<br />　　<br />　　<strong>Data growth</strong><br />　　<br />　　实际上，不管是ArrayList还是Vector，在它们内部都是使用一个Array来保存数据的。编程过程中，在使用它们任何一个的时候，你都需要记住这一点。你在往一个ArrayList或者Vector里插入一个元素的时候，如果内部数组空间不够了，这个对象(译者按：指的是你使用的ArrayList或者Vector)就要扩展它的大小。Vector在默认情况下是产生一个双倍大小，而ArrayList增加50%的大小。只要你合理的使用这些类，你就可以结束你在增加新的元素的时候所付出的性能代价。把对象(译者按：指的是你使用的ArrayList或者Vector)的初始化容量指定为你编程过程中所能用到的最大的容量总是最好的办法。仔细的指定容量，你可以避免以后改变内部Array容量，所要付出的代价。如果你并不知道到底有多少个数据，当是你知道数据的增长率，Vector确实有一点点优势，因为你可以指定增加值(译者按，如果没有猜错的话，作者说的方法应该是setSize(int newSize)　Sets the size of this vector.)。<br />　　<br />　　<strong>Usage patterns</strong><br />　　<br />　　ArrayList和Vector在从指定位置取得元素，从容器的末尾增加和删除元素都非常的有效，所有的这些操作都能在一个常数级的时间(O(1))内完成。但是从一个其他的位置增加和删除一个元素就显得颇为费时，差不多需要的时间为O(n-i)，这里的n代表元素个数，i代表要增加和删除的元素所在的位置。这些操作需花费更多的时间，因为你需要挨个移动i和更高位置的元素。那么，以上这些到底说明了什么呢？<br />　　<br />　　这意味着，如果你取得一个元素，或者从数组末尾增加或删除一个元素的话，随便你使用Vector和ArrayList。如果你想要对数组内容做其他操作的话，那么就为自己好另一个容器吧。比喻说，LinkedList可以在常数级时间(O(1))内为任意一个位置的元素增加和删除。但是，取得一个元素，会稍微慢一点，时间要用O(i) ，这个i是元素的位置。通过ArrayList也是很简单的，因为你可以简单使用一个索引，而不是构造一个iterator 。LinkedList也为每个插入的元素建立一个内部对象。所以，你也必须知道，同时产生了垃圾对象。<br />　　<br />　　最后，Practical Java (Addison-Wesley, Feb. 2000) Peter Haggar 里的&ldquo;实践41&ldquo;建议你使用一个普通的原始的数组来代替Vector和ArrayListe，特别是对效率优先的代码来说。通过使用数组(array)，你可以避免同步，额外的方法调用，非理想化的大小改变。你付出的只是额外的开发时间。</p>
          <br/>
          <span style="color:red;">
            <a href="http://xiaofeng.javaeye.com/blog/183440#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></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 16 Apr 2008 16:35:56 +0800</pubDate>
        <link>http://xiaofeng.javaeye.com/blog/183440</link>
        <guid>http://xiaofeng.javaeye.com/blog/183440</guid>
      </item>
      <item>
        <title>Vector、ArrayList和List的异同(转)</title>
        <author>hilliate</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://xiaofeng.javaeye.com">hilliate</a>&nbsp;
          链接：<a hr