<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>半人马</title>
    <description></description>
    <link>http://centaur.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>dwr作为数据源的extjs grid crud解决方案</title>
        <author>半人马</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://centaur.javaeye.com">半人马</a>&nbsp;
                    链接：<a href="http://centaur.javaeye.com/blog/122815" style="color:red;">http://centaur.javaeye.com/blog/122815</a>&nbsp;
          发表时间: 2007年09月11日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <a href="http://extjs.com/forum/showthread.php?t=5586">这里</a>是前人的伟大成果。用了以后不太爽，主要问题在ListRangeReader，既然已经要求服务端按照自己的要求组装数据了，为什么还要在客户端做这许多数据解析重组的工作？于是自己做了一个略显干净的实现。<br />
extjs grid所要求的datastore实际上是这样格式的对象：<br />
<div class="code_title">js 代码</div>
<div class="dp-highlighter">
<ol class="dp-c" start="1">
    <li class="alt"><span><span>{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;success:&nbsp;<span class="keyword">true</span><span>&nbsp;or&nbsp;</span><span class="keyword">false</span><span>,&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;records:&nbsp;当前页中的数据项,&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;totalRecords:所有数据总数&nbsp;&nbsp;</span></li>
    <li class="alt"><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<br />
其中的records的每一项为Ext.data.Record类型，这个类型担负着与grid交互的责任，但是其数据部分是简单的：<br />
<div class="code_title">js 代码</div>
<div class="dp-highlighter">
<ol class="dp-c" start="1">
    <li class="alt"><span><span>{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;id:&nbsp;数据对象的id;&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;data:&nbsp;真实的数据对象;&nbsp;&nbsp;</span></li>
    <li class=""><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<br />
我们先在服务器端按照以上格式把数据组装好。首先是Record<br />
<table cellspacing="1" border="1" align="" height="460" summary="" cellpadding="1" width="434">
    <caption>ExtRecord.java</caption>
    <tbody>
        <tr>
            <td>@DataTransferObject<br />
            public class ExtRecord<t> {<br />
            &nbsp;&nbsp;&nbsp; long id;<br />
            &nbsp;&nbsp;&nbsp; T data;<br />
            <br />
            <br />
            &nbsp;&nbsp;&nbsp; public ExtRecord(long id, T obj) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.id = id;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.data = obj;<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; public long getId() {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return id;<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; public void setId(long id) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.id = id;<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; public T getData() {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return data;<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; public void setData(T data) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.data = data;<br />
            &nbsp;&nbsp;&nbsp; }<br />
            }</t></td>
        </tr>
    </tbody>
</table>
之后是datastore<br />
<table cellspacing="1" border="1" align="left" summary="" cellpadding="1" width="200">
    <caption>ExtDataStore.java</caption>
    <tbody>
        <tr>
            <td>@DataTransferObject<br />
            public interface ExtDataStore<t> {<br />
            &nbsp;&nbsp;&nbsp; @RemoteProperty<br />
            &nbsp;&nbsp;&nbsp; public boolean isSuccess();<br />
            &nbsp;&nbsp;&nbsp; @RemoteProperty<br />
            &nbsp;&nbsp;&nbsp; public List<extrecord><t>&gt; getRecords();<br />
            &nbsp;&nbsp;&nbsp; @RemoteProperty<br />
            &nbsp;&nbsp;&nbsp; public int getTotalRecords();<br />
            }<br />
            </t></extrecord></t></td>
        </tr>
    </tbody>
</table>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
如果没有特殊要求，使用缺省实现就行了<br />
<table cellspacing="1" border="1" align="left" height="416" summary="" cellpadding="1" width="601">
    <caption>DefaultExtDataStore.java</caption>
    <tbody>
        <tr>
            <td>public class DefaultExtDataStore<t> implements ExtDataStore<t>{<br />
            &nbsp;&nbsp;&nbsp; boolean success;<br />
            &nbsp;&nbsp;&nbsp; List<extrecord><t>&gt; records;<br />
            &nbsp;&nbsp;&nbsp; int totalRecords;<br />
            <br />
            <br />
            &nbsp;&nbsp;&nbsp; public boolean isSuccess() {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return success;<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; public void setSuccess(boolean success) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.success = success;<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; public List<extrecord><t>&gt; getRecords() {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return records;<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; public void setRecords(List<extrecord><t>&gt; records) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.records = records;<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; public int getTotalRecords() {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return totalRecords;<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; public void setTotalRecords(int totalRecords) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.totalRecords = totalRecords;<br />
            &nbsp;&nbsp;&nbsp; }<br />
            }<br />
            </t></extrecord></t></extrecord></t></extrecord></t></t></td>
        </tr>
    </tbody>
</table>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
定义一个dwr service模板<br />
<table cellspacing="1" border="1" align="" height="711" summary="" cellpadding="1" width="663">
    <tbody>
        <tr>
            <td>public abstract class ExtDWRService&lt;T, M extends HibernateEntityDao&lt;T&gt;&gt; {<br />
            &nbsp;&nbsp;&nbsp; M manager;<br />
            <br />
            &nbsp;&nbsp;&nbsp; protected void setManager(M manager) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.manager = manager;<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; protected ExtDataStore&lt;T&gt; list(int start, int limit, String sort) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DefaultExtDataStore&lt;T&gt; result = new DefaultExtDataStore&lt;T&gt;();<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result.setSuccess(true);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List&lt;T&gt; all = manager.getAll();<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result.setTotalRecords(all.size());<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List&lt;ExtRecord&lt;T&gt;&gt; records = new ArrayList&lt;ExtRecord&lt;T&gt;&gt;();<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(T item : all.subList(start,<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Math.min(start+limit, all.size()))){<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; records.add(new ExtRecord&lt;T&gt;(<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Long.valueOf(BeanUtils.getProperty(item, &quot;id&quot;)), item));<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result.setRecords(records);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return result;<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; protected void update(long id, T newValues) throws IllegalAccessException, InvocationTargetException {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T oldValues = manager.get(id);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BeanUtils.setProperty(newValues, &quot;id&quot;, id);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; org.springside.core.utils.BeanUtils.copyProperties(oldValues, newValues);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; manager.save(oldValues);<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; protected T load(long id){<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return manager.get(id);<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; protected void add(T newValues) throws IllegalAccessException, InvocationTargetException, InstantiationException {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T newObj = (T) newValues.getClass().newInstance();<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; org.springside.core.utils.BeanUtils.copyProperties(newObj, newValues);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; manager.save(newObj);<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; protected void del(long[] ids){<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(long id: ids){<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; manager.removeById(id);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            }</td>
        </tr>
    </tbody>
</table>
<br />
这里顺便给出一个具体service实现的例子供参考<br />
<table cellspacing="1" border="1" align="" height="491" summary="" cellpadding="1" width="655">
    <tbody>
        <tr>
            <td>public class AdvPositionService extends ExtDWRService&lt;AdvPosition, AdvPositionManager&gt; {<br />
            &nbsp;&nbsp;&nbsp; public void setAdvPositionManager(AdvPositionManager advPositionManager) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.setManager(advPositionManager);<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; @RemoteMethod<br />
            &nbsp;&nbsp;&nbsp; public ExtDataStore&lt;AdvPosition&gt; list(int start, int limit, String sort) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return super.list(start, limit, sort);&nbsp;&nbsp;&nbsp; <br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; @RemoteMethod<br />
            &nbsp;&nbsp;&nbsp; public void add(AdvPosition newValues) throws IllegalAccessException, InvocationTargetException, InstantiationException {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super.add(newValues);<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; @RemoteMethod<br />
            &nbsp;&nbsp;&nbsp; public void update(long id, AdvPosition newValues) throws IllegalAccessException, InvocationTargetException {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super.update(id, newValues);<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            <br />
            &nbsp;&nbsp;&nbsp; @RemoteMethod<br />
            &nbsp;&nbsp;&nbsp; public void del(long[] ids) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super.del(ids);<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; @RemoteMethod<br />
            &nbsp;&nbsp;&nbsp; public AdvPosition load(long id) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return super.load(id);<br />
            &nbsp;&nbsp;&nbsp; }<br />
            }</td>
        </tr>
    </tbody>
</table>
<br />
以上是服务端要做的事情。<br />
客户端实现DWRReader（DWRProxy不变）替代ListRangeReader。<br />
<div class="code_title">js 代码</div>
<div class="dp-highlighter">
<ol class="dp-c" start="1">
    <li class="alt"><span><span>Ext.data.DWRReader&nbsp;=&nbsp;</span><span class="keyword">function</span><span>()&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;Ext.data.DWRReader.superclass.constructor.call(<span class="keyword">this</span><span>,&nbsp;</span><span class="keyword">null</span><span>,&nbsp;[]);&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>Ext.extend(Ext.data.DWRReader,&nbsp;Ext.data.DataReader,&nbsp;{&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;read:&nbsp;<span class="keyword">function</span><span>(response)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">var</span><span>&nbsp;recordType&nbsp;=&nbsp;</span><span class="keyword">this</span><span>.recordType;&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">var</span><span>&nbsp;records&nbsp;=&nbsp;[];&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>&nbsp;(</span><span class="keyword">var</span><span>&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;response.records.length;&nbsp;i++)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">var</span><span>&nbsp;record&nbsp;=&nbsp;response.records[i]&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;records[records.length]&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;recordType(record.data,&nbsp;record.id);&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.records&nbsp;=&nbsp;records;&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;response;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>})&nbsp;&nbsp;</span></li>
</ol>
</div>
这样dataStore的初始化就很简单了<br />
<div class="code_title">js 代码</div>
<div class="dp-highlighter">
<ol class="dp-c" start="1">
    <li class="alt"><span><span class="keyword">function</span><span>&nbsp;init_dataStore()&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;dataStore&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;Ext.data.Store({&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy:&nbsp;<span class="keyword">new</span><span>&nbsp;Ext.data.DWRProxy(AdvPositionService.list,&nbsp;</span><span class="keyword">true</span><span>),&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;reader:&nbsp;<span class="keyword">new</span><span>&nbsp;Ext.data.DWRReader()&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;});&nbsp;&nbsp;</span></li>
    <li class=""><span>}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>init_dataStore()&nbsp;&nbsp;</span></li>
    <li class="alt"><span>dataStore.load({params:{start:0,&nbsp;limit:myPageSize}});&nbsp;&nbsp;</span></li>
</ol>
</div>
<br />
最后给几条友情提示：<br />
<br />
1. 增删改的操作与grid没有多大关系，可以参考原文自行实现。需要提醒的是，原文中的代码有比较严重的bug，会导致每次添加和修改操作都新建一个对话框实例<br />
2. 以上的java代码使用了SpringSide和apache commons BeanUtils的部分功能，请自行集成，这些对本方案不是必需的，重要的是领会精神<br />
3. 请为你的model声明Converter，另外，dwr的EnumConverter有bug，需要类似于StringConverter在ConvertOutboundData中做encoding<br />
4. 由于dwr的bug，使用本方案有时会出现Warning multiple matching methods. Using first match.的警告，不影响系统运行<br />
5. 总体来说，dwr的使用能够让extjs的代码干净一些，extjs+dwr+spring是我推荐的组合，前提是你有时间和精力去玩儿javascript的诡异语法<br />
6. javaeye的html编辑器会吞掉java代码中的范型，另外草稿第二次保存会丢失我的数据。
          <br/><br/>
          <span style="color:red;">
            <a href="http://centaur.javaeye.com/blog/122815#comments" style="color:red;">已有 <strong>7</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 11 Sep 2007 10:43:39 +0800</pubDate>
        <link>http://centaur.javaeye.com/blog/122815</link>
        <guid>http://centaur.javaeye.com/blog/122815</guid>
      </item>
          <item>
        <title>小练习一则:将.srt格式的视频字幕文件中字幕向前或向后推移一段时间</title>
        <author>半人马</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://centaur.javaeye.com">半人马</a>&nbsp;
                    链接：<a href="http://centaur.javaeye.com/blog/110473" style="color:red;">http://centaur.javaeye.com/blog/110473</a>&nbsp;
          发表时间: 2007年08月09日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          .srt字幕格式如下：<br />
<table cellspacing="1" border="1" align="" height="218" summary="" cellpadding="1" width="200">
    <tbody>
        <tr>
            <td>1<br />
            00:00:48,860 --&gt; 00:00:51,400<br />
            站好，你不喜欢你的工作吗？<br />
            <br />
            2<br />
            00:01:00,160 --&gt; 00:01:01,540<br />
            食物<br />
            <br />
            3<br />
            00:01:06,090 --&gt; 00:01:08,090<br />
            你要去哪里？<br />
            <br />
            .......</td>
        </tr>
    </tbody>
</table>
<br />
ruby代码如下：<br />
<div class="code_title">ruby 代码</div>
<div class="dp-highlighter">
<div class="bar">&nbsp;</div>
<ol class="dp-rb" start="1">
    <li class="alt"><span><span class="comment">#&nbsp;param:&nbsp;time_str&nbsp;:&nbsp;string&nbsp;with&nbsp;&quot;00:01:08,123&quot;&nbsp;like&nbsp;format</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span><span class="comment">#&nbsp;param:&nbsp;offset&nbsp;:&nbsp;int,&nbsp;seconds&nbsp;to&nbsp;shift&nbsp;ahead</span><span>&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span><span class="keyword">def</span><span>&nbsp;offset(time_str,&nbsp;offset)&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;new_time&nbsp;=&nbsp;<span class="builtin">Time</span><span>.parse(time_str)&nbsp;-&nbsp;offset&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;format(<span class="string">&quot;%02d:%02d:%02d,%03d&quot;</span><span>,&nbsp;new_time.hour,&nbsp;new_time.min,&nbsp;new_time.sec,&nbsp;new_time.usec/1000)&nbsp;&nbsp;</span></span></li>
    <li class=""><span><span class="keyword">end</span><span>&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span><span class="keyword">def</span><span>&nbsp;convert(src_file_path,&nbsp;dst_file_path,&nbsp;offset)&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;open(dst_file_path,&nbsp;<span class="string">&quot;w&quot;</span><span>)&nbsp;</span><span class="keyword">do</span><span>&nbsp;</span><span class="variable">|dst_file</span><span>|&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;open(src_file_path,&nbsp;<span class="string">&quot;r&quot;</span><span>).each_line&nbsp;</span><span class="keyword">do</span><span>&nbsp;</span><span class="variable">|line</span><span>|&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;line.include?(</span><span class="string">&quot;&nbsp;--&gt;&nbsp;&quot;</span><span>)&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new_line&nbsp;=&nbsp;line.split(<span class="string">&quot;&nbsp;--&gt;&nbsp;&quot;</span><span>).collect{&nbsp;</span><span class="variable">|time_str</span><span>|&nbsp;offset(time_str,&nbsp;offset)}.join(</span><span class="string">&quot;&nbsp;--&gt;&nbsp;&quot;</span><span>)&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dst_file.puts&nbsp;new_line&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;<span class="string">&quot;line&nbsp;#{line}&nbsp;converted&nbsp;to&nbsp;#{new_line}&quot;</span><span>&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">else</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dst_file.puts&nbsp;line&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">end</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">end</span><span>&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;<span class="keyword">end</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span><span class="keyword">end</span><span>&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>convert&nbsp;<span class="string">&quot;c:\\src.srt&quot;</span><span>,&nbsp;</span><span class="string">&quot;c:\\dst.srt&quot;</span><span>,&nbsp;90&nbsp;&nbsp;</span></span></li>
</ol>
</div>
          <br/><br/>
          <span style="color:red;">
            <a href="http://centaur.javaeye.com/blog/110473#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 09 Aug 2007 09:17:40 +0800</pubDate>
        <link>http://centaur.javaeye.com/blog/110473</link>
        <guid>http://centaur.javaeye.com/blog/110473</guid>
      </item>
          <item>
        <title>rails, 跨越三个Request的flash数据</title>
        <author>半人马</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://centaur.javaeye.com">半人马</a>&nbsp;
                    链接：<a href="http://centaur.javaeye.com/blog/92779" style="color:red;">http://centaur.javaeye.com/blog/92779</a>&nbsp;
          发表时间: 2007年06月21日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          关于flash中数据的生命周期，标准的说法是&ldquo;写入flash中的数据将在下一个request处理完毕时清除&rdquo;，但是如果在before_filter中将数据写入flash，则该数据的生命周期将跨越三个request，如下面的controller:<br />
<div class="code_title">ruby 代码</div>
<div class="dp-highlighter">
<div class="bar">&nbsp;</div>
<ol class="dp-rb" start="1">
    <li class="alt"><span><span>before_filter&nbsp;</span><span class="symbol">:redirect_filter</span><span>,&nbsp;</span><span class="symbol">:only</span><span>&nbsp;=&gt;&nbsp;</span><span class="symbol">:test_flash</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span><span class="keyword">def</span><span>&nbsp;redirect_filter&nbsp; <br />
    </span></span></li>
    <li class=""><span><span>&nbsp;&nbsp;&nbsp; flash[:written_by_filter]='xyz'<br />
    </span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;redirect_to&nbsp;<span class="symbol">:action</span><span>=&gt;</span><span class="symbol">:test_flash_dest</span><span>&nbsp;</span><span class="keyword">and</span><span>&nbsp;</span><span class="keyword">return</span><span>&nbsp;</span><span class="keyword">false</span><span>&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span><span class="keyword">end</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span><span class="keyword">def</span><span>&nbsp;test_flash&nbsp;&nbsp;</span></span></li>
    <li class=""><span><span class="keyword">end</span><span>&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span><span class="keyword">def</span><span>&nbsp;test_flash_dest&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span><span class="keyword">end</span><span>&nbsp;&nbsp;</span></span></li>
</ol>
</div>
测试页面 test_flash_dest.rhtml如下：<br />
<div class="code_title">ruby 代码</div>
<div class="dp-highlighter">
<div class="bar">&nbsp;</div>
<ol class="dp-rb" start="1">
    <li class="alt"><span><span>&lt;div&gt;flash[</span><span class="symbol">:written_by_filter</span><span>]=&lt;%=&nbsp;flash[</span><span class="symbol">:written_by_filter</span><span>]&nbsp;%&gt;&lt;/div&gt;&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<br />
我们用浏览器访问test_flash action，会被重定向到test_flash_dest并显示&quot;<font color="#0000ff"><strong>flash[:written_by_filter]=xyz</strong></font>&quot;，这时我们刷新一下，页面上仍旧显示&ldquo;<font color="#0000ff"><strong>flash[:written_by_filter]=xyz</strong></font>&rdquo;，再次刷新时才显示&ldquo;<font color="#0000ff"><strong>flash[:written_by_filter]=</strong></font>&rdquo;。<br />
<br />
我不知道这是不是rails的bug，只是第一次发现这种行为时还是吃惊了一把。猜想rails是把调用before_filter的request及redirect_to的request视作同一个request，因为将上面代码中的
<div class="code_title">ruby 代码</div>
<div class="dp-highlighter">
<div class="bar">&nbsp;</div>
<ol class="dp-rb" start="1">
    <li class="alt"><span><span>flash[</span><span class="symbol">:written_by_filter</span><span>]&nbsp;=&nbsp;'xyz'&nbsp;&nbsp;</span></span></li>
</ol>
</div>
改为
<div class="code_title">ruby 代码</div>
<div class="dp-highlighter">
<div class="bar">&nbsp;</div>
<ol class="dp-rb" start="1">
    <li class="alt"><span><span>flash.now[</span><span class="symbol">:written_by_filter</span><span>]&nbsp;=&nbsp;'xyz'&nbsp;&nbsp;</span></span></li>
</ol>
</div>
则'xyz'数据能够如我们希望的那样仅跨越两个request
          <br/><br/>
          <span style="color:red;">
            <a href="http://centaur.javaeye.com/blog/92779#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 21 Jun 2007 15:01:24 +0800</pubDate>
        <link>http://centaur.javaeye.com/blog/92779</link>
        <guid>http://centaur.javaeye.com/blog/92779</guid>
      </item>
          <item>
        <title>小练习一则</title>
        <author>半人马</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://centaur.javaeye.com">半人马</a>&nbsp;
                    链接：<a href="http://centaur.javaeye.com/blog/76323" style="color:red;">http://centaur.javaeye.com/blog/76323</a>&nbsp;
          发表时间: 2007年04月30日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          JBoss Seam 1.2.1GA的发行包的src里，有一些文件中有莫名其妙的0xA0字符，本来想用shell搞定的，结果搞了半天也没有用sed弄出完整的解决方案，最后只好用Java语言写了，顺带着也练练groovy和ruby.<br />
<br />
最初的Java代码是这样的：
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar">&nbsp;</div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span class="keyword">import</span><span>&nbsp;java.io.*;&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;Wash&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;main(String[]&nbsp;args)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File&nbsp;root&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;File(</span><span class="string">&quot;c:/ProgramFiles/jboss-seam-1.2.1.GA/src&quot;</span><span>);&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wash(<span class="keyword">new</span><span>&nbsp;File(</span><span class="string">&quot;c:/temp/seamsrc&quot;</span><span>));&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">private</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;washFile(File&nbsp;file)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;IOException&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;path&nbsp;=&nbsp;file.getAbsolutePath();&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span class="string">&quot;Washing&nbsp;file:&nbsp;&quot;</span><span>&nbsp;+&nbsp;path);&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File&nbsp;temp&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;File(path&nbsp;+&nbsp;</span><span class="string">&quot;.bak&quot;</span><span>);&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp.createNewFile();&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileInputStream&nbsp;in&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;FileInputStream(file);&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileOutputStream&nbsp;out&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;FileOutputStream(temp);&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">byte</span><span>&nbsp;bbyte;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">boolean</span><span>&nbsp;modified&nbsp;=&nbsp;</span><span class="keyword">false</span><span>;&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">while</span><span>&nbsp;((bbyte&nbsp;=&nbsp;(</span><span class="keyword">byte</span><span>)&nbsp;in.read())&nbsp;!=&nbsp;-</span><span class="number">1</span><span>)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;(bbyte&nbsp;!=&nbsp;(</span><span class="keyword">byte</span><span>)&nbsp;</span><span class="number">0xa0</span><span>)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.write(bbyte);&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="keyword">else</span><span>&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;modified&nbsp;=&nbsp;<span class="keyword">true</span><span>;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;in.close();&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.close();&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;(modified)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;file.delete();&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp.renameTo(<span class="keyword">new</span><span>&nbsp;File(path));&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="keyword">else</span><span>&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp.delete();&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">private</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;washDir(File&nbsp;dir)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;IOException&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>&nbsp;(File&nbsp;file&nbsp;:&nbsp;dir.listFiles())&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;(file.isDirectory())&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;washDir(file);&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="keyword">else</span><span>&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;washFile(file);&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
想了想washFile和washDir可以合并，于是refactor了一下，成为这样<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar">&nbsp;</div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span class="keyword">import</span><span>&nbsp;java.io.*;&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;Wash&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;main(String[]&nbsp;args)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wash(<span class="keyword">new</span><span>&nbsp;File(</span><span class="string">&quot;c:/ProgramFiles/jboss-seam-1.2.1.GA/src&quot;</span><span>));&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">private</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;wash(File&nbsp;file)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;(file.isFile())&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;path&nbsp;=&nbsp;file.getAbsolutePath();&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.print(<span class="string">&quot;Washing&nbsp;file:&nbsp;&quot;</span><span>&nbsp;+&nbsp;path+</span><span class="string">&quot;&nbsp;...&quot;</span><span>);&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File&nbsp;temp&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;File(path&nbsp;+&nbsp;</span><span class="string">&quot;.bak&quot;</span><span>);&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileInputStream&nbsp;in&nbsp;=&nbsp;<span class="keyword">null</span><span>;&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileOutputStream&nbsp;out&nbsp;=&nbsp;<span class="keyword">null</span><span>;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">boolean</span><span>&nbsp;modified&nbsp;=&nbsp;</span><span class="keyword">false</span><span>;&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">try</span><span>&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp.createNewFile();&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;in&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;FileInputStream(file);&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;FileOutputStream(temp);&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">byte</span><span>&nbsp;bbyte;&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">while</span><span>&nbsp;((bbyte&nbsp;=&nbsp;(</span><span class="keyword">byte</span><span>)&nbsp;in.read())&nbsp;!=&nbsp;-</span><span class="number">1</span><span>)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;(bbyte&nbsp;!=&nbsp;(</span><span class="keyword">byte</span><span>)&nbsp;</span><span class="number">0xa0</span><span>)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.write(bbyte);&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="keyword">else</span><span>&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;modified&nbsp;=&nbsp;<span class="keyword">true</span><span>;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="keyword">catch</span><span>&nbsp;(IOException&nbsp;e)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.exit(-<span class="number">1</span><span>);&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="keyword">finally</span><span>&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">try</span><span>&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">assert</span><span>&nbsp;(in&nbsp;!=&nbsp;</span><span class="keyword">null</span><span>&nbsp;&amp;&amp;&nbsp;out&nbsp;!=&nbsp;</span><span class="keyword">null</span><span>);&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;in.close();&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.close();&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="keyword">catch</span><span>&nbsp;(IOException&nbsp;e)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;(modified)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;file.delete();&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp.renameTo(<span class="keyword">new</span><span>&nbsp;File(path));&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span class="string">&quot;File&nbsp;&quot;</span><span>+file.getAbsolutePath()+</span><span class="string">&quot;&nbsp;washed.&quot;</span><span>);&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="keyword">else</span><span>&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span class="string">&quot;Not&nbsp;modified,&nbsp;removing&nbsp;temp&nbsp;file&nbsp;&quot;</span><span>+temp.getAbsolutePath());&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp.delete();&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="keyword">else</span><span>&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>&nbsp;(File&nbsp;child&nbsp;:&nbsp;file.listFiles())&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wash(child);&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<br />
下面是groovy的版本 ：<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar">&nbsp;</div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span>wash&nbsp;=&nbsp;{&nbsp;dir&nbsp;-&gt;&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;dir.eachFile&nbsp;{&nbsp;child&nbsp;-&gt;&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>(child.isFile()){&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;path&nbsp;=&nbsp;child.absolutePath&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print&nbsp;<span class="string">&quot;washing&nbsp;file&nbsp;&quot;</span><span>+path+</span><span class="string">&quot;...&quot;</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;File(path+</span><span class="string">&quot;.bak&quot;</span><span>)&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;modified&nbsp;=&nbsp;<span class="keyword">false</span><span>;&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp.withOutputStream&nbsp;{&nbsp;outputStream&nbsp;-&gt;&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;child.eachByte{&nbsp;bbyte&nbsp;-&gt;&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>(bbyte&nbsp;!=&nbsp;(</span><span class="keyword">byte</span><span>)</span><span class="number">0xa0</span><span>){&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;outputStream.write(bbyte)&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="keyword">else</span><span>&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;modified&nbsp;=&nbsp;<span class="keyword">true</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>(modified){&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;child.delete()&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp.renameTo(<span class="keyword">new</span><span>&nbsp;File(path))&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;println(<span class="string">&quot;File&nbsp;&quot;</span><span>+path&nbsp;+</span><span class="string">&quot;&nbsp;washed.&quot;</span><span>)&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="keyword">else</span><span>&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;println(<span class="string">&quot;Not&nbsp;modified,&nbsp;removing&nbsp;temp&nbsp;file&nbsp;&quot;</span><span>+temp.absolutePath)&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp.delete()&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="keyword">else</span><span>&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;println(<span class="string">&quot;washing&nbsp;subdirectory...&quot;</span><span>+child.absolutePath)&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wash(child)&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>wash(<span class="keyword">new</span><span>&nbsp;File(</span><span class="string">&quot;c:/temp/seamsrc&quot;</span><span>))&nbsp;&nbsp;</span></span></li>
</ol>
</div>
groovy跟java还是亲啊，有了java版本，groovy版本很快就出来了。代码量确实有缩减，还了解到groovy的closure的作用域与def的使用有些关联。其实在这段代码中外层的wash closure跟method的定义已经没啥区别了。<br />
<br />
在做ruby时，发现ruby的文件操作API极度混乱，在javaeye ruby版本发了点牢骚，还跟人<a href="http://www.javaeye.com/topic/75828">论战</a>了一把，后来我的想法得到了松底迪的支持，挺高兴，于是就有了<a href="http://www.javaeye.com/topic/76304" title="Fileex">fileex</a>的实现。使用fileex后的ruby实现代码如下：<br />
<div class="code_title">ruby 代码</div>
<div class="dp-highlighter">
<div class="bar">&nbsp;</div>
<ol class="dp-rb" start="1">
    <li class="alt"><span><span>require&nbsp;</span><span class="string">&quot;fileex&quot;</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span><span class="keyword">def</span><span>&nbsp;wash(dir)&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;dir.<span class="keyword">each</span><span>{&nbsp;</span><span class="variable">|child</span><span>|&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;child.directory?&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wash(child)&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">else</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;path&nbsp;=&nbsp;child.path&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;<span class="string">&quot;washing&nbsp;file&nbsp;#{path}...&quot;</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp&nbsp;=&nbsp;<span class="builtin">File</span><span>.</span><span class="keyword">new</span><span>(</span><span class="string">&quot;#{path}.bak&quot;</span><span>).create.open(</span><span class="string">&quot;w+&quot;</span><span>)&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;modified&nbsp;=&nbsp;<span class="keyword">false</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;child.open.each_byte{&nbsp;<span class="variable">|byte</span><span>|&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp.putc(byte)&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;byte!=0xA0&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp.putc(byte)&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">else</span><span>&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;modified&nbsp;=&nbsp;<span class="keyword">true</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">end</span><span>&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;child.close&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp.close&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;modified&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;<span class="string">&quot;File&nbsp;#{path}&nbsp;washed.&quot;</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;child.delete&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp.rename(path)&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">else</span><span>&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp.delete&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">end</span><span>&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">end</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span><span class="keyword">end</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>wash(<span class="string">&quot;c:/temp/seamsrc&quot;</span><span>.to_file)&nbsp;&nbsp;</span></span></li>
</ol>
</div>
这下终于爽了。<br />
          <br/><br/>
          <span style="color:red;">
            <a href="http://centaur.javaeye.com/blog/76323#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 30 Apr 2007 15:06:07 +0800</pubDate>
        <link>http://centaur.javaeye.com/blog/76323</link>
        <guid>http://centaur.javaeye.com/blog/76323</guid>
      </item>
          <item>
        <title>Rubish File</title>
        <author>半人马</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://centaur.javaeye.com">半人马</a>&nbsp;
                    链接：<a href="http://centaur.javaeye.com/blog/76304" style="color:red;">http://centaur.javaeye.com/blog/76304</a>&nbsp;
          发表时间: 2007年04月30日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          本文的起因在<a href="http://www.javaeye.com/topic/75828">这里</a>。在松底迪的鼓励和指导下，做了一个我认为合理的File实现，规则如下：<br />
<br />
1. 追加String的to_file方法
<div class="code_title">ruby 代码</div>
<div class="dp-highlighter">
<ol class="dp-rb" start="1">
    <li class="alt"><span><span class="string">&quot;c:/temp/test.txt&quot;</span><span>.to_file.exist?&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<br />
2. 区分File对象的new和open，只有当需要对File的内容进行操作时，才open。<br />
<br />
3. 推荐的new操作只有一个初始化参数即路径名，open方法只有mode及其它参数，一次典型的调用如下：
<div class="code_title">ruby 代码</div>
<div class="dp-highlighter">
<ol class="dp-rb" start="1">
    <li class="alt"><span><span class="builtin"></span><span></span><span class="keyword"></span><span>&quot;name&quot;.to_file.open(</span><span class="string">&quot;mode&quot;</span><span>)&nbsp;</span><span class="keyword">do</span><span>&nbsp;</span><span class="variable">|file</span><span>|&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xxxxxxx&nbsp;&nbsp;</span></li>
    <li class="alt"><span><span class="keyword">end</span><span>&nbsp;&nbsp;</span></span></li>
</ol>
</div>
但为了照顾部分人的喜好，继承ruby胸怀宽广的传统，仍保留带open参数的new方式，如：
<div class="code_title">ruby 代码</div>
<div class="dp-highlighter">
<ol class="dp-rb" start="1">
    <li class="alt"><span><span class="builtin">File</span><span>.</span><span class="keyword">new</span><span>(</span><span class="string">&quot;name&quot;</span><span>,&nbsp;</span><span class="string">&quot;mode&quot;</span><span>)&nbsp;&nbsp;</span></span></li>
</ol>
</div>
将按mode打开文件<br />
<br />
4. 如果open调用带有block，则内部保证在block执行完毕后close文件，否则需要显示close.
<div class="code_title">ruby 代码</div>
<div class="dp-highlighter">
<ol class="dp-rb" start="1">
    <li class="alt"><span><span>file&nbsp;=&nbsp;</span><span class="builtin">File</span><span>.</span><span class="keyword">new</span><span>(</span><span class="string">&quot;c:\\temp\\test.txt&quot;</span><span>)&nbsp;&nbsp;</span></span></li>
    <li class=""><span>puts&nbsp;file.open.readlines&nbsp;&nbsp;</span></li>
    <li class="alt"><span>file.close&nbsp;&nbsp;</span></li>
</ol>
</div>
<div class="code_title">ruby 代码</div>
<div class="dp-highlighter">
<ol class="dp-rb" start="1">
    <li class="alt"><span><span>&rdquo;somefile.txt&ldquo;.to_file.open&nbsp;{&nbsp;</span><span class="variable">|file</span><span>|&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;puts&nbsp;file.readlines&nbsp;&nbsp;</span></li>
    <li class="alt"><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<br />
<br />
4. 维持原File类的静态open方法的语义，典型调用如下：<br />
<div class="code_title">ruby 代码</div>
<div class="dp-highlighter">
<ol class="dp-rb" start="1">
    <li class="alt"><span><span class="builtin">File</span><span>.open(</span><span class="string">&quot;name&quot;</span><span>,&nbsp;</span><span class="string">&quot;mode&quot;</span><span>)&nbsp;{&nbsp;</span><span class="variable">|f</span><span>|&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f.xxx&nbsp;&nbsp;</span></li>
    <li class="alt"><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<br />
5. 不需要了解文件内容，如信息查询等操作，全部作为instance method，包括：
<div class="code_title">ruby 代码</div>
<div class="dp-highlighter">
<ol class="dp-rb" start="1">
    <li class="alt"><span><span class="symbol">:directory</span><span>?,&nbsp;</span><span class="symbol">:file</span><span>?,&nbsp;</span><span class="symbol">:readable</span><span>?,&nbsp;</span><span class="symbol">:owned</span><span>?,&nbsp;</span><span class="symbol">:pipe</span><span>?,&nbsp;</span><span class="symbol">:mtime</span><span>?,&nbsp;</span><span class="symbol">:extname</span><span>,&nbsp;</span><span class="symbol">:ftype</span><span>,&nbsp;&nbsp;&nbsp;</span></span></li>
    <li class=""><span><span class="symbol">:executable_real</span><span>?,&nbsp;</span><span class="symbol">:executable</span><span>?,&nbsp;</span><span class="symbol">:dirname</span><span>,&nbsp;</span><span class="symbol">:exist</span><span>?,&nbsp;</span><span class="symbol">:basename</span><span>,&nbsp;</span><span class="symbol">:blockdev</span><span>?,&nbsp;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span><span class="symbol">:chardev</span><span>?,&nbsp;</span><span class="symbol">:atime</span><span>,&nbsp;</span><span class="symbol">:chmod</span><span>,&nbsp;</span><span class="symbol">:chown</span><span>,&nbsp;</span><span class="symbol">:ctime</span><span>,&nbsp;</span><span class="symbol">:delete</span><span>,&nbsp;</span><span class="symbol">:grpowned</span><span>?,&nbsp;</span><span class="symbol">:lchmod</span><span>,&nbsp;</span><span class="symbol">:stat</span><span>,&nbsp;&nbsp;&nbsp;</span></span></li>
    <li class=""><span><span class="symbol">:readable_real</span><span>?,&nbsp;</span><span class="symbol">:readlink</span><span>,&nbsp;</span><span class="symbol">:rename</span><span>,&nbsp;</span><span class="symbol">:setgid</span><span>,&nbsp;</span><span class="symbol">:setuid</span><span>,&nbsp;</span><span class="symbol">:size</span><span>,&nbsp;</span><span class="symbol">:size</span><span>?,&nbsp;</span><span class="symbol">:socket</span><span>?,&nbsp;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span><span class="symbol">:split</span><span>,&nbsp;</span><span class="symbol">:sticky</span><span>,&nbsp;</span><span class="symbol">:symlink</span><span>?,&nbsp;</span><span class="symbol">:truncate</span><span>,&nbsp;</span><span class="symbol">:writable</span><span>?,&nbsp;</span><span class="symbol">:writable_real</span><span>,&nbsp;</span><span class="symbol">:zero</span><span>?&nbsp;&nbsp;</span></span></li>
</ol>
</div>
详情请参考ruby的缺省File实现的文档<br />
<br />
6. 对于目录，追加each遍历方法，并去掉恶心的&ldquo;.&quot;, &quot;..&quot;两个东西，每一个遍历项是一个新的File对象，典型调用如下：
<div class="code_title">ruby 代码</div>
<div class="dp-highlighter">
<ol class="dp-rb" start="1">
    <li class="alt"><span><span class="builtin">File</span><span>.</span><span class="keyword">new</span><span>(</span><span class="string">&quot;/dir&quot;</span><span>).</span><span class="keyword">each</span><span>&nbsp;{&nbsp;</span><span class="variable">|child</span><span>|&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;child.directory?&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;......&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">else</span><span>&nbsp;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.....&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">end</span><span>&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li>
</ol>
</div>
<br />
7. 追加文件实例的create方法<br />
<div class="code_title">ruby 代码</div>
<div class="dp-highlighter">
<ol class="dp-rb" start="1">
    <li class="alt"><span><span class="string">&quot;/somedir/somefile&quot;</span><span>.to_file.create&nbsp;&nbsp;</span></span></li>
</ol>
</div>
追加opened?方法，查询文件是否已被打开<br />
维持path语义，返回构造时提供的路径名，类型为字符串，不做normalize<br />
<br />
8. 其它功能均维持File的原状。<br />
<br />
代码见附件，使用时在自己的脚本前require一下即可。<br />
          <br/><br/>
          <span style="color:red;">
            <a href="http://centaur.javaeye.com/blog/76304#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 30 Apr 2007 13:46:45 +0800</pubDate>
        <link>http://centaur.javaeye.com/blog/76304</link>
        <guid>http://centaur.javaeye.com/blog/76304</guid>
      </item>
          <item>
        <title>Acegi中的FilterInvocationDefinitionMap的局限性及小改进</title>
        <author>半人马</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://centaur.javaeye.com">半人马</a>&nbsp;
                    链接：<a href="http://centaur.javaeye.com/blog/69952" style="color:red;">http://centaur.javaeye.com/blog/69952</a>&nbsp;
          发表时间: 2007年04月11日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Acegi中的FilterInvocationDefinitionMap提供两种实现：PATTERN_TYPE_ANT_PATH及PATTERN_TYPE_PERL5。其中PATTERN_TYPE_ANT_PATH使用apache Ant的路径格式来进行url的模式匹配，由于只有**, *, ?少数几个通配符，所以使用起来比较简单，但是无法支持带参数的url，如/action.do?method=m这种url，在进行匹配之前，会先将?后面的部分截去。见PathBasedFilterInvocationDefinitionMap.java的代码：
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar">&nbsp;</div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span class="keyword">public</span><span>&nbsp;ConfigAttributeDefinition&nbsp;lookupAttributes(String&nbsp;url)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;Strip&nbsp;anything&nbsp;after&nbsp;a&nbsp;question&nbsp;mark&nbsp;symbol,&nbsp;as&nbsp;per&nbsp;SEC-161.&nbsp;See&nbsp;also&nbsp;SEC-321</span><span>&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">int</span><span>&nbsp;firstQuestionMarkIndex&nbsp;=&nbsp;url.indexOf(</span><span class="string">&quot;?&quot;</span><span>);&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;(firstQuestionMarkIndex&nbsp;!=&nbsp;-</span><span class="number">1</span><span>)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;url&nbsp;=&nbsp;url.substring(<span class="number">0</span><span>,&nbsp;firstQuestionMarkIndex);&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;(isConvertUrlToLowercaseBeforeComparison())&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;url&nbsp;=&nbsp;url.toLowerCase();&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;(logger.isDebugEnabled())&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.debug(<span class="string">&quot;Converted&nbsp;URL&nbsp;to&nbsp;lowercase,&nbsp;from:&nbsp;'&quot;</span><span>&nbsp;+&nbsp;url&nbsp;+&nbsp;</span><span class="string">&quot;';&nbsp;to:&nbsp;'&quot;</span><span>&nbsp;+&nbsp;url&nbsp;+&nbsp;</span><span class="string">&quot;'&quot;</span><span>);&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;Iterator&nbsp;iter&nbsp;=&nbsp;requestMap.iterator();&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">while</span><span>&nbsp;(iter.hasNext())&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EntryHolder&nbsp;entryHolder&nbsp;=&nbsp;(EntryHolder)&nbsp;iter.next();&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">boolean</span><span>&nbsp;matched&nbsp;=&nbsp;pathMatcher.match(entryHolder.getAntPath(),&nbsp;url);&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;(logger.isDebugEnabled())&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.debug(<span class="string">&quot;Candidate&nbsp;is:&nbsp;'&quot;</span><span>&nbsp;+&nbsp;url&nbsp;+&nbsp;</span><span class="string">&quot;';&nbsp;pattern&nbsp;is&nbsp;&quot;</span><span>&nbsp;+&nbsp;entryHolder.getAntPath()&nbsp;+&nbsp;</span><span class="string">&quot;;&nbsp;matched=&quot;</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+&nbsp;matched);&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;(matched)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;entryHolder.getConfigAttributeDefinition();&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;</span><span class="keyword">null</span><span>;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
在对Acegi的缺省实现不进行扩展的情况下，要实现对带参数URL的安全控制，可以使用PATTERN_TYPE_PERL5即正则表达式进行模式匹配（在RegExpBasedFilterInvocationDefinitionMap中实现），例如上述的路径可以用如下的模式来进行匹配：^/user\.do\?method=.*，采用这种方案的优点是可以利用正则表达式的强大表达能力，缺点是难以实现模式的自动生成。在一个实用的基于角色的权限管理体系中，通常对要进行安全控制的资源是由管理员通过管理界面来定制的，如果使用PATTERN_TYPE_PERL5的格式来制定模式，则需要管理员熟练掌握正则表达式的使用，有难度。考虑实现一个UrlFilterInvocationDefinitionMap，仅提供一种通配符*，又支持url参数，简单又实用。代码如下：<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar">&nbsp;</div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span class="keyword">import</span><span>&nbsp;org.acegisecurity.ConfigAttributeDefinition;&nbsp;&nbsp;</span></span></li>
    <li class=""><span><span class="keyword">import</span><span>&nbsp;org.acegisecurity.intercept.web.AbstractFilterInvocationDefinitionSource;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span><span class="keyword">import</span><span>&nbsp;org.acegisecurity.intercept.web.FilterInvocationDefinition;&nbsp;&nbsp;</span></span></li>
    <li class=""><span><span class="keyword">import</span><span>&nbsp;org.apache.commons.logging.Log;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span><span class="keyword">import</span><span>&nbsp;org.apache.commons.logging.LogFactory;&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span><span class="keyword">import</span><span>&nbsp;java.util.*;&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span><span class="comment">/**</span>&nbsp;</span></li>
    <li class=""><span><span class="comment">&nbsp;*&nbsp;User:&nbsp;user</span>&nbsp;</span></li>
    <li class="alt"><span><span class="comment">&nbsp;*&nbsp;Date:&nbsp;2007-4-11</span>&nbsp;</span></li>
    <li class=""><span><span class="comment">&nbsp;*&nbsp;Time:&nbsp;9:14:00</span>&nbsp;</span></li>
    <li class="alt"><span><span class="comment">&nbsp;*/</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;UrlFilterInvocationDefinitionMap&nbsp;</span><span class="keyword">extends</span><span>&nbsp;AbstractFilterInvocationDefinitionSource&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">implements</span><span>&nbsp;FilterInvocationDefinition&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">private</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">final</span><span>&nbsp;Log&nbsp;logger&nbsp;=&nbsp;LogFactory.getLog(UrlFilterInvocationDefinitionMap.</span><span class="keyword">class</span><span>);&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">private</span><span>&nbsp;List&lt;EntryHolder&gt;&nbsp;requestMap&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;ArrayList&lt;EntryHolder&gt;();&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">private</span><span>&nbsp;</span><span class="keyword">boolean</span><span>&nbsp;convertUrlToLowercaseBeforeComparison&nbsp;=&nbsp;</span><span class="keyword">false</span><span>;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">public</span><span>&nbsp;ConfigAttributeDefinition&nbsp;lookupAttributes(String&nbsp;url)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Iterator&nbsp;iter&nbsp;=&nbsp;requestMap.iterator();&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;(isConvertUrlToLowercaseBeforeComparison())&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;url&nbsp;=&nbsp;url.toLowerCase();&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;(logger.isDebugEnabled())&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.debug(<span class="string">&quot;Converted&nbsp;URL&nbsp;to&nbsp;lowercase,&nbsp;from:&nbsp;'&quot;</span><span>&nbsp;+&nbsp;url&nbsp;+&nbsp;</span><span class="string">&quot;';&nbsp;to:&nbsp;'&quot;</span><span>&nbsp;+&nbsp;url&nbsp;+&nbsp;</span><span class="string">&quot;'&quot;</span><span>);&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">while</span><span>&nbsp;(iter.hasNext())&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EntryHolder&nbsp;entryHolder&nbsp;=&nbsp;(EntryHolder)&nbsp;iter.next();&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">boolean</span><span>&nbsp;matched&nbsp;=&nbsp;UrlMatcher.matches(url,&nbsp;entryHolder.getUrlPattern());&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;(logger.isDebugEnabled())&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.debug(<span class="string">&quot;Candidate&nbsp;is:&nbsp;'&quot;</span><span>&nbsp;+&nbsp;url&nbsp;+&nbsp;</span><span class="string">&quot;';&nbsp;pattern&nbsp;is&nbsp;&quot;</span><span>&nbsp;+&nbsp;entryHolder.getUrlPattern()&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+&nbsp;<span class="string">&quot;;&nbsp;matched=&quot;</span><span>&nbsp;+&nbsp;matched);&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;(matched)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;entryHolder.getConfigAttributeDefinition();&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;</span><span class="keyword">null</span><span>;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">public</span><span>&nbsp;Iterator&nbsp;getConfigAttributeDefinitions()&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set&lt;ConfigAttributeDefinition&gt;&nbsp;set&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;HashSet&lt;ConfigAttributeDefinition&gt;();&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>&nbsp;(EntryHolder&nbsp;aRequestMap&nbsp;:&nbsp;requestMap)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set.add(aRequestMap.getConfigAttributeDefinition());&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;set.iterator();&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;addSecureUrl(String&nbsp;urlPattern,&nbsp;ConfigAttributeDefinition&nbsp;attr)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;requestMap.add(<span class="keyword">new</span><span>&nbsp;EntryHolder(urlPattern,&nbsp;attr));&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;(logger.isDebugEnabled())&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.debug(<span class="string">&quot;Added&nbsp;url&nbsp;pattern:&nbsp;&quot;</span><span>&nbsp;+&nbsp;urlPattern&nbsp;+&nbsp;</span><span class="string">&quot;;&nbsp;attributes:&nbsp;&quot;</span><span>&nbsp;+&nbsp;attr);&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">public</span><span>&nbsp;</span><span class="keyword">boolean</span><span>&nbsp;isConvertUrlToLowercaseBeforeComparison()&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;</span><span class="keyword">this</span><span>.convertUrlToLowercaseBeforeComparison;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;setConvertUrlToLowercaseBeforeComparison(</span><span class="keyword">boolean</span><span>&nbsp;convertUrlToLowercaseBeforeComparison)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">this</span><span>.convertUrlToLowercaseBeforeComparison&nbsp;=&nbsp;convertUrlToLowercaseBeforeComparison;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">protected</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;EntryHolder&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">private</span><span>&nbsp;ConfigAttributeDefinition&nbsp;configAttributeDefinition;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">private</span><span>&nbsp;String&nbsp;urlPattern;&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">public</span><span>&nbsp;EntryHolder(String&nbsp;urlPattern,&nbsp;ConfigAttributeDefinition&nbsp;attr)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">this</span><span>.urlPattern&nbsp;=&nbsp;urlPattern;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">this</span><span>.configAttributeDefinition&nbsp;=&nbsp;attr;&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">protected</span><span>&nbsp;EntryHolder()&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">throw</span><span>&nbsp;</span><span class="keyword">new</span><span>&nbsp;IllegalArgumentException(</span><span class="string">&quot;Cannot&nbsp;use&nbsp;default&nbsp;constructor&quot;</span><span>);&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">public</span><span>&nbsp;String&nbsp;getUrlPattern()&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;urlPattern;&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">public</span><span>&nbsp;ConfigAttributeDefinition&nbsp;getConfigAttributeDefinition()&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;configAttributeDefinition;&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
其中模式匹配用了一个UrlMatcher类，代码及test列在下面：<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar">&nbsp;</div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span class="keyword">import</span><span>&nbsp;java.util.regex.Pattern;&nbsp;&nbsp;</span></span></li>
    <li class=""><span><span class="keyword">import</span><span>&nbsp;java.util.regex.Matcher;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span><span class="comment">/**</span>&nbsp;</span></li>
    <li class="alt"><span><span class="comment">&nbsp;*&nbsp;User:&nbsp;user</span>&nbsp;</span></li>
    <li class=""><span><span class="comment">&nbsp;*&nbsp;Date:&nbsp;2007-4-11</span>&nbsp;</span></li>
    <li class="alt"><span><span class="comment">&nbsp;*&nbsp;Time:&nbsp;9:48:09</span>&nbsp;</span></li>
    <li class=""><span><span class="comment">&nbsp;*/</span><span>&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;UrlMatcher&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">boolean</span><span>&nbsp;matches(String&nbsp;url,&nbsp;String&nbsp;urlPattern){&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StringBuffer&nbsp;buff&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;StringBuffer();&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buff.append('^');&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buff.append(urlPattern.replaceAll(<span class="string">&quot;\\.&quot;</span><span>,&nbsp;</span><span class="string">&quot;\\\\.&quot;</span><span>).replaceAll(</span><span class="string">&quot;\\?&quot;</span><span>,&nbsp;</span><span class="string">&quot;\\\\?&quot;</span><span>).replaceAll(</span><span class="string">&quot;\\*&quot;</span><span>,&nbsp;</span><span class="string">&quot;.*&quot;</span><span>));&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buff.append(<span class="string">&quot;$&quot;</span><span>);&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Pattern&nbsp;pattern&nbsp;=&nbsp;Pattern.compile(buff.toString());&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Matcher&nbsp;matcher&nbsp;=&nbsp;pattern.matcher(url);&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">boolean</span><span>&nbsp;found&nbsp;=&nbsp;matcher.find();&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;found&nbsp;&amp;&amp;&nbsp;matcher.group().equals(url);&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class=""><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar">&nbsp;</div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span class="comment">/**</span>&nbsp;</span></li>
    <li class=""><span><span class="comment">&nbsp;*&nbsp;User:&nbsp;user</span>&nbsp;</span></li>
    <li class="alt"><span><span class="comment">&nbsp;*&nbsp;Date:&nbsp;2007-4-11</span>&nbsp;</span></li>
    <li class=""><span><span class="comment">&nbsp;*&nbsp;Time:&nbsp;10:07:07</span>&nbsp;</span></li>
    <li class="alt"><span><span class="comment">&nbsp;*/</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span><span class="keyword">import</span><span>&nbsp;junit.framework.*;&nbsp;&nbsp;</span></span></li>
    <li class=""><span><span class="keyword">import</span><span>&nbsp;com.vnv.basicacegi.security.UrlMatcher;&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;UrlMatcherTest&nbsp;</span><span class="keyword">extends</span><span>&nbsp;TestCase&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;testMatches()&nbsp;</span><span class="keyword">throws</span><span>&nbsp;Exception&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertTrue(UrlMatcher.matches(<span class="string">&quot;/user.do?method=home&quot;</span><span>,&nbsp;</span><span class="string">&quot;/user.do?method=*&quot;</span><span>));&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertTrue(UrlMatcher.matches(<span class="string">&quot;/user/home/abc/action.do&quot;</span><span>,&nbsp;</span><span class="string">&quot;/user/*/action.do&quot;</span><span>));&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertTrue(UrlMatcher.matches(<span class="string">&quot;/user/home/abc/action.do?method=a&amp;c=d&quot;</span><span>,&nbsp;</span><span class="string">&quot;/user/*/action.do*&quot;</span><span>));&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertTrue(UrlMatcher.matches(<span class="string">&quot;/user/home/abc/action.do?method=a&amp;c=d&quot;</span><span>,&nbsp;</span><span class="string">&quot;/user/*/action.do?*&quot;</span><span>));&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertTrue(UrlMatcher.matches(<span class="string">&quot;/user/home/abc/action.do?method=a&amp;c=d&quot;</span><span>,&nbsp;</span><span class="string">&quot;/user/*/action.do?method=*&quot;</span><span>));&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertFalse(UrlMatcher.matches(<span class="string">&quot;/user/action.do?method=a&amp;c=d&quot;</span><span>,&nbsp;</span><span class="string">&quot;/user/*/action.do?method=*&quot;</span><span>));&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertTrue(UrlMatcher.matches(<span class="string">&quot;/action.do?method=a&amp;c=d&quot;</span><span>,&nbsp;</span><span class="string">&quot;*/action.do?method=*&quot;</span><span>));&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>} <br />
    </span></li>
</ol>
</div>
这下可以爽了。
          <br/><br/>
          <span style="color:red;">
            <a href="http://centaur.javaeye.com/blog/69952#comments" style="color:red;">已有 <strong>2</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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;">Windows7在微软WinHEC 2008上揭开神秘面纱</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, 11 Apr 2007 10:39:00 +0800</pubDate>
        <link>http://centaur.javaeye.com/blog/69952</link>
        <guid>http://centaur.javaeye.com/blog/69952</guid>
      </item>
          <item>
        <title>Apache+Mongrel上host多个rails应用</title>
        <author>半人马</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://centaur.javaeye.com">半人马</a>&nbsp;
                    链接：<a href="http://centaur.javaeye.com/blog/34286" style="color:red;">http://centaur.javaeye.com/blog/34286</a>&nbsp;
          发表时间: 2006年11月14日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          下面是Apache+Mongrel上host多个rails应用的方法，提供需要的人使用。<br /><br />1. 软件版本<br />&nbsp;&nbsp;&nbsp;&nbsp; 我用的操作系统是Redhat Linux 2.4.21-37.EL<br />&nbsp;&nbsp;&nbsp;&nbsp; 系统安装时带的Apache httpd 2.0.46-54ent<br />&nbsp;&nbsp;&nbsp;&nbsp; ruby 1.8.5<br />&nbsp;&nbsp;&nbsp;&nbsp; rails 1.1.6<br />&nbsp;&nbsp;&nbsp;&nbsp; mongrel&nbsp; 0.3.13.4<br /><br />2. 课题<br />&nbsp;&nbsp;&nbsp;&nbsp; 你有一个可以运行的rails应用app1，要将它部署在httpd http://host/上，并在http://host/app1下访问<br /><br />3. 实施步骤<br />&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue">a)</span> 在apache httpd.conf相同目录下创建新的配置文件http-mongrel-proxy.conf输入以下内容<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <pre name="code" class="java">
ProxyRequests Off
&lt;Proxy *>
Order deny,allow
Allow from all
&lt;/Proxy>

ProxyPass /app1 http://127.0.0.1:3000/app1
ProxyPassReverse /app1/ http://127.0.0.1:3000/app1
           </pre><br />&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue">b)</span> 确认httpd.conf中打开了<pre name="code" class="java">
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so</pre>几项，并在httpd.conf末尾添加一行将新的配置文件包含进来<pre name="code" class="java">Include conf/http-mongrel-proxy.conf</pre><br /><br />&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue">c)</span> 在app1项目路径下启动mongrel<br /><pre name="code" class="java">mongrel_rails start --prefix=/app1 -e production </pre>其中--prefix是mongrel新版本中专门为了解决我们的课题提供的新选项。其它的启动选项如-d什么的自己加<br />&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue">d)</span> 重启httpd<br />&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue">e)</span> 如果你的rails应用按照rails惯例开发，你会发现你的images, stylesheet甚至是一些form action都不起作用。这是因为你在rhtml中使用了/images/, /stylesheets/, /action/view这样的绝对路径。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我建议的解决办法是在你的layout文件中设置&lt;base href=" &lt;%= $htmlbase %> " >，并修改所有以/开头的绝对路径为相对路径。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在config/environment/production.rb中添加全局变量定义<br />&nbsp;&nbsp;&nbsp;&nbsp; <pre name="code" class="java">$htmlbase="http://host/app1/fake.html"</pre>其中fake.html可以不存在。<br />&nbsp;&nbsp;&nbsp;&nbsp; 为了保持开发时的方便，在config/environment/development.rb中添加定义<br />&nbsp;&nbsp;&nbsp;&nbsp; <pre name="code" class="java">$htmlbase="http://host:3000/fake.html"</pre><br />&nbsp;&nbsp;&nbsp;&nbsp; 这样开发和部署时的代码不用改来改去了。<br />&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue">f)</span> 优化。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 现在你的应用应该可以按照你预想的方式运行了，现在我们作一点小优化，让mongrel只负责动态内容的处理，让apache去处理静态信息。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 确认httpd.conf中打开了<pre name="code" class="java">LoadModule alias_module modules/mod_alias.so</pre><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 编辑http-mongrel-proxy.conf，在proxypass语句之前添加以下配置:<br /><pre name="code" class="java">
Alias /app1 "/path/to/app1/public"
&lt;Directory "/path/to/app1/public">
    Options Indexes FollowSymLinks MultiViews
    AllowOverride none
    Order allow,deny
    Allow from all
&lt;/Directory>

ProxyPass /app1/images !
ProxyPass /app1/stylesheets !
ProxyPass /app1/javascripts !
</pre><br />其中ProxyPass ... !语句是让proxy不要管这些静态内容，让alias来管。<br />重启apache，这时候应该可以看到你期望看到的页面了。<br />这个步骤中你可能需要的问题是静态内容的permission denied。这时候你需要给用户apache访问/path/to/app1/public的读权限。举个例子：<br />我的/path/to/app1/public是/home/centaur/workspace/app1/public，这时需要做两件事：<br />第一件，将用户apache加入centaur组（创建centaur用户时的缺省初始组），moduser命令自己查<br />第二件，为/home/centaur目录添加组成员可执行权限（x），一般这个目录的缺省权限是700<br />&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue">g)</span> 下面你按照上面的方法可以host你的app2, app3，当然每个mongre_rails启动时占用的端口要不一样，在http-mongrel-proxy.conf中也要添加相应的配置。<br />&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue">h)</span> 以上内容绝非原创，参考了N多前辈的成果，但是我这个应该更准确更实用一点。也请神原谅我的懒，等有人找我麻烦的时候再写参考文献一节吧。
          <br/><br/>
          <span style="color:red;">
            <a href="http://centaur.javaeye.com/blog/34286#comments" style="color:red;">已有 <strong>2</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 14 Nov 2006 19:55:16 +0800</pubDate>
        <link>http://centaur.javaeye.com/blog/34286</link>
        <guid>http://centaur.javaeye.com/blog/34286</guid>
      </item>
      </channel>
</rss>