﻿<?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-无为-随笔分类-JAVA WEB应用</title><link>http://www.blogjava.net/mlh123caoer/category/23932.html</link><description>无为则可为，无为则至深！
</description><language>zh-cn</language><lastBuildDate>Fri, 26 Aug 2011 08:15:45 GMT</lastBuildDate><pubDate>Fri, 26 Aug 2011 08:15:45 GMT</pubDate><ttl>60</ttl><item><title>配置Linux系统环境变量的三种方法</title><link>http://www.blogjava.net/mlh123caoer/archive/2011/08/26/357357.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Fri, 26 Aug 2011 07:11:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2011/08/26/357357.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/357357.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2011/08/26/357357.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/357357.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/357357.html</trackback:ping><description><![CDATA[<div><span style="font-family: Verdana, Arial, Helvetica, sans-serif, 宋体; line-height: 25px; color: #333333; "><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">在linux下进行Java开发需要配置环境变量，下面介绍了三种配置环境变量的方法。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; "><br /></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">1.修改/etc/profile文件</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">如果你的计算机仅仅作为开发使用时推荐使用这种方法，因为所有用户的shell都有权使用这些环境变量，可能会给系统带来安全性问题。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">&nbsp;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">(1)用文本编辑器打开/etc/profile</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">&nbsp;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">(2)在profile文件末尾加入：</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">JAVA_HOME=/usr/share/jdk1.5.0_05</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">PATH=$JAVA_HOME/bin:$PATH</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">export JAVA_HOME</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">export PATH</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">export CLASSPATH</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">&nbsp;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">(3)重新登录</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">&nbsp;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">注解：</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">a. 你要将 /usr/share/jdk1.5.0_05jdk 改为你的jdk安装目录</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">&nbsp;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">b. linux下用冒号&#8220;:&#8221;来分隔路径</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">&nbsp;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">c. $PATH / $CLASSPATH / $JAVA_HOME 是用来引用原来的环境变量的值,在设置环境变量时特别要注意不能把原来的值给覆盖掉了，这是一种常见的错误。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">&nbsp;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">d. CLASSPATH中当前目录&#8220;.&#8221;不能丢,把当前目录丢掉也是常见的错误。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">&nbsp;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">e. export是把这三个变量导出为全局变量。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">&nbsp;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">f. 大小写必须严格区分。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">&nbsp;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">2. 修改.bashrc文件　　</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">这种方法更为安全，它可以把使用这些环境变量的权限控制到用户级别，如果你需要给某个用户权限使用这些环境变量，你只需要修改其个人用户主目录下的.bashrc文件就可以了。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">&nbsp;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">(1)用文本编辑器打开用户目录下的.bashrc文件</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">&nbsp;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">(2)在.bashrc文件末尾加入：　　</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">set JAVA_HOME=/usr/share/jdk1.5.0_05</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">export JAVA_HOME</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">set PATH=$JAVA_HOME/bin:$PATH</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">export PATH</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">set CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">export CLASSPATH</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">&nbsp;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">(3)重新登录</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">&nbsp;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">3. 直接在shell下设置变量</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">不赞成使用这种方法，因为换个shell，你的设置就无效了，因此这种方法仅仅是临时使用，以后要使用的时候又要重新设置，比较麻烦。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">&nbsp;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">只需在shell终端执行下列命令：</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">export JAVA_HOME=/usr/share/jdk1.5.0_05</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">export PATH=$JAVA_HOME/bin:$PATH</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; text-indent: 2em; ">export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar</p></span></div><img src ="http://www.blogjava.net/mlh123caoer/aggbug/357357.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2011-08-26 15:11 <a href="http://www.blogjava.net/mlh123caoer/archive/2011/08/26/357357.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Calender</title><link>http://www.blogjava.net/mlh123caoer/archive/2009/11/06/301491.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Fri, 06 Nov 2009 12:49:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2009/11/06/301491.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/301491.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2009/11/06/301491.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/301491.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/301491.html</trackback:ping><description><![CDATA[<div>
<p>&nbsp;import java.util.Calendar;</p>
<p>import java.util.GregorianCalendar;</p>
<p>public class CalTest {</p>
<p><span class="Apple-tab-span" style="white-space:pre">	</span>public static void main(String[] argv) {</p>
<p><span class="Apple-tab-span" style="white-space:pre">		</span>CalTest calTest = new CalTest();</p>
<p><span class="Apple-tab-span" style="white-space:pre">		</span>calTest.cal(2009, 11);</p>
<p><span class="Apple-tab-span" style="white-space:pre">	</span>}</p>
<p><span class="Apple-tab-span" style="white-space:pre">	</span>public void cal(final int year, final int month) {</p>
<p><span class="Apple-tab-span" style="white-space:pre">		</span>Calendar calendar = new GregorianCalendar();</p>
<p><span class="Apple-tab-span" style="white-space:pre">		</span>calendar.set(year, month-1, 1);</p>
<p><span class="Apple-tab-span" style="white-space:pre">		</span>int week = calendar.get(GregorianCalendar.DAY_OF_WEEK) - 1;</p>
<p><span class="Apple-tab-span" style="white-space:pre">		</span>int days = calendar.getActualMaximum(GregorianCalendar.DAY_OF_MONTH);</p>
<p><span class="Apple-tab-span" style="white-space:pre">		</span>System.out.println();</p>
<p><span class="Apple-tab-span" style="white-space:pre">		</span>System.out.println("日\t一\t二\t三\t四\t五\t六");</p>
<p><span class="Apple-tab-span" style="white-space:pre">		</span>for(int i = 0; i &lt; week; i++) {</p>
<p><span class="Apple-tab-span" style="white-space:pre">			</span>System.out.println("\t");</p>
<p><span class="Apple-tab-span" style="white-space:pre">		</span>}</p>
<p><span class="Apple-tab-span" style="white-space:pre">		</span></p>
<p><span class="Apple-tab-span" style="white-space:pre">		</span>for(int i = 1; i &lt;= days; i ++) {</p>
<p><span class="Apple-tab-span" style="white-space:pre">			</span>System.out.print(i + "\t");</p>
<p><span class="Apple-tab-span" style="white-space:pre">			</span>if((week + i)%7 == 0) {</p>
<p><span class="Apple-tab-span" style="white-space:pre">				</span>System.out.println();</p>
<p><span class="Apple-tab-span" style="white-space:pre">			</span>}</p>
<p><span class="Apple-tab-span" style="white-space:pre">			</span></p>
<p><span class="Apple-tab-span" style="white-space:pre">		</span>}</p>
<p><span class="Apple-tab-span" style="white-space:pre">	</span>}</p>
<p><br />
</p>
<p>}</p>
<p><br />
</p>
<p>运行效果：</p>
<p><img src="http://www.blogjava.net/images/blogjava_net/mlh123caoer/dd.jpg" border="0" alt="" /><br />
</p>
</div><img src ="http://www.blogjava.net/mlh123caoer/aggbug/301491.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2009-11-06 20:49 <a href="http://www.blogjava.net/mlh123caoer/archive/2009/11/06/301491.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java开发者需坚守的十大基本准则</title><link>http://www.blogjava.net/mlh123caoer/archive/2009/09/29/296938.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Tue, 29 Sep 2009 11:52:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2009/09/29/296938.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/296938.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2009/09/29/296938.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/296938.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/296938.html</trackback:ping><description><![CDATA[<span  style="color: #333333; font-family: 宋体; font-size: 13px; ">
<p style="margin-top: 0px; margin-right: 8px; margin-bottom: 0px; margin-left: 8px; color: #333333; "><font size="3">有许多标准和实践准则可适用于Java开发者，但此处要说的，是每个Java开发者需坚守的基本原则。<br style="font-size: 12px; " />
<br style="font-size: 12px; " />
&nbsp;&nbsp;&nbsp;</font><strong>一、为代码加注释。</strong><font size="3">虽然每个人都知道这点，但有时却不自觉忘了履行，今天你&#8220;忘了&#8221;加注释了吗？虽然注释对程序的功能没什么&#8220;贡献&#8221;，但过一段时间，比如说两星期之后或者更长，回过头来看看自己的代码，说不定已经记不住它是干什么的了。如果这些代码是你个人的，那还算是走运了，不幸的是，当然了，大多数时候都是别人的不幸，很多时候大家都是在为公司写代码，写代码的人也许早已经离开了公司，但别忘了一句古话，有来有往嘛，为他人，也为我们自己，请为你的代码加上注释。<br style="font-size: 12px; " />
<br style="font-size: 12px; " />
</font><strong>&nbsp;&nbsp; 二、不要让事情复杂化。</strong><font size="3">程序员有时候总是对简单问题想出复杂的解决方案，比如说，在只有五个用户的程序中引入EJB、对程序实现了并不需要的框架（framework），之类的还有属性文件、面向对象解决方案、多线程等等。为什么要这样做呢？也许我们并不知道是否这样会更好，但这样做也许可以学到一些新东西，或者让自己更感兴趣一些。如果是不知道为什么这样做，建议多请教经验丰富的程序员，如果是为了个人的目的，麻烦让自己更专业一点。<br style="font-size: 12px; " />
<br style="font-size: 12px; " />
&nbsp;&nbsp;&nbsp;</font><strong>三、始终牢记——&#8220;少即是好（Less is more）并不总是对的&#8221;。</strong><font size="3">代码效率虽然很重要，但在许多解决方案中，编写更少的代码并不能改善这些代码的效率，请看下面这个简单的例子：</font></p>
<div style="margin-top: 0px; margin-bottom: 0px; border-style: initial; border-color: initial; text-align: left; margin-right: auto; margin-left: auto; color: #333333; ">
<pre style="font-family: 'Courier New'; white-space: pre-wrap; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; background-color: #ededed; ">
<div style="margin-top: 0px; margin-bottom: 0px; border-style: initial; border-color: initial; text-align: left; margin-right: auto; margin-left: auto; color: #333333; "><span style="color: #0000ff; ">if</span><span style="color: #000000; ">(newStatusCode.equals(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">SD</span><span style="color: #000000; ">"</span><span style="color: #000000; ">) </span><span style="color: #000000; ">&amp;&amp;</span><span style="color: #000000; "> (sellOffDate </span><span style="color: #000000; ">==</span> <span style="color: #0000ff; ">null</span> <span style="color: #000000; ">||</span><span style="color: #000000; ">
todayDate.compareTo(sellOffDate)</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">0</span> <span style="color: #000000; ">||</span><span style="color: #000000; "> (lastUsedDate </span><span style="color: #000000; ">!=</span> <span style="color: #0000ff; ">null</span> <span style="color: #000000; ">&amp;&amp;</span><span style="color: #000000; ">
todayDate.compareTo(lastUsedDate)</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">)) </span><span style="color: #000000; ">||</span><span style="color: #000000; ">
(newStatusCode.equals(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">OBS</span><span style="color: #000000; ">"</span><span style="color: #000000; ">) </span><span style="color: #000000; ">&amp;&amp;</span><span style="color: #000000; "> (OBSDate </span><span style="color: #000000; ">==</span> <span style="color: #0000ff; ">null</span> <span style="color: #000000; ">||</span><span style="color: #000000; ">
todayDate.compareTo(OBSDate)</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">))){
newStatusCode </span><span style="color: #000000; ">=</span> <span style="color: #000000; ">"</span><span style="color: #000000; ">NYP</span><span style="color: #000000; ">"</span><span style="color: #000000; ">;
}</span></div>
</pre>
</div>
<p style="margin-top: 0px; margin-right: 8px; margin-bottom: 0px; margin-left: 8px; color: #333333; "><font size="3">能看明白if条件语句是干什么的吗？能想出来是谁写的这段代码吗？如果把它分成两段独立的if语句，是不是更容易理解呢，下面是修改后的代码：</font></p>
<div style="margin-top: 0px; margin-bottom: 0px; border-style: initial; border-color: initial; text-align: left; margin-right: auto; margin-left: auto; color: #333333; ">
<pre style="font-family: 'Courier New'; white-space: pre-wrap; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; background-color: #ededed; ">
<div style="margin-top: 0px; margin-bottom: 0px; border-style: initial; border-color: initial; text-align: left; margin-right: auto; margin-left: auto; color: #333333; "><span style="color: #0000ff; ">if</span><span style="color: #000000; ">(newStatusCode.equals(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">SD</span><span style="color: #000000; ">"</span><span style="color: #000000; ">) </span><span style="color: #000000; ">&amp;&amp;</span><span style="color: #000000; "> (sellOffDate </span><span style="color: #000000; ">==</span> <span style="color: #0000ff; ">null</span> <span style="color: #000000; ">||</span><span style="color: #000000; ">
todayDate.compareTo(sellOffDate)</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">0</span> <span style="color: #000000; ">||</span><span style="color: #000000; "> (lastUsedDate </span><span style="color: #000000; ">!=</span> <span style="color: #0000ff; ">null</span> <span style="color: #000000; ">&amp;&amp;</span><span style="color: #000000; ">
todayDate.compareTo(lastUsedDate)</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">))){
newStatusCode </span><span style="color: #000000; ">=</span> <span style="color: #000000; ">"</span><span style="color: #000000; ">NYP</span><span style="color: #000000; ">"</span><span style="color: #000000; ">;
}</span><span style="color: #0000ff; ">else</span>
<span style="color: #0000ff; ">if</span><span style="color: #000000; ">(newStatusCode.equals(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">OBS</span><span style="color: #000000; ">"</span><span style="color: #000000; ">) </span><span style="color: #000000; ">&amp;&amp;</span><span style="color: #000000; "> (OBSDate </span><span style="color: #000000; ">==</span> <span style="color: #0000ff; ">null</span> <span style="color: #000000; ">||</span><span style="color: #000000; ">
todayDate.compareTo(OBSDate)</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">))
{
newStatusCode </span><span style="color: #000000; ">=</span> <span style="color: #000000; ">"</span><span style="color: #000000; ">NYP</span><span style="color: #000000; ">"</span><span style="color: #000000; ">;
}</span></div>
</pre>
</div>
<p style="margin-top: 0px; margin-right: 8px; margin-bottom: 0px; margin-left: 8px; color: #333333; "><font size="3">是不是读起来容易多了呢，在此只是多加了一个if和两个花括号，但代码的可读性与可理解性就一下子提高了一大截。</font></p>
<p style="margin-top: 0px; margin-right: 8px; margin-bottom: 0px; margin-left: 8px; color: #333333; "><strong>&nbsp;&nbsp; 四、请不要硬编码。</strong><font size="3">开发者经常有意&#8220;忘记&#8221;或忽略掉这点，因为有些时候开发日程逼得实在太紧。其实，多写一行定义静态变量的代码能花多少时间呢？</font></p>
<div style="margin-top: 0px; margin-bottom: 0px; border-style: initial; border-color: initial; text-align: left; margin-right: auto; margin-left: auto; color: #333333; ">
<pre style="font-family: 'Courier New'; white-space: pre-wrap; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; background-color: #ededed; ">
<div style="margin-top: 0px; margin-bottom: 0px; border-style: initial; border-color: initial; text-align: left; margin-right: auto; margin-left: auto; color: #333333; "><span style="color: #0000ff; ">public</span> <span style="color: #0000ff; ">class</span><span style="color: #000000; "> A {
</span><span style="color: #0000ff; ">public</span> <span style="color: #0000ff; ">static</span><span style="color: #000000; "> final String S_CONSTANT_ABC </span><span style="color: #000000; ">=</span> <span style="color: #000000; ">"</span><span style="color: #000000; ">ABC</span><span style="color: #000000; ">"</span><span style="color: #000000; ">;
</span><span style="color: #0000ff; ">public</span><span style="color: #000000; "> boolean methodA(String sParam1){
</span><span style="color: #0000ff; ">if</span><span style="color: #000000; "> (A.S_CONSTANT_ABC.equalsIgnoreCase(sParam1)){
</span><span style="color: #0000ff; ">return</span> <span style="color: #0000ff; ">true</span><span style="color: #000000; ">;
}
</span><span style="color: #0000ff; ">return</span> <span style="color: #0000ff; ">false</span><span style="color: #000000; ">;
}
}</span></div>
</pre>
</div>
<p style="margin-top: 0px; margin-right: 8px; margin-bottom: 0px; margin-left: 8px; color: #333333; "><font size="3">现在，每次需要将&#8220;ABC&#8221;与其他变量进行比较时，不必记住实际代码，直接引用A.S_CONSTANT_ABC就行了，而且在今后需要进行修改时，也可在一处修改，不会翻遍整个源代码逐个修改了。</font></p>
<p style="margin-top: 0px; margin-right: 8px; margin-bottom: 0px; margin-left: 8px; color: #333333; "><font size="3">&nbsp;</font><strong>五、不要&#8220;创造&#8221;自己的框架（framework）。</strong><font size="3">确切来说，有数以千计的各种框架存在，而且大多数是开源的，这些框架都是优秀的解决方案，可用于日常程序开发中，我们只需使用这些框架的最新版本就行了，至少表面上要跟上形势吧。被大家广为接受的最为明显的一个例子就是Struts了，这个开源web框架非常适合用在基于web的应用程序中。是不是想开发出自己的Struts呢，还是省点力气吧，回头看看第二条——不要让事情复杂化。另外，如果正在开发的程序只有3个窗口，就不要使用Struts了，对这种程序来说，不需要那么多的&#8220;控制&#8221;。</font></p>
<p style="margin-top: 0px; margin-right: 8px; margin-bottom: 0px; margin-left: 8px; color: #333333; "><font size="3">&nbsp;&nbsp;&nbsp;</font><strong>六、不要使用println及字符串连接。</strong><font size="3">通常为了调试方便，开发者喜欢在可能的所有地方都加上System.out.println，也许还会提醒自己回过头来再来删除，但有些时候，经常会忘了删除或者不愿意删除它们。既然使用System.out.println是为了测试，那么测试完之后，为什么还要留着它们呢，因为在删除时，很可能会删除掉真正有用的代码，所以不能低估System.out.println危害啊，请看下面的代码：</font></p>
<div style="margin-top: 0px; margin-bottom: 0px; border-style: initial; border-color: initial; text-align: left; margin-right: auto; margin-left: auto; color: #333333; ">
<pre style="font-family: 'Courier New'; white-space: pre-wrap; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; background-color: #ededed; ">
<div style="margin-top: 0px; margin-bottom: 0px; border-style: initial; border-color: initial; text-align: left; margin-right: auto; margin-left: auto; color: #333333; "><span style="color: #0000ff; ">public</span> <span style="color: #0000ff; ">class</span><span style="color: #000000; "> BadCode {
</span><span style="color: #0000ff; ">public</span> <span style="color: #0000ff; ">static</span> <span style="color: #0000ff; ">void</span><span style="color: #000000; "> calculationWithPrint(){
</span><span style="color: #0000ff; ">double</span><span style="color: #000000; "> someValue </span><span style="color: #000000; ">=</span><span style="color: #000000; "> 0D;
</span><span style="color: #0000ff; ">for</span><span style="color: #000000; "> (</span><span style="color: #0000ff; ">int</span><span style="color: #000000; "> i </span><span style="color: #000000; ">=</span> <span style="color: #000000; ">0</span><span style="color: #000000; ">; i </span><span style="color: #000000; ">&lt;</span> <span style="color: #000000; ">10000</span><span style="color: #000000; ">; i</span><span style="color: #000000; ">++</span><span style="color: #000000; ">) {
System.</span><span style="color: #0000ff; ">out</span><span style="color: #000000; ">.println(someValue </span><span style="color: #000000; ">=</span><span style="color: #000000; "> someValue </span><span style="color: #000000; ">+</span><span style="color: #000000; "> i);
}
}
</span><span style="color: #0000ff; ">public</span> <span style="color: #0000ff; ">static</span> <span style="color: #0000ff; ">void</span><span style="color: #000000; "> calculationWithOutPrint(){
</span><span style="color: #0000ff; ">double</span><span style="color: #000000; "> someValue </span><span style="color: #000000; ">=</span><span style="color: #000000; "> 0D;
</span><span style="color: #0000ff; ">for</span><span style="color: #000000; "> (</span><span style="color: #0000ff; ">int</span><span style="color: #000000; "> i </span><span style="color: #000000; ">=</span> <span style="color: #000000; ">0</span><span style="color: #000000; ">; i </span><span style="color: #000000; ">&lt;</span> <span style="color: #000000; ">10000</span><span style="color: #000000; ">; i</span><span style="color: #000000; ">++</span><span style="color: #000000; ">) {
someValue </span><span style="color: #000000; ">=</span><span style="color: #000000; "> someValue </span><span style="color: #000000; ">+</span><span style="color: #000000; "> i;
}
}
</span><span style="color: #0000ff; ">public</span> <span style="color: #0000ff; ">static</span> <span style="color: #0000ff; ">void</span><span style="color: #000000; "> main(String [] n) {
BadCode.calculationWithPrint();
BadCode.calculationWithOutPrint();
}
}</span></div>
</pre>
</div>
<p style="margin-top: 0px; margin-right: 8px; margin-bottom: 0px; margin-left: 8px; color: #333333; "><font size="3">从测试中可以发现，方法calculationWithOutPrint()执行用了0.001204秒，作为对比，方法calculationWithPrint()执行可是用了10.52秒。<br style="font-size: 12px; " />
<br style="font-size: 12px; " />
要避免浪费CPU时间，最好的方法是引入像如下的包装方法：</font></p>
<div style="margin-top: 0px; margin-bottom: 0px; border-style: initial; border-color: initial; text-align: left; margin-right: auto; margin-left: auto; color: #333333; ">
<pre style="font-family: 'Courier New'; white-space: pre-wrap; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; background-color: #ededed; ">
<div style="margin-top: 0px; margin-bottom: 0px; border-style: initial; border-color: initial; text-align: left; margin-right: auto; margin-left: auto; color: #333333; "><span style="color: #0000ff; ">public</span> <span style="color: #0000ff; ">class</span><span style="color: #000000; "> BadCode {
</span><span style="color: #0000ff; ">public</span> <span style="color: #0000ff; ">static</span><span style="color: #000000; "> final </span><span style="color: #0000ff; ">int</span><span style="color: #000000; "> DEBUG_MODE </span><span style="color: #000000; ">=</span> <span style="color: #000000; ">1</span><span style="color: #000000; ">;
</span><span style="color: #0000ff; ">public</span> <span style="color: #0000ff; ">static</span><span style="color: #000000; "> final </span><span style="color: #0000ff; ">int</span><span style="color: #000000; "> PRODUCTION_MODE </span><span style="color: #000000; ">=</span> <span style="color: #000000; ">2</span><span style="color: #000000; ">;
</span><span style="color: #0000ff; ">public</span> <span style="color: #0000ff; ">static</span> <span style="color: #0000ff; ">void</span><span style="color: #000000; "> calculationWithPrint(</span><span style="color: #0000ff; ">int</span><span style="color: #000000; "> logMode){
</span><span style="color: #0000ff; ">double</span><span style="color: #000000; "> someValue </span><span style="color: #000000; ">=</span><span style="color: #000000; "> 0D;
</span><span style="color: #0000ff; ">for</span><span style="color: #000000; "> (</span><span style="color: #0000ff; ">int</span><span style="color: #000000; "> i </span><span style="color: #000000; ">=</span> <span style="color: #000000; ">0</span><span style="color: #000000; ">; i </span><span style="color: #000000; ">&lt;</span> <span style="color: #000000; ">10000</span><span style="color: #000000; ">; i</span><span style="color: #000000; ">++</span><span style="color: #000000; ">) {
someValue </span><span style="color: #000000; ">=</span><span style="color: #000000; "> someValue </span><span style="color: #000000; ">+</span><span style="color: #000000; "> i;
myPrintMethod(logMode, someValue);
}
}
</span><span style="color: #0000ff; ">public</span> <span style="color: #0000ff; ">static</span> <span style="color: #0000ff; ">void</span><span style="color: #000000; "> myPrintMethod(</span><span style="color: #0000ff; ">int</span><span style="color: #000000; "> logMode, </span><span style="color: #0000ff; ">double</span><span style="color: #000000; "> value) {
</span><span style="color: #0000ff; ">if</span><span style="color: #000000; "> (logMode </span><span style="color: #000000; ">&gt;</span><span style="color: #000000; "> BadCode.DEBUG_MODE) { </span><span style="color: #0000ff; ">return</span><span style="color: #000000; ">; }
System.</span><span style="color: #0000ff; ">out</span><span style="color: #000000; ">.println(value);
}
</span><span style="color: #0000ff; ">public</span> <span style="color: #0000ff; ">static</span> <span style="color: #0000ff; ">void</span><span style="color: #000000; "> main(String [] n) {
BadCode.calculationWithPrint(BadCode.PRODUCTION_MODE);
}
}</span></div>
</pre>
</div>
<p style="margin-top: 0px; margin-right: 8px; margin-bottom: 0px; margin-left: 8px; color: #333333; "><font size="3">另外，字符串连接也是浪费CPU时间的一个大头，请看下面的示例代码：</font></p>
<div style="margin-top: 0px; margin-bottom: 0px; border-style: initial; border-color: initial; text-align: left; margin-right: auto; margin-left: auto; color: #333333; ">
<pre style="font-family: 'Courier New'; white-space: pre-wrap; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; background-color: #ededed; ">
<div style="margin-top: 0px; margin-bottom: 0px; border-style: initial; border-color: initial; text-align: left; margin-right: auto; margin-left: auto; color: #333333; "><span style="color: #0000ff; ">public</span> <span style="color: #0000ff; ">static</span> <span style="color: #0000ff; ">void</span><span style="color: #000000; "> concatenateStrings(String startingString) {
</span><span style="color: #0000ff; ">for</span><span style="color: #000000; "> (</span><span style="color: #0000ff; ">int</span><span style="color: #000000; "> i </span><span style="color: #000000; ">=</span> <span style="color: #000000; ">0</span><span style="color: #000000; ">; i </span><span style="color: #000000; ">&lt;</span> <span style="color: #000000; ">20</span><span style="color: #000000; ">; i</span><span style="color: #000000; ">++</span><span style="color: #000000; ">) {
startingString </span><span style="color: #000000; ">=</span><span style="color: #000000; "> startingString </span><span style="color: #000000; ">+</span><span style="color: #000000; "> startingString;
}
}
</span><span style="color: #0000ff; ">public</span> <span style="color: #0000ff; ">static</span> <span style="color: #0000ff; ">void</span><span style="color: #000000; "> concatenateStringsUsingStringBuffer(String startingString) {
StringBuffer sb </span><span style="color: #000000; ">=</span> <span style="color: #0000ff; ">new</span><span style="color: #000000; "> StringBuffer();
sb.append(startingString);
</span><span style="color: #0000ff; ">for</span><span style="color: #000000; "> (</span><span style="color: #0000ff; ">int</span><span style="color: #000000; "> i </span><span style="color: #000000; ">=</span> <span style="color: #000000; ">0</span><span style="color: #000000; ">; i </span><span style="color: #000000; ">&lt;</span> <span style="color: #000000; ">20</span><span style="color: #000000; ">; i</span><span style="color: #000000; ">++</span><span style="color: #000000; ">) {
sb.append(sb.toString());
}
}</span></div>
</pre>
</div>
<p style="margin-top: 0px; margin-right: 8px; margin-bottom: 0px; margin-left: 8px; color: #333333; "><font size="3">在测试中可发现，使用StringBuffer的方法只用了0.01秒执行完毕，而使用连接的方法则用了0.08秒，选择显而易见了。</font></p>
<p style="margin-top: 0px; margin-right: 8px; margin-bottom: 0px; margin-left: 8px; color: #333333; "></p>
<p style="margin-top: 0px; margin-right: 8px; margin-bottom: 0px; margin-left: 8px; color: #333333; "><strong><font size="3">七、多关注GUI（用户界面）。</font></strong><font size="3">再三强调，GUI对商业客户来说，与程序的功能及效率同等重要，GUI是一个成功程序的最基本部分，而很多IT经理往往都没注意到GUI的重要性。在现实生活中，许多公司可能为了节省开支，没有雇用那些有着设计&#8220;用户友好&#8221;界面丰富经验的网页设计者，此时Java开发者只能依赖他们自身的HTML基本功及在此领域有限的知识，结果，很多开发出来的程序都是&#8220;计算机友好&#8221;甚于&#8220;用户友好&#8221;。很少有开发者同时精通软件开发及GUI设计，如果你在公司&#8220;不幸&#8221;被分配负责程序界面，就应该遵守下面三条原则：</font></p>
<p style="margin-top: 0px; margin-right: 8px; margin-bottom: 0px; margin-left: 8px; color: #333333; "><font size="3">1、 不要再发明一次轮子，即不做无用功。现有的程序可能会有类似的界面需求。<br style="font-size: 12px; " />
2、 先创建一个原型。这是非常重要一步，用户一般想看到他们将使用的东西，而且可以先利用这个原型征求用户的意见，再慢慢修改成用户想要的样子。<br style="font-size: 12px; " />
3、 学会换位思考。换句话来说，就是从用户的角度来审查程序的需求。举例来讲，一个汇总的窗口可以跨页或者不跨页，作为一个软件开发者，可能会倾向于不跨页，因为这样简单一些。但是，从用户的角度来看，可能不希望看到上百行数据都挤在同一页上。</font></p>
<p style="margin-top: 0px; margin-right: 8px; margin-bottom: 0px; margin-left: 8px; color: #333333; "><strong><font size="3">&nbsp;&nbsp; 八、文档需求不放松。</font></strong><font size="3">每个商业需求都必须记录在案，这可能听上去像童话，似乎在现实生活中很难实现。而我们要做的是，不管开发时间多紧迫，不管最终期限多临近，对每个商业需求都必须记录在案。</font></p>
<p style="margin-top: 0px; margin-right: 8px; margin-bottom: 0px; margin-left: 8px; color: #333333; "><font size="3">&nbsp;&nbsp;&nbsp;</font><strong><font size="3">九、单元测试、单元测试、单元测试。</font></strong><font size="3">关于什么是单元测试的最好方法，在此不便细说，只是强调，单元测试一定要完成，这也是编程中最基本的原则。当然了，如果有人帮你做单元测试自然是最好，如果没有，就自己来做吧，当创建一个单元测试计划时，请遵守以下三条最基本的原则：</font></p>
<p style="margin-top: 0px; margin-right: 8px; margin-bottom: 0px; margin-left: 8px; color: #333333; "><font size="3">1、 先于编写类代码之前编写单元测试。<br style="font-size: 12px; " />
2、 记录单元测试中的代码注释。<br style="font-size: 12px; " />
3、 测试所有执行关键功能的公有方法，这里不是指set和get方法，除非它们是以自己独特方式执行set和get方法。</font></p>
<p style="margin-top: 0px; margin-right: 8px; margin-bottom: 0px; margin-left: 8px; color: #333333; "><strong><font size="3">&nbsp;&nbsp; 十、质量，而不是数量。</font></strong><font size="3">有些时候因为产品问题、期限紧迫、或一些预料之外的事情，导致常常不能按时下班，但一般而言，公司不会因为雇员经常加班而对之表扬和奖励，公司只看重高质量的工作。如果遵守了前九条原则，你会发现自己写出的代码bug少且可维护性高，无形中质量提高了一大步。</font></p>
</span><img src ="http://www.blogjava.net/mlh123caoer/aggbug/296938.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2009-09-29 19:52 <a href="http://www.blogjava.net/mlh123caoer/archive/2009/09/29/296938.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Grails application now working on GlassFish v3</title><link>http://www.blogjava.net/mlh123caoer/archive/2008/03/10/185015.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Mon, 10 Mar 2008 03:53:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2008/03/10/185015.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/185015.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2008/03/10/185015.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/185015.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/185015.html</trackback:ping><description><![CDATA[<p>Recently <a href="http://glaforge.free.fr/weblog/">Guillaume</a> reported to me about his Grail app not deploying on <a href="https://glassfish.dev.java.net/downloads/v3-techPreview-2.html">GlassFish v3 Preview 2</a>. The problem reported was that the Grail app was taking lots of time to deploy on GlassFish v3 Preview 2. Although such failures are not acceptable but considering GlassFish v3 is a complete new architecture, is still under development and feature incomplete and above all the preview releases do not go thru the normal test cycle so such bugs can appear. </p>
<p>This issue was discussed at the GlassFish <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#117;&#115;&#101;&#114;&#115;&#64;&#103;&#108;&#97;&#115;&#115;&#102;&#105;&#115;&#104;&#46;&#100;&#101;&#118;&#46;&#106;&#97;&#118;&#97;&#46;&#110;&#101;&#116;">mailing list</a>, see the discussion <a href="http://forums.java.net/jive/thread.jspa?threadID=37205">here</a> and the corresponding <a href="https://glassfish.dev.java.net/issues/show_bug.cgi?id=4255">bug</a>. </p>
<p>The good news is that <a href="http://blogs.sun.com/dochez/">Jerome</a> quickly found out what the problem was and after the code went thru reviews, it was checked in and the fix went into yesterday's <a href="http://download.java.net/javaee5/v3/releases/preview/glassfish-snapshot-v3-preview-06_03_2008.zip">nightly</a> build. </p>
<p>Here is how I created and deployed a Grails application on GlassFish v3: </p>
<h3>Create a simple Grails app</h3>
<strong>Setup Grails</strong> This is the standard way you would setup the Grails environments:
<p><code></p>
<pre>    export PATH=$GRAILS_HOME/bin:$PATH
export GRAILS_HOME=/tools/grails
</pre>
</code>
<p>&nbsp;</p>
<p>&nbsp;</p>
<strong>Create a simple Grails app</strong> <code>
<pre>    vivekmz@boson(555)&gt; <strong>grails create-app MyFirstGrailsApp</strong>
Welcome to Grails 1.0.1 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: /tools/grails
Base Directory: /ws/sb
Environment set to development
Note: No plugin scripts found
Running script /tools/grails/scripts/CreateApp.groovy
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/src
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/src/java
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/src/groovy
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/grails-app
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/grails-app/controllers
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/grails-app/services
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/grails-app/domain
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/grails-app/taglib
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/grails-app/utils
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/grails-app/views
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/grails-app/views/layouts
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/grails-app/i18n
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/grails-app/conf
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/test
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/test/unit
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/test/integration
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/scripts
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/web-app
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/web-app/js
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/web-app/css
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/web-app/images
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/web-app/META-INF
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/lib
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/grails-app/conf/spring
[mkdir] Created dir: /ws/sb/MyFirstGrailsApp/grails-app/conf/hibernate
[propertyfile] Creating new property file:
/ws/sb/MyFirstGrailsApp/application.properties
[copy] Copying 2 files to /ws/sb/MyFirstGrailsApp
[copy] Copying 2 files to /ws/sb/MyFirstGrailsApp/web-app/WEB-INF
[copy] Copying 5 files to /ws/sb/MyFirstGrailsApp/web-app/WEB-INF/tld
[copy] Copying 87 files to /ws/sb/MyFirstGrailsApp/web-app
[copy] Copying 17 files to /ws/sb/MyFirstGrailsApp/grails-app
[copy] Copying 1 file to /ws/sb/MyFirstGrailsApp
[copy] Copying 1 file to /ws/sb/MyFirstGrailsApp
[copy] Copying 1 file to /ws/sb/MyFirstGrailsApp
[propertyfile] Updating property file:
/ws/sb/MyFirstGrailsApp/application.properties
Created Grails Application at /ws/sb/MyFirstGrailsApp
</pre>
</code>
<h3>Start GlassFish v3</h3>
<code>
<pre>    <strong>vivekmz@boson(735)&gt; glassfish/bin/asadmin start-domain</strong>
Mar 7, 2008 7:43:04 PM com.sun.enterprise.v3.server.AppServerStartup run
INFO: HK2 initialized in 281 ms
Mar 7, 2008 7:43:04 PM com.sun.enterprise.v3.server.AppServerStartup run
INFO: com.sun.enterprise.naming.impl.ServicesHookup@51b48197 Init done in 307 ms
Mar 7, 2008 7:43:04 PM com.sun.enterprise.v3.server.AppServerStartup run
INFO: com.sun.enterprise.v3.services.impl.CmdLineParamProcessor@9c0ec97 Init done in 310 ms
Mar 7, 2008 7:43:04 PM com.sun.enterprise.v3.server.AppServerStartup run
INFO: com.sun.enterprise.v3.server.SystemTasks@1fd0fafc Init done in 382 ms
Mar 7, 2008 7:43:04 PM com.sun.enterprise.v3.server.AppServerStartup run
INFO: com.sun.enterprise.v3.services.impl.LogManagerService@388ee016 Init done in 411 ms
Mar 7, 2008 7:43:04 PM com.sun.enterprise.v3.server.AppServerStartup run
INFO: com.sun.enterprise.v3.services.impl.HouseKeeper@a210b5b Init done in 413 ms
Mar 7, 2008 7:43:04 PM com.sun.enterprise.v3.services.impl.GrizzlyProxy start
INFO: Listening on port 8080
Mar 7, 2008 7:43:04 PM com.sun.enterprise.v3.services.impl.GrizzlyProxy start
INFO: Listening on port 8181
Mar 7, 2008 7:43:04 PM com.sun.enterprise.v3.services.impl.GrizzlyProxy start
INFO: Listening on port 4848
Mar 7, 2008 7:43:04 PM com.sun.enterprise.v3.server.AppServerStartup run
INFO: com.sun.enterprise.v3.services.impl.GrizzlyService@506f9b8e startup done in 630 ms
Mar 7, 2008 7:43:04 PM com.sun.enterprise.v3.server.AppServerStartup run
INFO: com.sun.enterprise.security.SecurityServicesUtil@585976c2 startup done in 732 ms
Mar 7, 2008 7:43:04 PM com.sun.enterprise.v3.server.AppServerStartup run
INFO: Glassfish v3 started in 733 ms
</pre>
</code><br />
You can see above it took 733ms to boot up!
<h3>Deploy the Grails App</h3>
Now that I have built <strong>MyFirstGrailsApp</strong>, it is time to deploy. So first I will create a war file:
<p><code></p>
<pre>    vivekmz@boson(558)&gt; cd MyFirstGrailsApp/
vivekmz@boson(559)&gt; <strong>grails war</strong>
</pre>
</code>
<p>&nbsp;</p>
Now Let's deploy to GlassFish v3:<br />
<code>
<pre>    vivekmz@boson(749)&gt; <strong>../glassfish/bin/asadmin deploy MyFirstGrailsApp-0.1.war</strong>
SUCCESS : MyFirstGrailsApp-0.1 deployed successfully
properties=(name=MyFirstGrailsApp-0.1)
</pre>
</code><br />
The server log tells, it took about 9.7 seconds to deploy it:
<p><code>[#|2008-03-07T20:19:03.580+0000|INFO|GlassFish10.0|javax.enterprise.system.tools.deployment|_ThreadID=12;_ThreadName=Thread-4;|Deployment of MyFirstGrailsApp-0.1 done is 9765 ms|#] </code></p>
<p>Now when I accessing http://localhost:8080/MyFirstGrailsApp-0.1/ my Grails app appears in the Firefox:</p>
<a href="http://weblogs.java.net/blog/vivekp/archive/images/grails.png"><img src="http://weblogs.java.net/blog/vivekp/archive/images/grails-small.png"  alt="" /> </a>
<p>&nbsp;</p>
<a href="https://glassfish.dev.java.net/">GlassFish v3</a> has been going thru continuous improvements and the development team is busy making it rock solid while adding new features to it. Continue sending your feedbacks to <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#117;&#115;&#101;&#114;&#115;&#64;&#103;&#108;&#97;&#115;&#115;&#102;&#105;&#115;&#104;&#46;&#100;&#101;&#118;&#46;&#106;&#97;&#118;&#97;&#46;&#110;&#101;&#116;">users@glassfish.dev.java.net</a>.<img src ="http://www.blogjava.net/mlh123caoer/aggbug/185015.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2008-03-10 11:53 <a href="http://www.blogjava.net/mlh123caoer/archive/2008/03/10/185015.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Acegi配置文档 </title><link>http://www.blogjava.net/mlh123caoer/archive/2007/12/16/168120.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Sun, 16 Dec 2007 13:38:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/12/16/168120.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/168120.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/12/16/168120.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/168120.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/168120.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 作者：javafish(likunkun) Email:javafish@sunxin.org Acegi是基于Spring的一个开源的安全认证框架，现在的最新版本是1.04。Acegi的特点就是有很多的过滤器：不过我们也用不到这么多的过滤器，只是可以把它们看作为一个个的模块，在用的时候加上自己用的着的即可，由于认证的流程的方面比较复杂导致它的配置很复杂，如果能摸清它的工作原理还是不太难....&nbsp;&nbsp;<a href='http://www.blogjava.net/mlh123caoer/archive/2007/12/16/168120.html'>阅读全文</a><img src ="http://www.blogjava.net/mlh123caoer/aggbug/168120.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-12-16 21:38 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/12/16/168120.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Acegi学习小结 </title><link>http://www.blogjava.net/mlh123caoer/archive/2007/12/16/168117.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Sun, 16 Dec 2007 13:31:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/12/16/168117.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/168117.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/12/16/168117.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/168117.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/168117.html</trackback:ping><description><![CDATA[<p><strong>一、基本原理</strong> <br />
Acegi认证授权主要基于两大技术，一是Filter机制，二是AOP的拦截机制。通过FilterSecurityInterceptor很好地实现了对URI的保护，通过MethodSecurityInterceptor实现了对Service的方法的拦截保护，通过ACL 实现了对prototype类型的Object进行过滤和保护。</p>
<p><strong>二、基本概念</strong> <br />
HttpSessionContextIntegrationFilter 存储SecurityContext in HttpSession <br />
ChannelProcessingFilter 重定向到另一种协议，如http到https</p>
<p>ConcurrentSessionFilter 因为不使用任何SecurityContextHolder的功能，但是需要更新SessionRegistry来表示当前的发送请求的principal，通过在web.xml中注册Listener监听Session事件，并发布相关消息，然后由SessionRegistry获得消息以判断当前用户的Session数量。</p>
<p>AuthenticationProcessingFilter 普通认证机制(大多数用这个)</p>
<p>CasProcessingFilter CAS认证机制</p>
<p>BasicProcessingFilter Http协议的Basic认证机制</p>
<p>HttpRequestIntegrationFilter Authentication 从容器的HttpServletRequest.getUserPrincipal()获得</p>
<p>JbossIntegrationFilter 与Jboss相关。</p>
<p>SecurityContextHolderAwareRequestFilter 与servlet容器结合使用。</p>
<p>RememberMeProcessingFilter 基于Cookies方式进行认证。</p>
<p>AnonymousProcessingFilter 匿名认证。</p>
<p>ExceptionTranslationFilter 捕获所有的Acegi Security 异常，这样要么返回一个HTTP错误响应或者加载一个对应的AuthenticationEntryPoint</p>
<p>AuthenticationEntryPoint 认证入口</p>
<p><strong>三、Acegi认证授权流程</strong> <br />
1、FilterToBeanProxy 负责代理请求给FilterChainProxy</p>
<p>2、FilterChainProxy 方便的将多个Filter串联起来，如上面基本概念中提到的各种Filter，当然如果对URI进行授权保护，也可以包含FilterSecurityInterceptor。注意各Filter的顺序。</p>
<p>3、AbstractSecurityInterceptor 调度中心。负责调用各模块完成相应功能。 <br />
FilterSecurityInterceptor 对URI进行拦截保护 <br />
AspectJSecurityInterceptor 对方法进行拦截保护 <br />
MethodSecurityInterceptor 对方法进行拦截保护</p>
<p>4、AuthenticationManager 用户认证 <br />
-&gt; AuthenticationProvider 实际进行用户认证的地方(多个)。 <br />
-&gt; UserDetailsService 返回带有GrantedAuthority的UserDetail或者抛出异常。</p>
<p>5、AccessDecisionManager(UnanimousBased/AffirmativeBased/ConsensusBased) 授权 <br />
-&gt; AccessDecisionVoter(RoleVoter/BaseAclEntryVoter) 实际投票的Voter(多个).</p>
<p>6、RunAsManager 变更GrantedAuthority</p>
<p>7、AfterInvocationManager 变更返回的对象 <br />
-&gt; BaseInvocationProvider 实际完成返回对象变更的地方(多个)。</p>
<p><strong></strong>&nbsp;</p><img src ="http://www.blogjava.net/mlh123caoer/aggbug/168117.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-12-16 21:31 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/12/16/168117.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Acegi框架介绍 </title><link>http://www.blogjava.net/mlh123caoer/archive/2007/12/16/168116.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Sun, 16 Dec 2007 13:29:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/12/16/168116.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/168116.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/12/16/168116.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/168116.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/168116.html</trackback:ping><description><![CDATA[<strong>【IT168 专稿】</strong>对于任何一个完整的应用系统，完善的 认证和授权机制是必不可少的。Acegi Security（以下简称Acegi）是一个能为基于Spring的企业应用提供强大而灵活安全访问控制解决方案的框架，Acegi已经成为 Spring官方的一个子项目，所以也称为Spring Security。它通过在Spring容器中配置一组Bean，充分利用Spring的IoC和AOP功能，提供声明式安全访问控制的功能。虽然，现在 Acegi也可以应用到非Spring的应用程序中，但在Spring中使用Acegi是最自然的方式。 <br />
Acegi可以实现业务对象方法级的安全访问控制粒度，它提供了以下三方面的应用程序的安全： <br />
<br />
<strong>? URL资源的访问控制</strong> <br />
&nbsp;&nbsp;&nbsp; 如所有用户（包括其名用户）可以访问index.jsp登录页面，而只有授权的用户可以访问/user/addUser.jsp页面。Acegi允许通过正则表达式或Ant风格的路径表达式定义URL模式，让授权用户访问某一URL匹配模式下的对应URL资源。 <br />
<br />
? <strong>业务类方法的访问控制 </strong><br />
&nbsp;&nbsp;&nbsp; Spring容器中所有Bean的方法都可以被Acegi管理，如所有用户可以调用BbtForum#getRefinedTopicCount()方法，而只有授权用户可以调用BbtForum#addTopic()方法。 <br />
<br />
<strong>? 领域对象的访问控制</strong> <br />
&nbsp;&nbsp;&nbsp; 业务类方法代表一个具体的业务操作，比如更改、删除、审批等，业务类方法访问控制解决了用户是否有调用某种操作的权限，但并未对操作的客体（领域对象）进 行控制。对于我们的论坛应用来说，用户可以调用BbtForum#updateUser(User user)方法更改用户注册信息，但应该仅限于更改自己的用户信息，也即调用BbtForum#updateUser()所操作的User这个领域对象必 须是受限的。 <br />
<br />
&nbsp;&nbsp;&nbsp; Acegi通过多个不同用途的Servlet过滤器对URL资源进行保护，在请求受保护的URL资源前，Acegi的Servlet过滤器判断用户是否有权访问目标资源，授权者被开放访问，而未未被授权者将被阻挡在大门之外。 <br />
&nbsp;&nbsp;&nbsp; Acegi通过Spring AOP对容器中Bean的受控方法进行拦截，当用户的请求引发调用Bean的受控方法时，Acegi的方法拦截器开始工作，阻止未授权者的调用。&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; 对领域对象的访问控制建立在对Bean方法保护的基础上，在最终开放目标Bean方法的执行前，Acegi将检查用户的ACL（Aeccess Control List：访问控制列表）是否包含正要进行操作的领域对象，只有领域对象被授权时，用户才可以使用Bean方法对领域对象进行处理。此外，Acegi还可 以对Bean方法返回的结果进行过滤，将一些不在当前用户访问权限范围内的领域对象剔除掉——即传统的数据可视域范围的控制。一般来说，使用Acegi控 制数据可视域未非理想的选择，相反通过传统的动态SQL的解决方案往往更加简单易行。 <br />
<br />
&nbsp;&nbsp;&nbsp; 从本质特性上来说，Servlet过滤器就是最原始的原生态AOP，所以我们可以说Acegi不但对业务类方法、领域对象访问控制采用了AOP技术方案， 对URL资源的访问控制也使用了AOP的技术方案。使用AOP技术方案的框架是令人振奋的，这意味着，开发者可以在应用程序业务功能开发完毕后，轻松地通 过Acegi给应用程序穿上安全保护的&#8220;铁布衫&#8221;。<br />
<br />
<strong>Acegi体系结构</strong> <br />
&nbsp;&nbsp;&nbsp; 乘飞机前需要通过安检，乘客必须提供身份证以验证其身份。在通过安检进入候机室后，国航、海航、南航等不同航空公司的飞机陆续到达，但你只能登上机票上对 应航班的飞机。在登机后，只能坐在机票对应的座位上——你不能抢占他人的座位，你不能在座位上刻字留念、你不能要求空姐打开机窗&#8230;&#8230; <br />
<br />
&nbsp;&nbsp;&nbsp; 乘飞机的过程最能体现安全控制的流程，我们可以从中找到身份认证、资源访问控制、领域对象安全控制的对应物：安检对应身份认证，登机对应资源访问控制而按号就座则对应领域对象安全控制。 <br />
&nbsp;&nbsp;&nbsp; Acegi通过两个组件对象完成以上安全问题的处理：AuthenticationManager（认证管理器）、AccessDecisionManager（访问控制管理器），如图 1所示：
<p align="center"><img height="249" alt="" src="http://image.it168.com/cms/2007-5-18/Image/2007518101053.JPG" width="450" /><br />
图 1 Acegi体系结构 </p>
<p>&nbsp;&nbsp;&nbsp; SecurityContextHolder是框架级的容器，它保存着和所有用户关联SecurityContext实例， SecurityContext承载着用户（也称认证主体）的身份信息的权限信息， AuthenticationManager、AccessDecisionManager将据此进行安全访问控制。 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; SecurityContext的认证主体安全信息在一个HTTP请求线程的多个调用之间是共享的（通过ThreadLocal），但它不能在多个请求之 间保持共享。为了解决这个问题，Acegi将认证主体安全信息缓存于HttpSession中，当用户请求一个受限的资源时，Acegi通过 HttpSessionContextIntegrationFilter将认证主体信息从HttpSession中加载到 SecurityContext实例中，认证主体关联的SecurityContext实例保存在Acegi容器级的 SecurityContextHolder里。当请求结束之后，HttpSessionContextIntegrationFilter执行相反的操 作，将SecurityContext中的认证主体安全信息重新转存到HttpSession中，然后从SecurityContextHolder中清 除对应的SecurityContext实例。通过HttpSession转存机制，用户的安全信息就可以在多个HTTP请求间共享，同时保证 SecurityContextHolder中仅保存当前有用的用户安全信息，其整体过程如图 2所示：</p>
<p align="center"><img height="385" alt="" src="http://image.it168.com/cms/2007-5-22/Image/2007522113014.JPG" width="441" /><br />
图 2 SecurityContext在HttpSession和请求线程间的转交过程 </p>
<p><br />
&nbsp;&nbsp;&nbsp; 当用户请求一个受限的资源时，AuthenticationManager首先开始工作，它象一个安检入口，对用户身份进行核查，用户必须提供身份认证的 凭证（一般是用户名/密码）。在进行身份认证时，AuthenticationManager将身份认证的工作委托给多个 AuthenticationProvider。因为在具体的系统中，用户身份可能存储在不同的用户信息安全系统中（如数据库、CA中心、LDAP服务 器），不同用户信息安全系统需要不同的AuthenticationProvider执行诸如用户信息查询、用户身份判断、用户授权信息获取等工作。只要 有一个AuthenticationProvider可以识别用户的身份，AuthenticationManager就通过用户身份认证，并将用户的授 权信息放入到SecurityContext中。 <br />
<br />
&nbsp;&nbsp; 当用户通过身份认证后，试图访问某个受限的程序资源时，AccessDecisionManager开始工作。 AccessDecisionManager采用民主决策机制判断用户是否有权访问目标程序资源，它包含了多个AccessDecisionVoter。 在访问决策时每个AccessDecisionVoter都拥有投票权，AccessDecisionManager统计投票结果，并按照某种决策方式根 据这些投票结果决定最终是否向用户开放受限资源的访问。 <br />
</p>
<br />
、操作类都在这些组件类的基础上进行操作。在进入Acegi框架的具体学习前，有必要事先了解一下这些承载Acegi框架重要概念的组件类。 <br />
&nbsp;&nbsp;&nbsp; 首先，我们要接触是UserDetails接口，它代表一个应用系统的用户，该接口定义了用户安全相关的信息，如用户名/密码，用户是否有效等信息，你可以根据以下接口方法进行相关信息的获取： <br />
&nbsp;&nbsp;&nbsp; String getUsername()：获取用户名；&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp; String getPassword()：获取密码；&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp; boolean isAccountNonExpired()：用户帐号是否过期；&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp; boolean isAccountNonLocked()：用户帐号是否锁定；&nbsp;<br />
&nbsp;&nbsp;&nbsp; &nbsp;boolean isCredentialsNonExpired()：用户的凭证是否过期；&nbsp;<br />
&nbsp;&nbsp;&nbsp; &nbsp;boolean isEnabled()：用户是否处于激活状态。 <br />
&nbsp;&nbsp;&nbsp; 当以上任何一个判断用户状态的方法都返回false时，用户凭证就被视为无效。 <br />
&nbsp;&nbsp;&nbsp; UserDetails还定义了获取用户权限信息的方法：GrantedAuthority[] getAuthorities()，GrantedAuthority代表用户权限信息，它定义了一个获取权限描述信息（以字符串表示，如 PRIV_COMMON）的方法：String getAuthority()。
<p align="center"><img height="131" alt="" src="http://image.it168.com/cms/2007-5-22/Image/200752214189.JPG" width="347" /><br />
图 3 用户和权限 </p>
<p>&nbsp;&nbsp;&nbsp; 在未使用Acegi之前，我们可能通过类似User、Customer等领域对象表示用户的概念，并在程序中编写相应的用户认证的逻辑。现在，你要做的一 个调整是让原先这些代表用户概念的领域类实现UserDetails接口，这样，Acegi就可以通过UserDetails接口访问到用户的信息了。&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp; UserDetails可能从数据库、LDAP等用户信息资源中返回，这要求有一种机制来完成这项工作，UserDetailsService正是充当这 一角色的接口。UserDetailsService接口很简单，仅有一个方法：UserDetails loadUserByUsername(String username) ，这个方法通过用户名获取整个UserDetails对象。 <br />
Authentication代表一个和应用程序交互的待认证用户，Acegi从类似于登录页面、Cookie等处获取待认证的用户信息（一般是用户名密码）自动构造Authentication实例。 </p>
<p align="center"><img height="102" alt="" src="http://image.it168.com/cms/2007-5-22/Image/2007522142056.JPG" width="325" /><br />
图 4 Acegi的认证用户 </p>
&nbsp;&nbsp;&nbsp; Authentication可以通过Object getPrincipal()获取一个代表用户的对象，这个对象一般可以转换为UserDetails，从中可以取得用户名/密码等信息。在 Authentication被AuthenticationManager认证之前，没有任何权限的信息。在通过认证之后，Acegi通过 UserDetails将用户对应的权限信息加载到Authentication中。Authentication拥有一个 GrantedAuthority[] getAuthorities()方法，通过该方法可以得到用户对应的权限信息。 <br />
&nbsp;&nbsp;&nbsp; Authentication和UserDetails很容易被混淆，因为两者都有用户名/密码及权限的信息，接口方法也很类似。其实 Authentication是Acegi进行安全访问控制真正使用的用户安全信息的对象，它拥有两个状态：未认证和已认证。UserDetails是代 表一个从用户安全信息源（数据库、LDAP服务器、CA中心）返回的真正用户，Acegi需要将未认证的Authentication和代表真实用户的 UserDetails进行匹配比较，通过匹配比较（简单的情况下是用户名/密码是否一致）后，Acegi将UserDetails中的其它安全信息（如 权限、ACL等）拷贝到Authentication中。这样，Acegi安全控制组件在后续的安全访问控制中只和Authentication进行交 互。 <br />
<br />
由于Acegi对程序资源进行访问安全控制时，一定要事先获取和请求用户对应的Authentication，Acegi框架必须为Authentication提供一个&#8220;寓所&#8221;，以便在需要时直接从&#8220;寓所&#8221;把它请出来，作为各种安全管理器决策的依据。 <br />
<br />
&nbsp;&nbsp;&nbsp; SecurityContextHolder就是Authentication容身的&#8220;寓所&#8221;，你可以通过 SecurityContextHolder.getContext().getAuthenication()代码获取Authentication。 细心观察一下这句代码，你会发现在SecurityContextHolder和Authentication之间存在一个getContext()中 介，这个方法返回SecurityContext对象。SecurityContext这个半路杀出来的程咬金有什么特殊的用途呢？我们知道 Authentication是用户安全相关的信息，请求线程其它信息（如登录验证码等）则放置在SecurityContext中，构成了一个完整的安 全信息上下文。SecurityContext接口提供了获取和设置Authentication的方法： <br />
 Authentication getAuthentication() <br />
 void setAuthentication(Authentication authentication)
<p align="center"><img height="119" alt="" src="http://image.it168.com/cms/2007-5-22/Image/2007522142528.JPG" width="376" /><br />
图 5 认证用户信息存储器</p>
&nbsp;&nbsp;&nbsp; SecurityContextHolder是Acegi框架级的对象，它在内部通过ThreadLocal为请求线程提供线程绑定的 SecurityContext对象。这样，任何参与当前请求线程的Acegi安全管理组件、业务服务对象等都可以直接通过 SecurityContextHolder.getContext()获取线程绑定的SecurityContext，避免通过方法入参的方式获取用户 相关的SecurityContext。 <br />
<br />
&nbsp;&nbsp;&nbsp; 线程绑定模式对于大多数应用来说是适合的，但是应用本身会创建其它的线程，那么只有主线程可以获得线程绑定SecurityContext，而主线程衍生 出的新线程则无法得到线程绑定的SecurityContext。Acegi考虑到了这些不同应用情况，提供了三种绑定SecurityContext的 模式： <br />
 SecurityContextHolder.MODE_THREADLOCAL：SecurityContext绑定到主线程，这是默认的模式； <br />
 SecurityContextHolder.MODE_GLOBAL：SecurityContext绑定到JVM中，所有线程都使用同一个SecurityContext； <br />
 SecurityContextHolder.MODE_INHERITABLETHREADLOCAL：：SecurityContext绑定到主线程及由主线程衍生的线程中。 <br />
&nbsp;&nbsp;&nbsp; 你可以通过SecurityContextHolder.setStrategyName(String strategyName)方法指定SecurityContext的绑定模式。 <br />
<br />
<strong>&nbsp; 用户认证过程</strong> <br />
　　Acegi支持多种方式的用户认证：如典型的基于数据库的认证、基于LDAP的认证、基于Yale中心认证等方式。不同的认证环境拥有不同的用户认证方式，现在我们先抛开这些具体的细节，考察一下Acegi对受限资源进行访问控制的典型过程： <br />
&nbsp;&nbsp;&nbsp; 1．你点击一个链接访问一个网页； <br />
&nbsp;&nbsp;&nbsp; 2．浏览器发送一个请求到服务器，服务器判断出你正在访问一个受保护的资源； <br />
&nbsp;&nbsp;&nbsp; 3．如果此时你并未通过身份认证，服务器发回一个响应提示你进行认证——这个响应可能是一个HTTP响应代码，抑或重定向到一个指定页面； <br />
&nbsp;&nbsp;&nbsp; 4．根据系统使用认证机制的不同，浏览器或者重定向到一个登录页面中，或者由浏览器通过一些其它的方式获取你的身份信息（如通过BASIC认证对话框、一个Cookie或一个X509证书）； <br />
&nbsp;&nbsp;&nbsp; 5．浏览器再次将用户身份信息发送到服务器上（可能是一个用户登录表单的HTTP POST信息、也可能是包含认证信息的HTTP报文头）； <br />
&nbsp;&nbsp;&nbsp; 6．服务器判断用户认证信息是否有效，如果无效，一般情况下，浏览器会要求你继续尝试，这意味着返回第3步。如果有效，则到达下一步； <br />
&nbsp;&nbsp;&nbsp; 7．服务器重新响应第2步所提交的原始请求，并判断该请求所访问的程序资源是否在你的权限范围内，如果你有权访问，请求将得到正确的执行并返回结果。否则，你将收到一个HTTP 403错误，这意味着你被禁止访问。 <br />
&nbsp;&nbsp;&nbsp; 在Acegi框架里，你可以找到对应以上大多数步骤的类，其中ExceptionTranslationFilter、AuthenticationEntryPoint、AuthenticationProvider以及Acegi的认证机制是其中的代表者。 <br />
<br />
&nbsp;&nbsp;&nbsp; ExceptionTranslationFilter是一个Acegi的Servlet过滤器，它负责探测抛出的安全异常。当一个未认证用户访问服务器 时，Acegi将引发一个Java异常。Java异常本身对HTTP请求以及如何认证用户是一无所知的， ExceptionTranslationFilter适时登场，对这个异常进行处理，启动用户认证的步骤（第3步）。如果已认证用户越权访问一个资源， Acegi也将引发一个Java异常，ExceptionTranslationFilter则将这个异常转换为HTTP 403响应码（第7步）。可见，Acegi通过异常进行通讯，<br />
ExceptionTranslationFilter接收这些异常并作出相应的动作。 <br />
<br />
&nbsp;&nbsp;&nbsp; 当ExceptionTranslationFilter通过Java异常发现用户还未认证时，它到底会将请求重定向哪个页面以要求用户提供认证信息呢？ 这通过咨询AuthenticationEntryPoint来达到目的——Acegi通过AuthenticationEntryPoint描述登录页 面。 <br />
<br />
&nbsp;&nbsp;&nbsp; 当你的浏览器通过HTTP表单或HTTP报文头向服务器提供用户认证信息时，Acegi需要将这些信息收集到Authentication中，Acegi 用&#8220;认证机制&#8221;描述这一过程。此时，这个新生成Authentication只包含用户提供的认证信息，但并未通过认证。<br />
AuthenticationProvider 负责对Authentication进行认证。AuthenticationProvider究竟如何完成这一过程呢？请回忆一下上节我们所介绍的 UserDetails和UserDetailsService，大多数AuthenticationProvider通过 UserDetailsService获取和未认证的Authentication对应的UserDetails并进行匹配比较来完成这一任务。当用户认 证信息匹配时，Authentication被认为是有效的，AuthenticationProvider进一步将UserDetails中权限、 ACL等信息拷贝到Authentication。 <br />
当Acegi通过认证机制收集到用户认证信息并填充好Authentication后，Authentication将被保存到SecurityContextHolder中并处理用户的原始请求（第7步）。 <br />
<br />
&nbsp;&nbsp;&nbsp; 你完全可以抛开Acegi的安全机制，编写自己的Servlet过滤器，使用自己的方案构建Authentication对象并将其放置到SecurityContextHolder中。也许你使用了CMA（Container <br />
Managed Authentication：容器管理认证），CMA允许你从ThreadLocal或JNDI中获取用户认证信息，这时你只要获取这些信息并将其转换为Authentication就可以了。 <br />
<br />
<strong>&nbsp;&nbsp; 安全对象访问控制 <br />
</strong>&nbsp;&nbsp;&nbsp; Acegi称受保护的应用资源为&#8220;安全对象&#8221;，这包括URL资源和业务类方法。我们知道在Spring AOP中有前置增强、后置增强、异常增强和环绕增强，其中环绕增强的功能最为强大——它不但可以在目标方法被访问前拦截调用，还可以在调用返回前改变返回 的结果，甚至抛出异常。Acegi使用环绕增强对安全对象进行保护。 <br />
&nbsp;&nbsp;&nbsp; Acegi通过AbstractSecurityInterceptor为安全对象访问提供一致的工作模型，它按照以下流程进行工作： <br />
&nbsp;&nbsp;&nbsp; 1． 从SecurityContext中取出已经认证过的Authentication（包括权限信息）； <br />
&nbsp;&nbsp;&nbsp; 2． 通过反射机制，根据目标安全对象和&#8220;配置属性&#8221;得到访问目标安全对象所需的权限； <br />
&nbsp;&nbsp;&nbsp; 3． AccessDecisionManager根据Authentication的授权信息和目标安全对象所需权限做出是否有权访问的判断。如果无权访问，Acegi将抛出AccessDeniedException异常，否则到下一步； <br />
4． 访问安全对象并获取结果（返回值或HTTP响应）； <br />
5． AbstractSecurityInterceptor可以在结果返回前进行处理：更改结果或抛出异常。 &nbsp;&nbsp;&nbsp; Acegi称受保护的应用资源为&#8220;安全对象&#8221;，这包括URL资源和业务类方法。我们知道在Spring AOP中有前置增强、后置增强、异常增强和环绕增强，其中环绕增强的功能最为强大——它不但可以在目标方法被访问前拦截调用，还可以在调用返回前改变返回 的结果，甚至抛出异常。Acegi使用环绕增强对安全对象进行保护。 &nbsp;&nbsp;&nbsp; Acegi通过AbstractSecurityInterceptor为安全对象访问提供一致的工作模型，它按照以下流程进行工作： &nbsp;&nbsp;&nbsp; 1． 从SecurityContext中取出已经认证过的Authentication（包括权限信息）； &nbsp;&nbsp;&nbsp; 2． 通过反射机制，根据目标安全对象和&#8220;配置属性&#8221;得到访问目标安全对象所需的权限； &nbsp;&nbsp;&nbsp; 3． AccessDecisionManager根据Authentication的授权信息和目标安全对象所需权限做出是否有权访问的判断。如果无权访问， Acegi将抛出AccessDeniedException异常，否则到下一步； 4． 访问安全对象并获取结果（返回值或HTTP响应）； 5． AbstractSecurityInterceptor可以在结果返回前进行处理：更改结果或抛出异常。
<p align="center"><img height="187" alt="" src="http://image.it168.com/cms/2007-5-22/Image/2007522143216.JPG" width="450" /><br />
图 6 AbstractSecurityInterceptor工作流程 </p>
<p>&nbsp;&nbsp;&nbsp; 安全对象和一般对象的区别在于前者通过Acegi的&#8220;配置属性&#8221;进行了描述，如&#8220;/view.jsp=PRIV_COMMON&#8221;配置属性就将 &#8220;/view.jsp&#8221;这个URL资源标识为安全对象，它表示用户在访问/view.jsp时，必须拥有PRIV_COMMON这个权限。配置属性通过 XML配置文件，注解、数据库等方式提供。安全对象通过配置属性表示为一个权限，这样，Acegi就可以根据Authentication的权限信息获知 用户可以访问的哪些安全对象。 <br />
&nbsp;&nbsp;&nbsp; 根据安全对象的性质以及具体实现技术，AbstractSecurityInterceptor拥有以下三个实现类： <br />
 FilterSecurityInterceptor：对URL资源的安全对象进行调用时，通过该拦截器实施环绕切面。该拦截器使用Servlet过滤器实现AOP切面，它本身就是一个Servlet过滤器； <br />
 MethodSecurityInterceptor：当调用业务类方法的安全对象时，可通过该拦截器类实施环绕切面； <br />
 AspectJSecurityInterceptor：和MethodSecurityInterceptor类似，它是针对业务类方法的拦截器，只不过它通过AspectJ实施AOP切面。 <br />
</p>
<br />
<strong>&nbsp; Acegi版本升级的一些重大变化&nbsp;<br />
</strong>&nbsp;&nbsp;&nbsp; Acegi项目开始于2003年，Acegi团队在发布新版本时非常谨慎，在本书写作之时，Acegi最新版本为1.0.3。在此之前Acegi已经发布 了10多个预览版本，由于Acegi框架优异的表现，许多大型应用早在Acegi 1.0正式版本发布之前（2006年5月），就已经采用Acegi框架作为其安全访问控制的解决方案。<br />
<br />
&nbsp;&nbsp;&nbsp; 在Acegi社区里，来自世界各地众多优秀的安全领域专家对Acegi的改进和发展献计献策，Acegi团队广泛听取并吸收各种有益的建议，将它们融入到Acegi的框架中，使Acegi成为构建在Spring基础上企业应用的首选安全控制框架。 <br />
Acegi 1.0.3版本相比于早期预览版本发生了很大的变化，对于需要进行Acegi版本的项目来说，了解这一变化特别重要。下面，我们列出Acegi的一些重大的升级更新： <br />
 包名的更新：在0.9.0及之前的版本中，Acegi采用net.sf.acegisecurity包名前缀，在1.0.0版本之后更改为 org.acegisecurity（Hibernate也走过相同的道路，好在Acegi在正式版本发布之时就完成了这种转变）； <br />
<br />
 ACL模块的调整：ACL模块发生了重大的调整，Acegi团队接收了社区大量关于ACL模块的反馈意见，重新设计了ACL模块的底层结构，在性能、封装 性、灵活性上得到了质的提升。事实上，Acegi使用org.acegisecurity.acls包代替了原来的 org.acegisecurity.acl包，后者将在后期的版本中删除，由于这种伤筋动骨的变化，将很难兼容原来ACL模块。不过，目前基于新框架的 ACL模块还没有进行充分的测试，Acegi承诺在1.1.0版本发布时提供最终的实现； <br />
<br />
 删除了ContextHolder及其相关类：在Acegi 0.9版本中，ContextHolder及其相关类被彻底从Acegi项目中删除。ContextHolder可以在多个HTTP请求中共享同一个 ThreadLocal，这和Spring提倡的ThreadLocal只应在同一线程中共享相悖。现在，Acegi使用 SecurityContextHolder替换ContextHolder，它的生命周期是一个HTTP 请求； <br />
<br />
 使用FilterChainProxy同时代理多个过滤器：在早期的版本中，Acegi通过FilterToBeanProxy将web.xml中的 Servlet过滤器定义转移到Spring容器中。这比直接在web.xml中配置Servlet过滤器要方便一些，但是Acegi框架往往需要定义多 个Servlet过滤器，使web.xml配置文件变得冗长难看。在Acegi 0.8版本中提供FilterChainProxy，它可以同时代理多个Servlet过滤器并保证过滤器的顺序。因此在新版本中， FilterChainProxy成为推荐的选择。 <br />
<br />
<strong>&nbsp;&nbsp;&nbsp; 小结</strong> <br />
&nbsp;&nbsp;&nbsp; Acegi是Spring项目下一个成熟的安全访问控制框架，它允许利用了Spring IoC的AOP的功能完成安全对象的访问控制。在Acegi框架中，SecurityContextHolder处于非常核心的位置，它是存放认证管理器 用户安全信息SecurityContext的&#8220;容器&#8221;，SecurityContext保存着用户安全访问控制所需的信息，直接被访问决策管理器使用。 HttpSessionContextIntegrationFilter通过在SecurityContextHolder和HttpSession中 摆渡SecurityContext，使多个请求线程可以共享同一个SecurityContext。<br /><img src ="http://www.blogjava.net/mlh123caoer/aggbug/168116.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-12-16 21:29 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/12/16/168116.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> JBossTools 和Red Hat Developer Studio 新的beta版发布</title><link>http://www.blogjava.net/mlh123caoer/archive/2007/10/09/151253.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Tue, 09 Oct 2007 01:46:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/10/09/151253.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/151253.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/10/09/151253.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/151253.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/151253.html</trackback:ping><description><![CDATA[<p><a class="regularLink" href="http://labs.jboss.com/tools/download/index.html" target="">JBoss Tools</a>&nbsp;和<a class="regularLink" href="http://www.redhat.com/developers/rhds/index.html" target="">Red Hat Developer Studio</a>新的beta版今天发布。 </p>
<p>这个对于Seam 1.2 用户来说是个好消息，因为我们现在完全支持创建Eclipse WTP兼容包括Seam 1.2.1的Seam组件热部署项目。增加完全增量异步部署到JBoss AS server中，你能得到既快又好的部署环境。 </p>
<p>该发布版也支持Hibernate Tools用户的一些新功能和其他的bug修复。你能阅读<a class="regularLink" href="http://docs.jboss.org/tools/whatsnew/" target="">What's New and Noteworthy</a> 这篇文章了解它们。</p>
<p>尽管现在还不支持Seam 2的项目创建向导，但是代码完成和Seam视图能和Seam 2相容。仅需要右击项目增加<q>Seam支持。大家赶紧试一下啊，Seam可是将来的主流啊。</q></p><img src ="http://www.blogjava.net/mlh123caoer/aggbug/151253.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-10-09 09:46 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/10/09/151253.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>web测试总结</title><link>http://www.blogjava.net/mlh123caoer/archive/2007/09/30/149767.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Sun, 30 Sep 2007 01:33:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/09/30/149767.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/149767.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/09/30/149767.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/149767.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/149767.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 在Web工程过程中，基于Web系统的测试、确认和验收是一项重要而富有挑战性的工作。基于Web的系统测试与传统的软件测试不同，它不但需要检查和验证是否按照设计的要求运行，而且还要测试系统在不同用户的浏览器端的显示是否合适。重要的是，还要从最终用户的角度进行安全性和可用性测试。然而，Internet和Web媒体的不可预见性使测试基于Web的系统变得困难。因此，我们必须为测试和评估复杂的基于Web的系统研究新的方法和技术。 &nbsp;&nbsp;<a href='http://www.blogjava.net/mlh123caoer/archive/2007/09/30/149767.html'>阅读全文</a><img src ="http://www.blogjava.net/mlh123caoer/aggbug/149767.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-09-30 09:33 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/09/30/149767.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Web bean 未发布版最新进程</title><link>http://www.blogjava.net/mlh123caoer/archive/2007/09/23/147509.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Sun, 23 Sep 2007 00:56:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/09/23/147509.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/147509.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/09/23/147509.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/147509.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/147509.html</trackback:ping><description><![CDATA[<h3 goog_ds_charindex="1">第一部分: 介绍Web Bean<br />
</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 我们现在真的临近发布一个Web bean的社区预览草案。该草案的目的是收集关于我们定义的组件模型，依赖管理模型和扩展上下文模型的反馈，希望让人们对Web <br />
Bean感兴趣。我们也需要在其他的EE6 相关专家组的前面开展我们的工作，以至于它们可以考虑如何同我们已定义的一些机制尽可能的重用和集成。然而，该规范本质就<br />
是用高级技术性语言写的，因此在此blog是第一个以系列文章的友好形式介绍Web bean（也就是说我的翻译是国人第一份，哈哈。）当社区预览草案发布以后，请花时<br />
间下载和审查它。但是请先读此系列文章。</p>
<h2>历史回顾</h2>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 首先介绍一下背景。Web bean 是由 <a class="regularLink" href="http://jboss.org/">JBoss</a>&nbsp;创造的，帮助填平Java EE5的裂隙。EE 5平台对用成熟的技术包括EJB3，JTA，JCA和JPA来访问事务资源提供了极大<br />
支持。当然，此平台也以支持广泛的Web表现技术例如Java Servlets,JSP和JSF作为特征。然而，Web层和事务层彼此独立发展，已经失去了发展一个为访问企业事务<br />
资源的Web应用共享的组件模型的机会。今天，Web Bean正在以JBoss，Sun，Oracle和Google作为代表,以及一些独立成员支持下发展。组件模型受到<a class="regularLink" href="http://code.google.com/p/google-guice/">Google Guice<br />
</a>和<a class="regularLink" href="http://jboss.com/products/seam">Seam</a>的极大影响。</p>
<h3>Java EE的一个统一组件模型</h3>
<p>Web bean是一个同两层技术相兼容的组件模型。Web bean同JSF和EJB3集成，允许一个EJB3会话bean作为一个JSF可管理的活动，因此同这两个组件模型兼容。另外，Web bean提供一个会话模型和持久化上下文管理，因此解决了影响JSF和JPA的状态管理问题和优化事务管理问题。总而言之，Web bean 使建立通过JPA访问数据库的Java EE Web应用程序更容易开发。当web bean为JSF和EJB3的集成提供一个轻快实现时，组件模型变得更通用。特别是，它支持没有JSF或没有EJB3的情况下的使用。较早提出的一个问题是某种程度上Web bean被限制在EE和EJB3环境下。专家组无异议的决定是: </p>
<ol>
    <li>一个Web bean不必是一个EJB；
    <li>Web bean应该可以在容器外执行。 </li>
</ol>
<p>第一个决定只认识到不是每一个组件都需要EJB服务（例如声明式事务，授权等）的事实。然而，Web bean将不复制此项功能，所以当需要这些服务时，Web bean需要写成会话bean。第二个决定允许组件在应用服务器外面集成或单元测试，允许代码级重用，例如一个批处理过程。</p>
<p>一些会员，尤其<a class="regularLink" href="http://crazybob.org/">Bob Lee</a>，认为我们已做的工作只是在EE平台外面有用，并且特别是组件模型应考虑Java SE中的使用。然而，作为规范领导和根据我们JSR提议的语言，我做出决定清晰的指定目标环境是Java EE，限制我们的争论在EE开发者需要什么。</p>
<p>如果将来，有来自社区和JCP的压力开放Web bean的一部分（例如高级Guice样式依赖注入引擎）的话，我们能够在那时跟从在EJB3专家组有JPA建立的先例，定义EE平台以外的行为。 </p>
<h2>Web bean 组件</h2>
<p>精确地说一个Web bean是什么？ </p>
<p>一个Web bean是一个包含业务逻辑的应用组件。一个Web bean可以从Java 代码中被调用，或者通过统一了的EL调用。一个Web bean 可以访问事务资源。两个Web bean的依赖由Web bean容器自动管理。大多数Web Bean是有状态和上下文的。一个Web bean的生命周期总是由容器管理。让我们稍微回顾一下。它对于上下文意味着什么呢？因为Web bean是有状态的，所以它同我有哪一个bean实例有关。同一个无状态组件模型（无状态会话bean）或者单例组件模型（例如serlets）不一样，一个组件的不同客户端看到组件的不同状态。客户端可见状态依赖于客户端有哪一个组件实例的引用。</p>
<p>然而，象一个无状态会话bean或单例模型一样，象JSF，但是与有状态会话bean不一样，客户端不通过显式创建和破坏它来控制实例的生命周期。作为代替，一个上下文定义： </p>
<ul>
    <li>实力的生命周期
    <li>此实例对于客户端的可见作用域 </li>
</ul>
<p>所以在相同作用域执行的客户端（例如其它Web bean）将看到同一实例。但是，在不同作用域的客户端将看到不同实例。上下文模型一个很大的优势是它允许象创建服务一样创建有状态组件。客户端不需要它使用的管理的组件生命周期关注它自己，也不需要知道生命周期是什么。组件通过传送消息交互，组件实现定义了它们自己状态的生命周期。之所以此组件是松散耦合的，是因为： </p>
<ul>
    <li>它们通过定义良好的公共API交互
    <li>它们的生命周期完全被解耦 </li>
</ul>
<p>我们能够用实现相同API和有一个不影响其它组件实现的不同生命周期的另一个不同组件替代组件。实际上，Web bean为在足够人工拦截的重写组件实现定义了一个部署时的高级功能，这将在我们将来安装时看到。更正规的是，根据该规范： </p>
<blockquote>一个Web bean组件包括：
<ul>
    <li>组件类型
    <li>或这是一个bean实现类或者是解析方法
    <li>一系列的API类型
    <li>一系列（可能为空）的绑定批注类型
    <li>作用域
    <li>组件名 </li>
</ul>
</blockquote>
<p>让我们看一看这些条目对于组建开发者来说意味着什么。 </p>
<h3>组件类型</h3>
<p>我们现在关于组件类型所需要知道的是一个Web bean开发者可能定义一些享元作为批注，例如允许全部组件集合在特定系统部署中有条件的安装的<tt>@Mock</tt>, <tt>@Staging</tt>&nbsp;或者 <tt>@AustralianTaxLaw</tt>。我们在后一节中的更多讨论这个独一无二的强大功能。 </p>
<p>一个非常简单的Web bean可能仅使用内置的组件类型<tt>@Component：</tt> </p>
<pre>@Component
public class Credentials { ... }</pre>
<p>组件前场景类型批注识别此类作为一个Web bean到Web bean容器中。 </p>
<h3>API 类型，绑定批注和依赖注入</h3>
<p>Web bean通常通过依赖注入获得对于其它Web bean的引用。任何注入型参数指定一个组件必须满足的契约。契约为： </p>
<ul>
    <li>一个API
    <li>一个&nbsp;（可能为空）绑定批注集合 </li>
</ul>
<p>一个API是用户定义类或者接口。（如果组件是一个EJB会话bean，那么此API类型是<tt>@Local接口。）一个绑定批注是一个本身用@BindingType注解的用户定义批注</tt>。容器搜索满足契约（实现此API和支持绑定批注）的组件，注入那个组件。例如，如果这个是注入点： </p>
<pre>@In @CreditCard PaymentProcessor paymentProcessor;</pre>
<p>以下组件将被注入： </p>
<pre>@CreditCard @Component
public class CreditCardPaymentProcessor
implements PaymentProcessor { ... }</pre>
<p>Web bean定一个高级但是直接解析算法，它帮助容器决定如果超过一个组件满足一个指定契约的话将做什么。我们将在以后文章中详细介绍。 </p>
<h3>组件作用域</h3>
<p>作用域定义组件实例的生命周期和可见性。Web bean上下文模型是可扩展的，The <em>scope</em> defines the lifecycle and visibility of instances of the component. The Web Beans context model is extensible, 包含模糊作用域。然而，对于规范来说某个重要的作用域是内置的，有Web bean容器来提供。例如，任何Web 应用程序都可访问一个会话作用域： </p>
<pre>@SessionScoped @Component
public class ShoppingCart { ... }</pre>
<p>我们将在以后文章中详细介绍作用域。 </p>
<h3>组件名和统一表达式语言（EL）</h3>
<p>所有Web bean可以通过名字在统一EL表达式中使用。自定制一个Web bean名字是很容易的：</p>
<p>@SessionScoped @Component @Named("cart")<br />
public class ShoppingCart { ... }</p>
<p>到那时我们能很容易在JSF页使用此组件： </p>
<pre>&lt;h:dataTable value="#{cart.lineItems}" var="item"&gt;
....
&lt;/h:dataTable&gt;</pre>
<h3>解析方法和<tt>web-beans.xml文件</tt></h3>
<p>大多数Web bean通过写一个实现类和注解它来定义。然而，有另外两种定义一个Web bean的方式： </p>
<ol>
    <li>通过一个XML部署描述文件<tt>web-beans.xml</tt>
    <li>通过写一个解析方法 </li>
</ol>
<p>我们在将来的文章中介绍<tt>web-beans.xml文件。</tt> </p>
<p>一个解析方法是一在当前上下文中没有实例存在时由容器调用它来获得一个组件实例的方法。例如： </p>
<pre>@SessionScoped @Component
public class Login {
User user;
...
public void login() {
user = ...;
}
@Resolves @LoggedIn User getCurrentUser() {
return user;
}
}</pre>
<p>一个解析方法是第一个类Web bean组件。再一次的告诉大家，后面章节继续介绍它。</p>
<h3>登录</h3>
<p>让我们通过梳理以下前面的例子来描述一下这些观点。我们将实现用户登录/注出。首先我们将定义一个组件包含用户名和密码，这些将在登录过程中用到： </p>
<pre>@Component
public class Credentials {
private String username;
private String password;
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
}</pre>
<p>此组件绑定到登录在以下JSF表格的提示符下： </p>
<pre>&lt;f:form&gt;
&lt;h:panelGrid columns="2" rendered="#{!login.isLoggedIn}"&gt;
&lt;h:outputLabel for="username"&gt;Username:&lt;/h:outputLabel&gt;
&lt;h:inputText id="username" value="#{credentials.username}"/&gt;
&lt;h:outputLabel for="password"&gt;Password:&lt;/h:outputLabel&gt;
&lt;h:inputText id="password" value="#{credentials.password}"/&gt;
&lt;/h:panelGrid&gt;
&lt;h:commandButton action="#{login.login}" rendered="#{!login.isLoggedIn}"/&gt;
&lt;h:commandButton acion="#{login.logout}" rendered="#{login.isLoggedIn}"/&gt;
&lt;/f:form&gt;</pre>
<p>实际工作由一个维护关于当前进入的用户信息和向其他组件暴露用户实体的会话作用域组件去做： </p>
<pre>@SessionScoped @Component
public class Login {
@In Credentials credentials;
@In @UserDatabase EntityManager userDatabase;
private User user;
public void login() {
List&lt;User&gt; results = userDatabase.createQuery(
"select u from User u where u.username=:username and u.password=:password")
.setParameter("username", credentials.getUserName())
.setParameter("password", credentials.getPassword())
.getResultList();
if ( !results.isEmpty() ) {
user = results.get(0);
}
}
public void logout() {
user = null;
}
public boolean isLoggedIn() {
return user!=null;
}
@Resolves @LoggedIn User getCurrentUser() {
return user;
}
}</pre>
<p>当然，<tt>@LoggedIn是一个绑定批注：</tt> </p>
<pre>@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD})
@BindingType
public @interface LoggedIn {}</pre>
<p>现在，任何其它的组件能够很容易注入当前用户：</p>
<pre>@Component
public class DocumentEditor {
@In @Current Document document;
@In @LoggedIn User currentUser;
@In @DocumentDatabase EntityManager docDatabase;
public void save() {
document.setCreatedBy(currentUser);
docDatabase.persist(document);
}
}</pre>
<h2>大家继续关注我啊！</h2>
<p>希望这篇文章为您理解Web bean组件模型提供帮助。有更多的东西需要讨论，我希望您将有时间看一看此系列文章的剩余部分。&nbsp;</p>
——————来自牛哄哄的Hibernate之父 Gavin King<img src ="http://www.blogjava.net/mlh123caoer/aggbug/147509.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-09-23 08:56 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/09/23/147509.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>依赖注入和单元测试</title><link>http://www.blogjava.net/mlh123caoer/archive/2007/09/14/145190.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Fri, 14 Sep 2007 09:07:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/09/14/145190.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/145190.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/09/14/145190.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/145190.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/145190.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 也许在各位读者眼里，依赖注入和框架Spring等同的。其实依赖注入是一个可以在容器外使用的OO开发概念。同时，依赖注入（Dependency Injection）对于单元测试<br>也很有用。在该篇blog中，我们可以了解到：<br><br>    * 什么是依赖注入（Dependency Injection）<br>    * 如何保证类和依赖注入友好性<br>    * 依赖注入有助于单元测试<br>&nbsp;&nbsp;<a href='http://www.blogjava.net/mlh123caoer/archive/2007/09/14/145190.html'>阅读全文</a><img src ="http://www.blogjava.net/mlh123caoer/aggbug/145190.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-09-14 17:07 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/09/14/145190.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转 ：Hibernate包作用总结</title><link>http://www.blogjava.net/mlh123caoer/archive/2007/09/11/144351.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Tue, 11 Sep 2007 11:55:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/09/11/144351.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/144351.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/09/11/144351.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/144351.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/144351.html</trackback:ping><description><![CDATA[Hibernate一共包括了23个jar包，令人眼花缭乱。本文将详细讲解Hibernate每个jar包的作用，便于你在应用中根据自己的需要进行取舍。 <br />
<br />
下载Hibernate，例如2.0.3稳定版本，解压缩，可以看到一个hibernate2.jar和lib目录下有22个jar包： <br />
<br />
hibernate2.jar: <br />
Hibernate的库，没有什么可说的，必须使用的jar包 <br />
<br />
cglib-asm.jar: <br />
CGLIB库，Hibernate用它来实现PO字节码的动态生成，非常核心的库，必须使用的jar包 <br />
<br />
dom4j.jar: <br />
dom4j是一个Java的XML API，类似于jdom，用来读写XML文件的。dom4j是一个非常非常优秀的Java XML
API，具有性能优异、功能强大和极端易用使用的特点，同时它也是一个开放源代码的软件，可以在SourceForge上找到它。在IBM
developerWorks上面可以找到一篇文章，对主流的Java XML
API进行的性能、功能和易用性的评测，dom4j无论在那个方面都是非常出色的。我早在将近两年之前就开始使用dom4j，直到现在。如今你可以看到越
来越多的Java软件都在使用dom4j来读写XML，特别值得一提的是连Sun的JAXM也在用dom4j。这是必须使用的jar包，
Hibernate用它来读写配置文件。 <br />
<br />
odmg.jar: <br />
ODMG是一个ORM的规范，Hibernate实现了ODMG规范，这是一个核心的库，必须使用的jar包。 <br />
<br />
commons-collections.jar： <br />
Apache Commons包中的一个，包含了一些Apache开发的集合类，功能比java.util.*强大。必须使用的jar包。 <br />
<br />
commons-beanutils.jar： <br />
Apache Commons包中的一个，包含了一些Bean工具类类。必须使用的jar包。 <br />
<br />
commons-lang.jar: <br />
Apache Commons包中的一个，包含了一些数据类型工具类，是java.lang.*的扩展。必须使用的jar包。 <br />
<br />
commons-logging.jar: <br />
Apache Commons包中的一个，包含了日志功能，必须使用的jar包。这个包本身包含了一个Simple
Logger，但是功能很弱。在运行的时候它会先在CLASSPATH找log4j，如果有，就使用log4j，如果没有，就找JDK1.4带的
java.util.logging，如果也找不到就用Simple
Logger。commons-logging.jar的出现是一个历史的的遗留的遗憾，当初Apache极力游说Sun把log4j加入JDK1.4，
然而JDK1.4项目小组已经接近发布JDK1.4产品的时间了，因此拒绝了Apache的要求，使用自己的java.util.logging，这个包
的功能比log4j差的很远，性能也一般。 <br />
<br />
后来Apache就开发出来了commons-logging.jar用来兼容两个
logger。因此用commons-logging.jar写的log程序，底层的Logger是可以切换的，你可以选择log4j，
java.util.logging或者它自带的Simple
Logger。不过我仍然强烈建议使用log4j，因为log4j性能很高，log输出信息时间几乎等于System.out，而处理一条log平均只需
要5us。你可以在Hibernate的src目录下找到Hibernate已经为你准备好了的log4j的配置文件，你只需要到Apache
网站去下载log4j就可以了。commons-logging.jar也是必须的jar包。 <br />
<br />
使用Hibernate必须的jar包就是以上的这几个，剩下的都是可选的。 <br />
<br />
ant.jar: <br />
Ant编译工具的jar包，用来编译Hibernate源代码的。如果你不准备修改和编译Hibernate源代码，那么就没有什么用，可选的jar包 <br />
<br />
optional.jar： <br />
Ant的一个辅助包。 <br />
<br />
c3p0.jar： <br />
C3PO是一个数据库连接池，Hibernate可以配置为使用C3PO连接池。如果你准备用这个连接池，就需要这个jar包。 <br />
<br />
proxool.jar： <br />
也是一个连接池，同上。 <br />
<br />
commons-pool.jar, commons-dbcp.jar: <br />
DBCP数据库连接池，Apache的Jakarta组织开发的，Tomcat4的连接池也是DBCP。 <br />
<br />
实际上Hibernate自己也实现了一个非常非常简单的数据库连接池，加上上面3个，你实际上可以在Hibernate上选择4种不同的数据库连接
池，选择哪一个看个人的偏好，不过DBCP可能更通用一些。另外强调一点，如果在EJB中使用Hibernate，一定要用App
Server的连接池，不要用以上4种连接池，否则容器管理事务不起作用。 <br />
<br />
connector.jar: <br />
JCA 规范，如果你在App Server上把Hibernate配置为Connector的话，就需要这个jar。不过实际上一般App Server肯定会带上这个包，所以实际上是多余的包。 <br />
<br />
jaas.jar: <br />
JAAS是用来进行权限验证的，已经包含在JDK1.4里面了。所以实际上是多余的包。 <br />
<br />
jcs.jar： <br />
如果你准备在Hibernate中使用JCS的话，那么必须包括它，否则就不用。 <br />
<br />
jdbc2_0-stdext.jar: <br />
JDBC2.0的扩展包，一般来说数据库连接池会用上它。不过App Server都会带上，所以也是多余的。 <br />
<br />
jta.jar： <br />
JTA规范，当Hibernate使用JTA的时候需要，不过App Server都会带上，所以也是多余的。 <br />
<br />
junit.jar: <br />
Junit包，当你运行Hibernate自带的测试代码的时候需要，否则就不用。 <br />
<br />
xalan.jar, xerces.jar, xml-apis.jar: <br />
Xerces是XML解析器，Xalan是格式化器，xml-apis实际上是JAXP。一般App
Server都会带上，JDK1.4也包含了解析器，不过不是Xerces，是Crimson，效率比较差，不过Hibernate用XML只不过是读取
配置文件，性能没什么紧要的，所以也是多余的。<img src ="http://www.blogjava.net/mlh123caoer/aggbug/144351.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-09-11 19:55 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/09/11/144351.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JSP乱码解决思路总结</title><link>http://www.blogjava.net/mlh123caoer/archive/2007/09/10/144060.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Mon, 10 Sep 2007 09:58:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/09/10/144060.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/144060.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/09/10/144060.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/144060.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/144060.html</trackback:ping><description><![CDATA[<p><span style="font-size: 1em;">对于Java由于默认的编码方式是 UNICODE,所以用中文也易出问题,常见的解决是<br />
String s2 = new String(s1.getBytes("ISO-8859-1"),"GBK");<br />
前三种方法是我比较常用的方法，别人的经验告诉我：通常get方法通过改server.xml解决，<br />
post方法通过过滤器或者设置字符集解决，呵呵，不知道是否可行！<br />
<br />
1、utf8解决JSP中文乱码问题<br />
<br />
一般说来在每个页面的开始处，加入：<br />
<br />
＜%@ page language="java" contentType="text/html; charset=UTF-8"<br />
pageEncoding="UTF-8"%＞<br />
<br />
＜%<br />
request.setCharacterEncoding("UTF-8");<br />
%＞<br />
<br />
charset=UTF-8 的作用是指定JSP向客户端输出的编码方式为"UTF-8"<br />
<br />
pageEncoding="UTF-8" 为了让JSP引擎能正确地解码含有中文字符的JSP页面，这在LINUX中很有效<br />
<br />
request.setCharacterEncoding("UTF-8"); 是对请求进行了中文编码<br />
<br />
有时，这样仍不能解决问题，还需要这样处理一下：<br />
<br />
String msg = request.getParameter("message");<br />
String str=new String(msg.getBytes("ISO-8859-1"),"UTF-8");<br />
out.println(st);<br />
<br />
2、Tomcat 5.5 中文乱码(利用tomcat已经写好的字符集过滤器)<br />
<br />
1)只要把%TOMCAT安装目录%/ webapps\servlets-examples\WEB-INF\classes\filters\SetCharacterEncodingFilter.class 文件拷到你的webapp目录/filters下，如果没有filters目录，就创建一个。<br />
<br />
2)在你的web.xml里加入如下几行：<br />
＜filter＞<br />
＜filter-name＞Set Character Encoding＜/filter-name＞<br />
＜filter-class＞filters.SetCharacterEncodingFilter＜/filter-class＞<br />
＜init-param＞<br />
＜param-name＞encoding＜/param-name＞<br />
＜param-value＞GBK＜/param-value＞<br />
＜/init-param＞<br />
＜/filter＞<br />
＜filter-mapping＞<br />
＜filter-name＞Set Character Encoding＜/filter-name＞<br />
＜url-pattern＞/*＜/url-pattern＞<br />
＜/filter-mapping＞<br />
<br />
<br />
3、 get方式的解决办法（修改tomcat server.xml，但是不建议使用的说）<br />
<br />
1) 打开tomcat的server.xml文件，找到区块，加入如下一行：<br />
URIEncoding="GBK"<br />
完整的应如下：<br />
<br />
＜Connector<br />
port="80" maxThreads="150" minSpareThreads="25" maxSpareThreads="75"<br />
enableLookups="false" redirectPort="8443" acceptCount="100"<br />
debug="0" connectionTimeout="20000"<br />
disableUploadTimeout="true"<br />
URIEncoding="GBK"<br />
/＞<br />
<br />
4、xmlHttpRequest中文问题<br />
<br />
页面jsp用的GBK编码<br />
<br />
＜%@ page contentType="text/html; charset=GBK"%＞<br />
<br />
javascript部分<br />
function addFracasReport() {<br />
var url="controler?actionId=0_06_03_01&amp;actionFlag=0010";<br />
var urlmsg="&amp;reportId="+fracasReport1.textReportId.value; //故障报告表编号<br />
var xmlHttp=Common.createXMLHttpRequest();<br />
xmlHttp.onreadystatechange = Common.getReadyStateHandler(xmlHttp, eval("turnAnalyPage"));<br />
xmlHttp.open("POST",url,true);<br />
xmlHttp.setRequestHeader( " Content-Type " , " application/x-www-form-urlencoded);<br />
xmlHttp.send(urlmsg);<br />
}<br />
<br />
后台java中获得的reportId是乱码，不知道该怎么转，主要是不知道xmlHttp.send(urlmsg); 以后是什么编码？在后面用java来转，试了几种，都没有成功，其中有：<br />
<br />
public static String UTF_8ToGBK(String str) {<br />
try {<br />
return new String(str.getBytes("UTF-8"), "GBK");<br />
} catch (Exception ex) {<br />
return null;<br />
}<br />
}<br />
<br />
public static String UTF8ToGBK(String str) {<br />
try {<br />
return new String(str.getBytes("UTF-16BE"), "GBK");<br />
} catch (Exception ex) {<br />
return null;<br />
}<br />
}<br />
<br />
public static String GBK(String str) {<br />
try {<br />
return new String(str.getBytes("GBK"),"GBK");<br />
} catch (Exception ex) {<br />
return null;<br />
}<br />
}<br />
public static String getStr(String str) {<br />
try {<br />
String temp_p = str;<br />
String temp = new String(temp_p.getBytes("ISO8859_1"), "GBK");<br />
temp = sqlStrchop(temp);<br />
return temp;<br />
} catch (Exception e) {<br />
return null;<br />
}<br />
}<br />
<br />
<br />
<br />
5、Solaris下Servlet编程的中文问题及解决办法<br />
<br />
在使用Java开发Internet上的一个应用系统时，发现在Windows下调试完全正常的Servlet，上传到Solaris 服务器上，运行却出现故障--返回的网页不能显示中文，应为中文的信息全为乱码；用中文信息做关键字，不能正确检索数据库。后来采用加入检查代码等方法探知故障原因如下：<br />
<br />
显示乱码主要是因为通过类 HttpServletResponse提供的方法setContentType 无法改变返回给客户的数据的编码方式，正确的编码方式应为GB2312或者GBK，而事实上为缺省的ISO8859-1。无法检索中文信息则是因为，客户提交的中文信息经浏览器编码到达服务器后，Servlet无法将其正确解码。<br />
<br />
举例说明显示乱码解决方法<br />
<br />
Servlet 一般通常做法如下：<br />
<br />
public class ZldTestServlet extends HttpServlet {<br />
<br />
public void doGet (HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException{<br />
<br />
//在使用 Writer向浏览器返回数据前，设置 content-type header ，在这里设置相应的字符集gb2312<br />
<br />
response.setContentType("text/html; charset=gb2312");<br />
<br />
PrintWriter out = response.getWriter(); //*<br />
<br />
// 正式返回数据<br />
<br />
out.println("〈html〉〈head〉〈title〉Servlet test〈/title〉〈/head〉" );<br />
<br />
out.println("这是一个测试页！");<br />
<br />
out.println("〈/body〉〈/html〉");<br />
<br />
out.close();<br />
<br />
}<br />
<br />
...<br />
<br />
}<br />
<br />
解决页面显示乱码问题，需将*处代码换成如下内容：<br />
<br />
PrintWriter out = new PrintWriter(new OutputStreamWriter(response.getOutputStream(),"gb2312"));<br />
<br />
Solaris中文信息检索问题的解决<br />
浏览器利用表单向服务器提交信息时，一般采用x-www-form-urlencoded 的MIME格式对数据进行编码。如果使用get方法，参数名称和参数值经编码后附加在URL后，在Java中称作查询串（query string）。<br />
<br />
在Servlet程序中，如果采用ServletRequest的方法getParameter取得参数值，在Solaris环境下，对汉字却不能正确解码。因而无法正确检索数据库。<br />
<br />
在Java 1.2的包--java.net中提供了URLEncode和URLDecode类。类URLEncode提供了按x-www-form-urlencoded格式对给定串进行转换的方法。类URLEncode则提供了逆方法。<br />
<br />
6、Common Mail乱码问题<br />
<br />
common mail是一个小而方便的mail包，他实现了对Java Mail的封装，使用起来十分的方便，但是我在使用他的时候发现，使用纯文本的内容发送，结果是乱码，代码如下：<br />
<br />
public class TestCommonMail {<br />
public static void main(String[] args) throws EmailException, MessagingException {<br />
SimpleEmail email = new SimpleEmail();<br />
email.setCharset("GB2312");<br />
email.setHostName("smtp.163.com");<br />
email.setSubject("test");<br />
email.addTo("test@163.com");<br />
email.setFrom("test@163.com");<br />
email.setMsg("我的测试");<br />
email.setAuthentication("test", "test");<br />
email.send();<br />
}<br />
}<br />
<br />
分析了一下commons mail的源码找到了原因。源码如下:<br />
<br />
public class SimpleEmail extends Email<br />
{<br />
public Email setMsg(String msg) throws EmailException, MessagingException<br />
{<br />
if (EmailUtils.isEmpty(msg))<br />
{<br />
throw new EmailException("Invalid message supplied");<br />
}<br />
<br />
setContent(msg, TEXT_PLAIN);<br />
return this;<br />
}<br />
}<br />
<br />
Email代码片段<br />
<br />
public void setContent(Object aObject, String aContentType)<br />
{<br />
this.content = aObject;<br />
if (EmailUtils.isEmpty(aContentType))<br />
{<br />
this.contentType = null;<br />
}<br />
else<br />
{<br />
// set the content type<br />
this.contentType = aContentType;<br />
<br />
// set the charset if the input was properly formed<br />
String strMarker = "; charset=";<br />
int charsetPos = aContentType.toLowerCase().indexOf(strMarker);<br />
if (charsetPos != -1)<br />
{<br />
// find the next space (after the marker)<br />
charsetPos += strMarker.length();<br />
int intCharsetEnd =<br />
aContentType.toLowerCase().indexOf(" ", charsetPos);<br />
<br />
if (intCharsetEnd != -1)<br />
{<br />
this.charset =<br />
aContentType.substring(charsetPos, intCharsetEnd);<br />
}<br />
else<br />
{<br />
this.charset = aContentType.substring(charsetPos);<br />
}<br />
}<br />
}<br />
}<br />
<br />
email.send(); 的send方法将调用<br />
public void buildMimeMessage() throws EmailException<br />
{<br />
try<br />
{<br />
this.getMailSession();<br />
this.message = new MimeMessage(this.session);<br />
<br />
if (EmailUtils.isNotEmpty(this.subject))<br />
{<br />
if (EmailUtils.isNotEmpty(this.charset))<br />
{<br />
this.message.setSubject(this.subject, this.charset);<br />
}<br />
else<br />
{<br />
this.message.setSubject(this.subject);<br />
}<br />
}<br />
<br />
// ========================================================<br />
// Start of replacement code<br />
if (this.content != null)<br />
{<br />
this.message.setContent(this.content, this.contentType);<br />
}<br />
// end of replacement code<br />
// ========================================================<br />
else if (this.emailBody != null)<br />
{<br />
this.message.setContent(this.emailBody);<br />
}<br />
else<br />
{<br />
this.message.setContent("", Email.TEXT_PLAIN);<br />
}<br />
<br />
if (this.fromAddress != null)<br />
{<br />
this.message.setFrom(this.fromAddress);<br />
}<br />
else<br />
{<br />
throw new EmailException("Sender address required");<br />
}<br />
<br />
if (this.toList.size() + this.ccList.size() + this.bccList.size() == 0)<br />
{<br />
throw new EmailException(<br />
"At least one receiver address required");<br />
}<br />
<br />
if (this.toList.size() ＞ 0)<br />
{<br />
this.message.setRecipients(<br />
Message.RecipientType.TO,<br />
this.toInternetAddressArray(this.toList));<br />
}<br />
<br />
if (this.ccList.size() ＞ 0)<br />
{<br />
this.message.setRecipients(<br />
Message.RecipientType.CC,<br />
this.toInternetAddressArray(this.ccList));<br />
}<br />
<br />
if (this.bccList.size() ＞ 0)<br />
{<br />
this.message.setRecipients(<br />
Message.RecipientType.BCC,<br />
this.toInternetAddressArray(this.bccList));<br />
}<br />
<br />
if (this.replyList.size() ＞ 0)<br />
{<br />
this.message.setReplyTo(<br />
this.toInternetAddressArray(this.replyList));<br />
}<br />
<br />
if (this.headers.size() ＞ 0)<br />
{<br />
Iterator iterHeaderKeys = this.headers.keySet().iterator();<br />
while (iterHeaderKeys.hasNext())<br />
{<br />
String name = (String) iterHeaderKeys.next();<br />
String value = (String) headers.get(name);<br />
this.message.addHeader(name, value);<br />
}<br />
}<br />
<br />
if (this.message.getSentDate() == null)<br />
{<br />
this.message.setSentDate(getSentDate());<br />
}<br />
<br />
if (this.popBeforeSmtp)<br />
{<br />
Store store = session.getStore("pop3");<br />
store.connect(this.popHost, this.popUsername, this.popPassword);<br />
}<br />
}<br />
catch (MessagingException me)<br />
{<br />
throw new EmailException(me);<br />
}<br />
}<br />
由代码可以知道纯文本方式最终调用了Java Mail的<br />
message.setContent(this.content, this.contentType);<br />
content是内容<br />
contentType是类型，如text/plain,<br />
(我们可以试试直接用Java mail发邮件，设置文本内容不使用setText方法，也使用setContent("测试", "text/plain")方式，你可以看到内容也是乱码)<br />
<br />
关键就在于text/plain，我们改成text/plain; charset=gb2312，ok乱码解决了。在commons mail我们看SimpleEmail 类中setMsg方法调用的就是 setContent(msg, TEXT_PLAIN); 我们只需要将Email类中的常量TEXT_PLAIN修改一下加入 charset=你的字符集 ，重新打包jar，这样就可以了<br />
<br />
7、toad的字符集的设置与oracle的安装<br />
<br />
oracle数据库服务器的安装一般是中文字符集，有时安装在不同的平台下，设置为ISO编码，toad是oracle开发的最好工具，不是我说的，可是中文环境下安装的toad，打开英文字符的oracle时，中文全是乱码。必须进行设置<br />
<br />
环境变量---〉系统变量<br />
加<br />
NLS_lANG=SIMPLIFIED CHINESE_CHINA.ZHS16GBK<br />
或<br />
NLS_lANG=AMERICAN_AMERICA.WE8ISO8859P1<br />
<br />
AMERICAN_AMERICA.WE8MSWIN1252<br />
<br />
或者<br />
<br />
打开注册表，点击HKEY_LOCAL_MATHINE<br />
再点击Software,再点击ORACLE<br />
在点击HOME（ORACLE所在目录）<br />
在注册表的右半面有NLS_LANG,<br />
双击它，将你想要的覆盖掉原来的就可以了<br />
最好记下旧的，以便可以改回来。<br />
<br />
connect sys/chang_on_install<br />
update props$<br />
set value$='ZHS16CGB231280'<br />
where name='NLS_CHARACTERSET';<br />
commit;<br />
这样就OK了<br />
<br />
8、如何解決GWT(google web toolkit)中文的問題<br />
<br />
GWT 中文乱码解决方法<br />
<br />
1.把你要显示的中文"测试字符串"输入到一个文件，如:1.txt<br />
2.进入命令行,进入1.txt所在的目录,敲入以下命令:native2ascii.exe 1.txt 2.txt 回车。这样就生成了另外一个文件2.txt。<br />
3.2.txt的内容如下:\u6d4b\u8bd5\u5b57\u7b26\u4e32<br />
4.然后用上面的编码，在gwt中使用，就可以了.<br />
<br />
9、xmlHttp得到的网页怎么是乱码？<br />
<br />
(1)在服务器端使用WebRequest而不是xmlHttp<br />
(2) 将<br />
<br />
StreamReader sr = new StreamReader(stream);<br />
<br />
对于简体中文改成：<br />
<br />
StreamReader sr = new StreamReader(stream , Encoding.Default );<br />
<br />
对于utf-8改成：<br />
<br />
StreamReader sr = new StreamReader(stream , Encoding.UTF8 );<br />
<br />
当然，Encoding枚举还有很多其他的成员，对于不同的编码content-type可以有选择的应用<br />
<br />
(3)后来我发现无论是content-type是gb2312还是utf-8,用<br />
<br />
StreamReader sr = new StreamReader(stream , Encoding.Default );<br />
<br />
都可以返回正常的汉字，所以统一的改成Encoding.Default<br />
<br />
<br />
<br />
<br />
--------------------------------------------------------------------------------<br />
<br />
最后，在服务器端从一个url获得网页的源代码的代码如下：<br />
<br />
<br />
<br />
/// ＜summary＞<br />
/// post一个指定的url，获得网页的源代码(用WebRequest实现)<br />
/// ＜/summary＞<br />
/// ＜param name="url"＞＜/param＞<br />
/// ＜returns＞<br />
/// 如果请求失败，返回null<br />
/// 如果请求成功，返回网页的源代码<br />
/// ＜/returns＞<br />
public static string GetContentFromUrl2( string url )<br />
{<br />
//变量定义<br />
string respstr;<br />
<br />
WebRequest myWebRequest=WebRequest.Create(url);<br />
// myWebRequest.PreAuthenticate=true;<br />
// NetworkCredential networkCredential=new NetworkCredential( username , password , domain );<br />
// myWebRequest.Credentials=networkCredential;<br />
<br />
// Assign the response object of 'WebRequest' to a 'WebResponse' variable.<br />
WebResponse myWebResponse=myWebRequest.GetResponse();<br />
System.IO.Stream stream = myWebResponse.GetResponseStream();<br />
StreamReader sr = new StreamReader(stream , Encoding.Default );<br />
//以字符串形式读取数据流<br />
respstr = sr.ReadToEnd();<br />
sr.Close();<br />
<br />
return respstr;<br />
<br />
}</span></p><img src ="http://www.blogjava.net/mlh123caoer/aggbug/144060.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-09-10 17:58 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/09/10/144060.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>常用开源GIS工程</title><link>http://www.blogjava.net/mlh123caoer/archive/2007/09/05/142840.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Wed, 05 Sep 2007 03:00:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/09/05/142840.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/142840.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/09/05/142840.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/142840.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/142840.html</trackback:ping><description><![CDATA[<p>常用的开放的GIS工程信息:<br/>1、MapServer : <a href="http://mapserver.gis.umn.edu">http://mapserver.gis.umn.edu</a><br/>MapServer是一个开放的用于建设空间数据发布以及制图网络应用程序的开发环境,MapServer<br/>不是一个功能齐全的GIS系统平台, MapServer 主要提供在网络上发布和渲染空间数据(maps, images,<br/>和vector data) 的能力.其支持PHP, Python, Perl, Ruby, Java, and C#等多种语言进行二次开发,<br/>支持跨平台,支持Linux, Windows, Mac OS X, Solaris,等更多操作系统环境.<br/>MapServer 网站德语版本: <a href="http://www.umn-mapserver.de/">http://www.umn-mapserver.de/</a> (German)<br/>2、GRASS GIS:http://grass.itc.it<br/>GRASS是一套开源的地理信息系统,用来管理和分析地理空间数据,包括强大的影像处理,制图打印,<br/>空间模型建立,可视化等功能,目前已经用在很多商业地理信息系统领域,也被很多政府部门和环境研究<br/>机构使用,最新版本可以到<a href="http://grass.itc.it/download/index.php">http://grass.itc.it/download/index.php</a>下载.</p>
<p>3、PostGIS:http://postgis.refractions.net/<br/>PostGIS为关系型数据库PostgreSQL增加了空间数据的支持能力,其模式和ESRI'的SDE(空间数据库<br/>引擎) 以及Oracle的Spatial 扩展很类似.PostGIS 是Refractions Research开发的一个开放的空间<br/>数据库技术工程.<br/>4、常用的开放的GIS工具和库:<br/>(1) AVCE00 和 E00Compr 库:http://avce00.maptools.org/<br/>AVCE00- C library 可以转换Arc/Info (binary) vector coverages 为 ASCII E00 文件!<br/>(2) E00Compr- C library 可以读写压缩的 E00 文件.<br/>(3) GDAL - Geospatial Data Abstraction Library: <a href="http://www.gdal.org/">http://www.gdal.org/</a><br/>GDAL 是一个Raster地理空间数据格式的数据转换函数库,详细的信息大家可以到官网上察看:<br/><a href="http://www.gdal.org">http://www.gdal.org</a><br/>资源下载地址: ftp at remotesensing.org, http at download.osgeo.org<br/>(4) Shapefile C Library V1.2: <a href="http://shapelib.maptools.org/">http://shapelib.maptools.org/</a><br/>Shapefile C Library 提供编写简单的C程序具有读,写,更新(限制的区域内) ESRI Shapefiles,<br/>并可以管理属性文件(.dbf)的能力.MITAB:http://mitab.maptools.org/<br/>(5) MITAB 是一个开放的用来读写MapInfo .TAB (binary) 和 .MIF/MID 文件的C++ library.<br/>它是基于OGR library 来编写的.</p><img src ="http://www.blogjava.net/mlh123caoer/aggbug/142840.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-09-05 11:00 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/09/05/142840.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>acegi参考手册翻译</title><link>http://www.blogjava.net/mlh123caoer/archive/2007/09/04/142743.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Tue, 04 Sep 2007 13:13:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/09/04/142743.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/142743.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/09/04/142743.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/142743.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/142743.html</trackback:ping><description><![CDATA[序言 <br />
Acegi Security为基于J2EE的企业应用软件提供全面的安全解决方案。正如你在本手册中看到的那样，我们尝试为您提供有用的，高可配置的安全系统。 <br />
安 全是一个永无止境的目标，获取一个全面的，系统级的实现方式是至关重要的。在安全界，我们鼓励你采用&#8220;分层安全&#8221;，这样每个层都确保自身尽可能的安全，另 外的层提供另外的安全。每个层自身越&#8220;紧密&#8221;，你的系统就越鲁棒和安全。在底层，你要处理传输入安全和系统认证，减少&#8220;中间人攻击&#8221;（man-in- the-middle attacks）。接下来你要使用防火墙，结合VPN或者IP安全来确保只有认证过的系统能够尝试连接。在企业环境中，你可能部署DMZ （demilitarized zone，隔离区）来把面向公众的服务器和后端的数据和应用服务器分隔开。在以非授权用户运行进程和文件系统安全最大化上，你的操作系统也将扮演一个关键 的角色。接下来你要防止针对系统的拒绝服务和暴力攻击。入侵检测系统在检测和应对攻击方面尤其有用，这些系统可以实时屏蔽恶意TCP/IP地址。在更高层 上，你的Java虚拟机需要进行配置，将授予不同Java类型的权限最小化，然后，你的应用程序要对添加针对自身特定问题域的安全配置。Acegi Security使后者－应用程序安全变得容易。 <br />
当然，你要正确对待上述提到的每个安全层，以及包含于每个层的管理因素。这样的管理因素具体包括：安全公告监测，补丁，人工诊断，审计，变更管理，工程管理系统，数据备份，灾难恢复，性能评测，负载监测，集中日志，应急反应程序等等。 <br />
Acegi Security专注于在企业应用安全层为您提供帮助，你将会发现和各式各样的需求和商业问题领域一样多。银行系统的需求和电子商务应用的需求不同。电子 商务应用和售卖军用自动工具的公司的需求不同。这些客户化的需求使得应用安全显得有趣，富有挑战性而且物有所值。 <br />
本手册为Acegi Security 1.0.0的发布而大规模重新组织。请先阅读Part I 架构概览。手册的其余部分按照传统的手册方式编排，需要一定的基础才能阅读。 <br />
我们希望您会觉得手册有用，并且欢迎您提供反馈意见和建议。 <br />
最后，欢迎加入Acegi Security社区。 <br />
acegi参考手册(v1.0.4)[译]－第一章 简介 <br />
Part I. 架构概览 <br />
象其他的软件一样，Acegi Security也有在整个框架中都会使用的特定核心接口，类，和概念抽象。在手册的这一部分，在检视这些规划和执行Acegi Security集成所必须的核心要素之前，我们先介绍Acegi Security。 <br />
<br />
第一章. 简介 <br />
1.1. Acegi Security是什么? <br />
Acegi Security为基于J2EE的企业软件应用提供全面的安全服务。特别是使用领先的J2EE解决方案－Srping框架开发的项目。如果您不是使用 Spring开发企业应用，我们温馨提醒您仔细研究一下。熟悉Spring，尤其是依赖注射原理，会极大的帮助你快速掌握Acegi Security。 <br />
人们使用Acegi Security有很多种原因，不过通常吸引他们到这个项目的原因是他们在J2EE的 Servlet Specification 或者 EJB Specification中找不到迫切需要的典型企业应用场景。提到这些规范，特别要提出的是他们不是在WAR或者EAR级别可移植的。这样，如果你切 换服务器环境，一般来说你要在目标环境中花费很多工夫来重新配置你的应用安全。使用Acegi Security解决了这些问题，并且为你提供了很多其他有用的，完全可定制的安全特性。 <br />
如你所知，安全包含两个主要操作。第一个被称为&#8220;认 证&#8221;，是为用户建立一个它所声明的principal。Principal通常代表用户，设备，或者其他能在你的应用中执行操作的其他系统。&#8220;授权&#8221;指判 定一个principal能否在你的系统中执行某个操作。在到达授权判断之前，principal的的身份认证已经由认证过程执行过了。这些概念是通用 的，不是Acegi Security特有的。 <br />
在认证层面，Acegi Security广泛支持各种认证模块。这些认证模块绝大多数是第三方提供，或者相关的标准组织开发的，例如Internet Engineering Task Force。作为补充，Acegi Security自己也提供了一些认证功能。Acegi Security当前支持如下的认证技术。 <br />
&amp;S226; HTTP BASIC authentication headers (an IEFT RFC-based standard) <br />
&amp;S226; HTTP Digest authentication headers (an IEFT RFC-based standard) <br />
&amp;S226; HTTP X.509 client certificate exchange (an IEFT RFC-based standard) <br />
&amp;S226; LDAP (a very common approach to cross-platform authentication needs, especially in large environments) <br />
&amp;S226; Form-based authentication (for simple user interface needs) <br />
&amp;S226; Computer Associates Siteminder <br />
&amp;S226; JA-SIG Central Authentication Service (otherwise known as CAS, which is a popular open source single sign on system) <br />
&amp;S226; Transparent authentication context propagation for Remote Method Invocation (RMI) and HttpInvoker (a Spring remoting protocol) <br />
&amp;S226; Automatic "remember-me" authentication (so you can tick a box to avoid re-authentication for a predetermined period of time) <br />
&amp;S226; Anonymous authentication (allowing every call to automatically assume a particular security identity) <br />
&amp;S226; Run-as authentication (which is useful if one call should proceed with a different security identity) <br />
&amp;S226; Java Authentication and Authorization Service (JAAS) <br />
&amp;S226; Container integration with JBoss, Jetty, Resin and Tomcat (so you can still use Container Manager Authentication if desired) <br />
&amp;S226; 你自己的认证系统 (如下所示) <br />
很 多独立软件供应商(ISVs)选择Acegi Security是因为它具有丰富的认证模块。这样无论他们的终端客户需要什么，他们都可以快速集成到他们的系统中，不用花很多工夫或者让终端客户改变环 境。如果Acegi Security System for Spring的7个认证模块还没有满足你的需求的话，Acegi Security是一个开放的系统，很容易写你自己的认证机制。许多Acegi Security的企业用户需要和&#8220;遗留&#8221;系统集成，这些遗留系统不遵循任何安全标准，Acegi Security能够和这样的系统&#8220;合作愉快&#8221;。 <br />
有 时候基本的认证是不够的。有时候你需要根据principal和应用交互的方式来应用不同的安全措施。例如，你可能为了防止密码被窃取，或者防止终端用户 受到&#8220;中间人&#8221;攻击，需要保证到达的是请求通过HTTPS的。或者，你要确保是一个真正的人而不是某种机器人或者自动进程在发送请求。这对于保护密码恢复 不受暴力破解攻击，或者防止他人很容易的复制你应用的关键内容。为了帮助你实现这些目标，Acegi Security完全支持自动&#8220;通道安全&#8221;("channel security")，以及集成Jcaptcha来检测是否是真正人类用户。 <br />
Acegi Security不仅提供了认证功能，而且提供了完备的授权功能。在授权方面主要有三个领域，授权web请求，授权方法调用，授权存取单个领域对象实例。 为了帮助你理解这些区别，对照考虑一下Servlet 规范中的web模式安全的授权功能，EJB容器管理安全以及文件系统安全。Acegi Security提供了所有这些重要领域的完备功能，我们将在本手册的后面介绍。 <br />
1.2. 历史 <br />
Acegi Security始于2003年晚期，当时在Spring Developers邮件列表中有人提问是否有人考虑提供一个基于Spring的安全实现。当时，Srping的社区是相对比较小的（尤其是和今天相 比！），实际上Spring本身也是2003年早期才作为一个SourceForge项目出现的。对此问题的回应是它确实是一个值得研究的领域，虽然限于 时间无法进行深入。 <br />
有鉴于此，这个简单的安全实现虽然构建了但是并没有发布。几周以后，Spring社区的其他成员询问了安全框架，代码就被提供给了他们。 <br />
随后又有人请求，到了2004年一月，大约有20人左右在使用这些代码。另外一些人加入到这些先行的用户中来，并建议建立一个SourceForge项目，这个项目在2004年3月建立起来。 <br />
在 早期，该项目自身并布具备任何认证模块。认证过程依赖容器管理安全（Container Managed Security）而Acegi Security注重授权。在一开始这样是合适的，但是随着越来越多的用户要求额外的容器支持，基于容器的认证的限制就显示出来了。另外一个相关的问题是 添加新的JAR文件到容器的classpath，通常会让最终用户感到困惑并且配置错误。 <br />
随后，Acegi Security加入了认证服务。大约一年后，Acegi Security成为了一个Spring Framework官方子项目。在2年半多的在多个软件项目中的活跃使用以及数以百计的改进和社区贡献，1.0.0最终版在2006年5月发布。 <br />
今天，Acegi Security成为一个强大而活跃的社区。在支持论坛上有数以千计的帖子。14位开发人员专职开发，一个活跃的社区也定期共享补丁并支持他们的同侪。 <br />
<br />
1.3. 发行版本号 <br />
理 解Acegi Security的版本号是非常好处的，它可以帮助你判定升级的到新的版本是否需要花费很大精力。我们的正式发行版本使用Apache Portable Runtime Project版本指引，可以在下述网站查看http://apr.apache.org/versioning.html。为了您查看方便，我们引用该 页的说明部分如下： <br />
&#8220;版本号由三个部分的整数组成：主版本号（MAJOR）、副版本号（MINOR）、补丁版本号（PATCH）。主要的含义 是主版本号（MAJOR）是不兼容的，API大规模升级。副版本号（MINOR）在源文件和可执行版和老版本保持兼容，补丁版本号（PATCH）则意味着 向前和向后的完全兼容&#8221;。 <br />
acegi参考手册(v1.0.4)[译]-第二章 技术概览[上] <br />
<br />
第二章. 技术概览 <br />
2.1. 运行时环境 <br />
Acegi Security可以在JRE1.3中运行。这个发行版本中支持也Java 5.0，尽管对应的Java类型被分开打包到一个后缀是&#8220;tiger&#8221;的包中。因为Acegi Security致力于以一种自包含的方式运行，因此不需要在JRE中放置任何特殊的配置文件。特别无需配置Java Authentication and Authorization Service (JAAS)策略文件或者将Acegi Security放置到通用的classpath路径中。 <br />
<br />
同样的，如果你使用EJB容器或者Servlet容器，同样无需放置任何特别的配置文件或者将Acegi Security包含在服务器的类加载器（classloader）中。 <br />
<br />
上述的设计提供了最大的部署灵活性，你可以直接把目标工件（JAR, WAR 或者 EAR)）直接从一个系统copy到另一个系统，它马上就可以运行起来。 <br />
<br />
2.2. 共享组件 <br />
让我们来看看Acegi Security中最重要的一些共享组件。所谓共享组件是指在框架中处于核心地位，系统脱离了它们之后就不能运行。这些Java类型代表了系统中其他部分的构建单元，因此理解它们是非常重要的，即使你不需要直接和它们打交道。 <br />
<br />
最 基础的对象是SecurityContextHolder。在这里存储了当前应用的安全上下文（security context），包括正在使用应用程序的principal的详细信息。SecurityContextHolder默认使用ThreadLocal来 存储这些详细信息，这意味着即便安全上下文（security context）没有被作为一个参数显式传入，它仍然是可用的。如果在当前principal的请求处理后清理线程,那么用这种方式使用 ThreadLocal是非常安全的。当然， Acegi Security自动为你处理这些，所以你无需担心。 <br />
<br />
有些应用程序由于使 用线程的方式而并不是完全适用ThreadLocal。例如，Swing客户端可能需要一个Java Virtual Machine中的所有线程都使用同样的安全上下文（security context）。在这种情况下你要使用SecurityContextHolder.MODE_GLOBAL模式。另外一些应用程序可能需要安全线程产 生的线程拥有同样的安全标识符（security identity）。这可以通过SecurityContextHolder.MODE_INHERITABLETHREADLOCAL来实现。你可以通 过两种方法来修改默认的SecurityContextHolder.MODE_THREADLOCAL。第一种是设置一个系统属性。或者，调用 SecurityContextHolder的一个静态方法。大部分的应用程序不需要修改默认值，不过如果你需要，那么请查看 SecurityContextHolder的JavaDocs获取更多信息。 <br />
<br />
我们在SecurityContextHolder中 存储当前和应用程序交互的principal的详细信息。Acegi Security使用一个Authentication对象来代表这个信息。尽管你通常不需要自行创建一个Authentication对象，用户还是经 常会查询Authentication对象。 <br />
<br />
你可以在你的应用程序中的任何地方使用下述的代码块： <br />
java 代码 <br />
<br />
1. Object obj = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); <br />
2. if (obj instanceof UserDetails) { <br />
3. String username = ((UserDetails)obj).getUsername(); <br />
4. } else { <br />
5. String username = obj.toString(); <br />
6. } <br />
<br />
上 述的代码展示了一些有趣的联系和关键的对象。首先，你会注意到在SecurityContextHolder和Authentication之间有一个媒 介对象。SecurityContextHolder.getContext() 方法实际上返回一个SecurityContext。Acegi Security使用若干个不同的SecurityContext实现，以备我们需要存储一些和principal无关的特殊信息。一个很好的例子就是我 们的Jcaptcha集成，它需要知道一个需求是否是由人发起的。这样的判断和principal是否通过认证完全没有关系，因此我们将它保存在 SecurityContext中。 <br />
<br />
从上述的代码片段可以看出的另一个问题是你可以从一个Authentication对象中获取一 个principal。Principal只是一个对象。通常可以把它cast为一个UserDetails对象。UserDetails在Acegi Security中是一个核心接口，它以一种扩展以及应用相关的方式来展现一个principal。可以把UserDetails看作是你的用户数据库和 Acegi Security在SecurityContextHolder所需要的东西之间的一个适配器（adapter）。作为你自己用户数据库的一个展现，你可 能经常要把它cast到你应用程序提供的原始对象，这样你就可以调用业务相关的方法(例如 getEmail(), getEmployeeNumber())。 <br />
<br />
现在你可能已经开始疑惑，那我什么时候提供UserDetails对象呢？我要如何提供呢？ <br />
我 想你告诉过我这个东西是声明式的，我不需要写任何Java代码－那怎么做到呢？对此的简短回答就是有一个叫做UserDetailsService的特殊 接口。这个接口只有一个方法，接受一个Sring类型的参数并返回一个UserDetails。Acegi Security提供的大多数认证提供器将部分认证过程委派给UserDetailsService。UserDetailsService用来构建保存 在SecurityContextHolder中的Authentication对象。好消息是我们提供若干个UserDetailsService的实 现，包括一个使用in-memory map和另一个使用JDBC的。 <br />
大多数用户还是倾向于写自己的实现，这样的实现经常就是简单的构建于已 有的Data Access Object (DAO)上，这些DAO展现了他们的雇员、客户、或者其他企业应用程序中的用户。要记得这样做的好处，不论你的UserDetailsService返 回什么，它总是可以从SecurityContextHolder中获取，象上面的代码显示的那样。 <br />
<br />
除了principal， Authentication提供的另一个重要方法就是getAuthorities（）。这个方法返回一个GrantedAuthority对象数组。 GrantedAuthority，毫无疑问，就是授予principal的权限。这些权限通常是&#8220;角色&#8221;，例如ROLE_ADMINISTRATOR 或者ROLE_HR_SUPERVISOR。这些角色稍后配置到web授权，方法授权和领域对象授权。Acegi Security的其他部分能够处理这些权限，并且期待他们被提供。通常你会从UserDetailsService中返回 GrantedAuthority对象。 <br />
<br />
通常GrantedAuthority对象都是应用范围的权限。它们都不对应特定的领域对 象。因此，你应该不会有一个代表54号员工对象的GrantedAuthority，因为这样会有数以千计的authority，你马上就会用光所有内存 （或者，至少会让系统花太长时间来认证一个用户）。当然，Acegi Security会高效的处理这种普遍的需求，但是你不会使用领域对象安全功能来实现这个目的。 <br />
<br />
最后，但不是不重要，你有时候需要在 HTTP 请求之间存储SecurityContext。另外有些时候你在每次请求的时候都会重新认证principal，不过大部分时候你会存储 SecurityContext。HttpSessionContextIntegrationFilter在HTTP之间存储 SecurityContext。正如类名字显示的那样，它使用HttpSession来进行存储。基于安全原因，你永远都不要直接和 HttpSession交互。没有理由这么做，所以记得使用SecurityContextHolder来代替。 <br />
<br />
让我们回忆一下，Acegi Security的基本组成构件是： <br />
&amp;S226; SecurityContextHolder,提供对SecurityContext的所有访问方式。 <br />
&amp;S226; SecurityContext, 存储Authentication以及可能的请求相关的安全信息。 <br />
&amp;S226; HttpSessionContextIntegrationFilter, 在web请求之间把SecurityContext存储在HttpSession中。 <br />
&amp;S226; Authentication, 以Acegi Security的方式表现principal。 <br />
&amp;S226; GrantedAuthority, 表示赋予一个principal的应用范围的权限。 <br />
&amp;S226; UserDetails, 为从你的应用程序DAO中获取必要的信息来构建一个Authentication 对象。 <br />
&amp;S226; UserDetailsService,用传入的String类型的username（或者认证ID，或类似）来创建一个UserDetails。 <br />
<br />
现在你已经理解了这些重复使用的组件，让我们仔细看看认证过程吧。 <br />
<br />
2.3. 认证 <br />
正 如我们在手册开始部分所说的那样，Acegi Security适用于很多认证环境。虽然我们建议大家使用Acegi Security自身的认证功能而不是和容器管理认证（Container Managed Authentication）集成，但是我们仍然支持这种和你私有的认证系统集成的认证。让我们先从Acegi Security完全自行管理管理web安全的角度来探究一下认证，这也是最复杂和最通用的情形。 <br />
<br />
想象一个典型的web应用的认证过程： <br />
<br />
1．你访问首页，点击一个链接。 <br />
2．一个请求被发送到服务器，服务器判断你是否请求一个被保护的资源。 <br />
3．因为你当前未被认证，服务器发回一个回应，表明你必须通过认证。这个回应可能是一个HTTP回应代码，或者重定向到一个特定的网页。 <br />
4．基于不同的认证机制，你的浏览器会重定向到一个网页好让你填写表单，或者浏览器会用某种方式获取你的身份认证（例如一个BASIC认证对话框，一个cookie，一个X509证书等等。）。 <br />
5．浏览器会发回给服务器一个回应。可能是一个包含了你填写的表单内容的HTTP POST，或者一个包含你认证详细信息的HTTP header。 <br />
6．接下来服务器会判断提供的认证信息是否有效。如果它们有效，你进入到下一步。如果它们无效，那么通常请求你的浏览器重试一次（你会回到上两步）。 <br />
7．你引发认证的那个请求会被重试。但愿你认证后有足够的权限访问那些被保护的资源。如果你有足够的访问权限，请求就会成功。否则，你将会受到一个意味&#8220;禁止&#8221;的HTTP403错误代码。 <br />
<br />
在Acegi Security中，对应上述的步骤，有对应的类。主要的参与者（按照被使用的顺序）是：ExceptionTranslationFilter， AuthenticationEntryPoint， 认证机制(authentication mechanism)， 以及AuthenticationProvider。 <br />
<br />
ExceptionTranslationFilter是Acegi Security用来检测任何抛出的安全异常的过滤器(filter)。这种异常通常是由AbstractSecurityInterceptor抛出 的，它是授权服务的主要提供者。我们将会在下一部分讨论AbstractSecurityInterceptor，现在我们只需要知道它产生Java异 常，并且对于HTTP或者如何认证一个principal一无所知。反而是ExceptionTranslationFilter提供这样的服务，它负责 要么返回403错误代码(如果principal通过了认证，只是缺少足够的权限，象上述第7步那样)，要么加载一个 AuthenticationEntryPoint (如果principal还没有被认证，那么我们要从第3步开始)。 <br />
<br />
AuthenticationEntryPoint 负责上述的第3步。如你所想，每个web应用都有一个默认的认证策略（象Acegi Security中几乎所有的东西一样，它也是可配置的，不过我们现在还是还是从简单开始）。每个主流的认证系统都有它自己的 AuthenticationEntryPoint实现，负责执行第3步中描述的动作。 <br />
<br />
当浏览器确定要发送你的认证信息（HTTP 表单或者HTTP header），服务器上需要有什么东西来&#8220;收集&#8221;这些认证信息。现在我们在上述的第6步。在Acegi Security中对从用户代理（通常是浏览器）收集认证信息有一个特定的名字，这个名字是&#8220;认证机制（authentication mechanism）&#8221;。当认证信息从客户代理收集过来以后，一个&#8220;认证请求（Authentication request）&#8221;对象被创建，并发送到AuthenticationProvider。 <br />
<br />
Acegi Security中认证的最后一环是一个AuthenticationProvider。非常简单，它的职责是取用一个认证请求 （Authentication request）对象，并且判断它是否有效。这个provider要么抛出一个异常，要么返回一个组装完毕的Authentication对象。还记得我 们的好朋友UserDetails 和 UserDetailsService吧？如果没有，回到前一部分重新回忆一下。大部分的AuthenticationProviders都会要求 UserDetailsService提供一个UserDetails对象。如前所述，大部分的应用程序会提供自己的 UserDetailsService，尽管有些会使用Acegi Security提供的JDBC或者 in-memory实现。作为成品的UserDetails 对象，特别是其中的GrantedAuthority[]s，在构建完备的Authentication对象时会被使用。 <br />
<br />
当认证机制 （authentication mechanism）取回组装完全的Authentication对象后，它将会相信请求是有效的，将Authentication放到 SecurityContextHolder中，并且将原始请求取回（上述第7步）。反之，AuthenticationProvider则拒绝请求，认 证机制（authentication mechanism）会请求用户重试（上述第2步）。 <br />
<br />
在讲述典型的认证流程的同时，有个好消 息是Acegi Security不关心你是如何把Authentication放到SecurityContextHolder内的。唯一关键的是在 AbstractSecurityInterceptor授权一个请求之前，在SecurityContextHolder中包含一个代表了 principal的Authentication。 <br />
<br />
你可以（很多用户确实）实现自己的过滤器（filter）或者MVC控制器 （controller）来提供和不是基于Acegi Security的认证系统交互。例如，你可能使用使用容器管理认证（Container Managed Authentication），从ThreadLocal 或者JNDI中获取当前用户信息，使得它有效。或者，你工作的公司有一个遗留的私有认证系统，而它是公司&#8220;标准&#8221;，你对它无能为力。在这种情况之下也是非 常容易让Acegi Security运作起来，提供认证能力。你所需要做的是写一个过滤器（或等价物）从某处读取第三方用户信息，构建一个Acegi Security式的Authentication对象，把它放到SecurityContextHolder中。这非常容易做，也是一种广泛支持的集成 方式。 <br />
acegi参考手册(v1.0.4)[译]-第二章 技术概览[下] <br />
2.4. 安全对象 <br />
如果你熟悉AOP，你会知 道有很多种advice可用：before, after, throws 和 around。around advice非常有用，因为它能够选择是否选择是否执行一个方法调用，是否修改返回值，以及是否抛出异常。Acegi Security对方法调用和web请求都提供around advice。我们使用AOP联盟实现对方法调用的around advice，对于web请求的around advice则是使用标准的过滤器（Filter）。 <br />
<br />
对于那些不熟悉AOP的人来说， 关键是要理解Acegi Security能够帮助你保护方法调用以及web请求。大多数人对保护他们服务层的方法调用感兴趣。这是因为在当前的J2EE应用中，服务层包含了大多 数的业务逻辑（声明，作者不赞成这种设计，反而支持正确封装的领域模型以及DTO，assembly, facade 以及 transparent persistence patterns，而不是当前主流的贫血模型，我们将在这里讨论）。如果你需要保护service层的方法调用，使用标准的Spring AOP平台（或者被成为AOP 联盟（AOP Alliance））就足够了。如果你需要直接对领域模型进行保护，那么可以考虑使用AspectJ。 <br />
<br />
你 可以选择对使用AspectJ 或者AOP联盟（AOP Alliance）对方法进行授权，或者你可以选择使用过滤器（filter）来对web请求进行授权。你将0个，1个，2个或者3个这些方法一起使用。 主流的用法是执行一些web请求授权，以及在服务层使用AOP联盟（AOP Alliance）对一些方法调用授权。 <br />
<br />
Acegi Security使用&#8220;安全对象&#8221;（secure object）这个词来指任何能够将安全应用于其上的对象。每个Acegi Security支持的安全对象都有自己的类，它是AbstractSecurityInterceptor的子类。重要的一点是，如果一个 principal通过认证，当AbstractSecurityInterceptor执行的时候，SecurityContextHolder中要包 含一个有效的Authentication。 <br />
<br />
AbstractSecurityInterceptor提供一个固定的工作流程来处理 安全对象请求。这个工作流程包括查找和当前请求相关联的&#8220;配置属性（configuration attributes）&#8221;。配置属性（configuration attributes）可以被认为是对被AbstractSecurityInterceptor使用的类有特殊含义的字符串。他们通常针对 AbstractSecurityInterceptor使用XML进行配置。反正，AbstractSecurityInterceptor会询问 AccessDecisionManager &#8220;这是配置属性（configuration attributes），这是当前的认证对象（Authentication object），这是当前请求的详细信息－那么这个特定的principal可以执行这个特定的操作吗？&#8221;。 <br />
<br />
假如 AccessDecisionManager判定允许这个请求，那么AbstractSecurityInterceptor一般来说就继续执行请求。虽 然这样，用户在少数情况之下可能需要替换SecurityContext中的Authentication，可以通过 AccessDecisionManager调用一个RunAsManager来实现。在某些不常见的情形下这将非常有用，例如服务层的方法需要用另一种 标识（身份）来调用远程系统。这可能有所帮助，因为Acegi Security自动在不同的服务器之间传播安全标识（假设你正确配置了RMI或者HttpInvoker remoting protocol client）。 <br />
<br />
随着安全对象处理和返回－意味着方法调用完毕或者过滤器链（filter chain）处理完毕－AbstractSecurityInterceptor有最后的机会来处理调用。这时， AbstractSecurityInterceptor可能会修改返回的对象。我们可能要这样做，因为授权判断不能在安全对象调用途中执行。由于高度的 可插拔性，如果需要AfterInvocationManager将控制权交给AfterInvocationManager来实际修改对象。这个类甚至 可以彻底替换对象，或者抛出异常，或者根本不修改它。 <br />
<br />
因为是AbstractSecurityInterceptor中心模版类，看起来第一副插图该献给它。（译注：原手册里的图画的太丑陋了，我用jude重新画了一遍） <br />
&lt;!--[if gte vml 1]&gt;&lt;v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"&gt; &lt;v:stroke joinstyle="miter" /&gt; &lt;v:formulas&gt; &lt;v:f eqn="if lineDrawn pixelLineWidth 0" /&gt; &lt;v:f eqn="sum @0 1 0" /&gt; &lt;v:f eqn="sum 0 0 @1" /&gt; &lt;v:f eqn="prod @2 1 2" /&gt; &lt;v:f eqn="prod @3 21600 pixelWidth" /&gt; &lt;v:f eqn="prod @3 21600 pixelHeight" /&gt; &lt;v:f eqn="sum @0 0 1" /&gt; &lt;v:f eqn="prod @6 1 2" /&gt; &lt;v:f eqn="prod @7 21600 pixelWidth" /&gt; &lt;v:f eqn="sum @8 21600 0" /&gt; &lt;v:f eqn="prod @7 21600 pixelHeight" /&gt; &lt;v:f eqn="sum @10 21600 0" /&gt; &lt;/v:formulas&gt; &lt;v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect" /&gt; &lt;o:lock v:ext="edit" aspectratio="t" /&gt; &lt;/v:shapetype&gt;&lt;v:shape id="_x0000_i1025" type="#_x0000_t75" style='width:423pt; height:270.75pt'&gt; &lt;v:imagedata src="file:///C:\WINDOWS\TEMP\msohtml1\01\clip_image001.jpg" o:title="ch2-1" /&gt; &lt;/v:shape&gt;&lt;![endif]--&gt;&lt;!--[if !vml]--&gt;&lt;!--[endif]--&gt; <br />
<br />
图1 关键&#8220;安全对象&#8221;模型 <br />
<br />
只有那些希望实现全 新的对请求进行截取截取和授权方式的开发者才需要直接使用安全对象。例如，可能构建一个新的安全对象安全调用一个消息系统。任何需要安全并且能够提供一种 截取调用的方式(例如AOP around advice semantics)的东西都可以成为安全对象。虽然如此，大部分的Spring应用都会只是透明应用当前支持的三种安全对象类型（AOP Alliance MethodInvocation, AspectJ JoinPoint 和 web request FilterInterceptor）。 <br />
<br />
2.5. 结论 <br />
恭喜！你已经获取了Acegi Security足够的概括性的图景来开始着手你的项目。我们探究了共享组件，认证过程，以及对&#8220;安全对象&#8221;的通用授权概念。手册中的余下部分你可能用到也可能用不到，可以按照任意顺序阅读。 <br />
acegi参考手册(v1.0.4)[译]-第三章 协助系统 <br />
第三章. 协助系统 <br />
本章介绍一些Acegi Security使用的附加和协助系统。那些和安全无关，但是包含在Acegi Security项目中的部分，将会在本章中讨论 <br />
3.1. 本地化 <br />
Acegi Security支持对终端客户可能会看到的异常信息进行本地化。如果你的应用是为英文用户设计的，那么你什么都不用做，因为Acegi Security的所有消息默认都是英文的。如果你要支持其他区域用户，那么本节包含了你所需要了解的所有东西。 <br />
包括认证失败或者访问被拒绝（授权失败）的所有异常消息都可以被本地化。提供给开发者或者系统部署人员的异常或者日志信息(包括错误的属性、接口不符、构造器错误、debug级日志)没有被本地化，它们硬编码在Acegi Security的代码中。 <br />
在acegi -security-xx.jar（译注：xx代表版本号）的org.acegisecurity包中包含了一个 messages.properties文件。这个文件会被你的application context引用，因为Acegi Security实现了Spring的MessageSourceAware接口，它期待在application context启动的时候注入一个message resolver。通常你所需要做的是在你的application context中注册一个引用这个消息的bean，如下所示： <br />
xml 代码 <br />
<br />
1. &lt;bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"&gt; <br />
2. &lt;property name="basename"&gt;&lt;value&gt;org/acegisecurity/messages&lt;!--&lt;/span--&gt;value&gt;&lt;!--&lt;/span--&gt;property&gt; <br />
3. &lt;!--&lt;/span--&gt;bean&gt; <br />
<br />
messages.properties是按照资源包标准命名的，它代表了Acegi Securtiy支持的默认语言。文件默认是英文的。如果你不注册一个消息源，Acegi Security仍然可以正常工作，它会用回硬编码的英文消息。 <br />
如 果你想定制messages.properties文件，或者支持其他语言，那么你应该copy这个文件，然后重命名，并在上述的bean定义中 注册。因为文件中的key并不多，因此本地化花不了多少工夫。如果你针对消息文件进行了本地化，那么请和社区分享，你可以添加一个JIRA任务，将你正确 命名的messages.properties本地化文件作为附件添加。 <br />
为了完善关于本地化的讨论需要知道Spring的 ThreadLocal org.springframework.context.i18n.LocaleContextHolder。你应该为每个用户设置代表他区域的 LocaleContextHolder。Acegi Security会尝试从这个ThreadLocal中获取的Locale来从消息源中获取消息。请参考Spring的文档以获取更多使用 LocaleContextHolder和能够帮你自动设置它的辅助类(例如 <br />
AcceptHeaderLocaleResolver, CookieLocaleResolver, FixedLocaleResolver, SessionLocaleResolver 等)的详细信息。 <br />
3.2. Filters <br />
正如你在整个手册中看到的那样，Acegi Security使用很多filter。你可以使用FilterToBeanProxy或者FilterChainProxy来确定这些是怎样加入到你的web应用中的，下面我们来看看。 <br />
大部分filter使用FilterToBeanProxy来配置。例如下面web.xml中配置所示： <br />
xml 代码 <br />
<br />
1. &lt;filter&gt; <br />
2. &lt;filter-name&gt;Acegi HTTP Request Security Filter&lt;/filter-name&gt; <br />
3. &lt;filter-class&gt;org.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt; <br />
4. &lt;init-param&gt; <br />
5. &lt;param-name&gt;targetClass&lt;/param-name&gt; <br />
6. &lt;param-value&gt;org.acegisecurity.ClassThatImplementsFilter&lt;/param-value&gt; <br />
7. &lt;/init-param&gt; <br />
8. &lt;/filter&gt; <br />
<br />
<br />
注 意在web.xml中的filter实际上是一个FilterToBeanProxy，而不是真正实现filter逻辑的filter。 FilterToBeanProxy所作的是代理Filter的方法到一个从Spring的application context 获取的bean。这使得这个bean可以享受Spring application context的生命周期支持以及配置灵活性。这个bean必须实现javax.servlet.Filter。 <br />
FilterToBeanProxy 只需要一个简单的初始化参数，targetClass或者targetBean。targetClass会定位 application context中指定的类的第一个对象，而FilterToBeanProxy按照bean的名字定位对象。象标准的Spring web应用一样，FilterToBeanProxy使用 WebApplicationContextUtils.getWebApplicationContext(ServletContext)来访问 application context，所以你应该在web.xml中配置一个ContextLoaderListener。 <br />
<br />
在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。 <br />
我们强烈推荐你使用FilterChainProxy而不是FilterToBeanProxy。虽然 FilterToBeanProxy是一个非 常有用的类FilterToBeanProxy，问题是当web.xml中filter变多时， 和 项就会太多而变得臃肿不堪。为了解决这个问题，Acegi Security提供一个FilterChainProxy类。它在FilterToBeanProxy中被装配（正如上面例子中所示），但目标类 （target class）是org.acegisecurity.util.FilterChainProxy。这样过滤器链（filter chain）可以在application context中按照如下代码配置： <br />
xml 代码 <br />
<br />
1. &lt;bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy"&gt; <br />
2. &lt;property name="filterInvocationDefinitionSource"&gt; <br />
3. &lt;value&gt; <br />
4. CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON <br />
5. PATTERN_TYPE_APACHE_ANT <br />
6. /webServices/*=httpSessionContextIntegrationFilterWithASCFalse,basicProcessingFilter,exceptionTranslationFilter, <br />
7. /*=httpSessionContextIntegrationFilterWithASCTrue,authenticationProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor <br />
8. &lt;!--&lt;/span--&gt;value&gt; <br />
9. &lt;!--&lt;/span--&gt;property&gt; <br />
10. &lt;!--&lt;/span--&gt;bean&gt; <br />
<br />
你 可能注意到FilterSecurityInterceptor定义方式的相似之处。同时支持正则表达式和Ant Paths格式，越对应的URI越早出现。在运行时，FilterChainProxy会定位符合当前的web请求的第一个URI模式。每个对应的配置属 性代表了在application context中定义的一个bean的名字。接着fiter会按照它们被指定的顺序，按照FilterChain的标准行为模式被调用(如果一个 Filter决定停止处理，它可以不在chain中执行)。 <br />
如你所见，FilterChainProxy需要为不同的请求模式重复配置 filter的名字（在上面的例子中，, exceptionTranslationFilter 和 filterSecurityInterceptor 是重复的）。这样的设计是为了让FilterChainProxy能够为不同的URI配置不同的filter调用顺序，同时也提高了表达力（针对正则表达 式、Ant Paths、以及任何FilterInvocationDefinitionSource的特定实现）和清晰度，可以知道是哪个filter应该被调用。 <br />
你可能注意到了我们在filter chain定义了两个HttpSessionContextIntegrationFilter (ASC是allowSessionCreation的缩写,是HttpSessionContextIntegrationFilter的一个属性)。 因为web服务不会为将来的请求提供一个jsessionid，为这样的用户创建HttpSessions是浪费的。如果你有一个需要最大限度的伸缩性的 高容量的应用，我们建议你使用上述的方法。对于小的应用，使用单一的HttpSessionContextIntegrationFilter (默认的allowSessionCreation设为true)应该足够了。 <br />
说到生命周期问题，如果对FilterChainProxy自 身调用init(FilterConfig) 和 destroy()方法，它会把它代理到底层的filter。这样FilterChainProxy保证只初始化和析构每个filter一次，不论它在 FilterInvocationDefinitionSource中定义了多少次。你可以通过FilterToBeanProxy的lifecycle 初始化参数来控制这些方法是否被调用。如上面所讨论的那样，默认所有servlet容器生命周期调用是不被代理到FilterChainProxy的。 <br />
在web.xml中定义的filter的顺序是非常重要的。不管你实际用到哪个filter，的顺序应该是如下所示的： <br />
1．ChannelProcessingFilter，因为可能要重定向到另一种协议。 <br />
2．ConcurrentSessionFilter 因为不使用任何SecurityContextHolder的功能，但是需要更新SessionRegistry来表示当前的发送请求的principal。 <br />
3． HttpSessionContextIntegrationFilter, 这样当一个web请求开始的时候就可以在SecurityContextHolder中设置一个SecurityContext，当web请求结束的时候 任何对SecurityContext的改动都会被copy到HttpSession（以备下一个web请求使用）。 <br />
4． Authentication processing mechanisms - AuthenticationProcessingFilter, CasProcessingFilter, BasicProcessingFilter, HttpRequestIntegrationFilter, JbossIntegrationFilter 等 - 修改SecurityContextHolder，使其中包含一个有效的认证请求令牌（token）。 <br />
5．SecurityContextHolderAwareRequestFilter, 如果你使用它来在你的servlet容器中安装一个Acegi Security aware HttpServletRequestWrapper。 <br />
6． RememberMeProcessingFilter, 如果早期的认证处理过程没有更新SecurityContextHolder，并且请求（request）提供了一个cookie启用remember- me服务，一个合适的被记住的Authentication对象会被放到SecurityContextHolder那里。 <br />
7．AnonymousProcessingFilter, 如果早期的认证处理过程没有更新SecurityContextHolder，, 一个匿名Authentication 对象会被放到SecurityContextHolder那里。 <br />
8．ExceptionTranslationFilter, 捕获所有的Acegi Security 异常，这样要么返回一个HTTP错误响应或者加载一个对应的AuthenticationEntryPoint。 <br />
9．FilterSecurityInterceptor, 保护 web URIs <br />
所 有上述的filter使用FilterToBeanProxy或FilterChainProxy。建议在一个应用中使用一个单个的 FilterToBeanProxy代理到一个单个的FilterChainProxy。，在FilterChainProxy中定义所有的Acegi Security Filters。如果你使用SiteMesh，确保Acegi Security filters 在 SiteMe**ers调用前调用。这样使SecurityContextHolder在SiteMesh decorator使用前能够 <br />
<br />
<br />
acegi参考手册(v1.0.4)[译]-第四章 信道安全 <br />
第四章. 信道安全 <br />
4.1. 概述 <br />
Acegi Security不仅能满足你的认证和授权的请求，而且能够保证你的未认证的web请求也能拥有某些属性。这些属性可能包括使用特定的传输类型，在HttpSession设置特定的属性等等。Web请求的最普遍的需求是使用特定的传输协议，例如HTTPS。 <br />
在 传输安全中的一个重要议题就是会话劫持（session hijacking）。Web容器通过一个jsessionid来引用一个HttpSession，这个jsessionid通过cookie 或者URL重写转向（URL rewriting）发送到到客户端。如果jsessionid是通过HTTP发送的，那么就存在被劫持以及在认证过程之后冒充被认证用户的可能。这是因 为大部分的web容器为特定的用户维护同一个会话标识符，即便是用户从HTTP 切换到 HTTPS页面。 <br />
如果对于你的特定应用来说，会话劫 持（session hijacking）是一个很严重的风险，那么唯一的解决方法就是对每一个请求都使用HTTPS。这意味着jsessionid不会使用非安全信道传输。 你要保证你的web.xml中定义，把它指向一个HTTPS位置，同时应用程序不把用户指向一个HTTP位置。 Acegi Security提供一个解决方案帮助你实现后者。 <br />
4.2. 配置 <br />
启用Acegi Security的信道安全服务，需要在web.xml中增加如下行： <br />
xml 代码 <br />
<br />
1. &lt;filter&gt; <br />
2. &lt;filter-name&gt;Acegi Channel Processing Filter&lt;/filter-name&gt; <br />
3. &lt;filter-class&gt;org.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt; <br />
4. &lt;init-param&gt; <br />
5. &lt;param-name&gt;targetClass&lt;/param-name&gt; <br />
6. &lt;param-value&gt;org.acegisecurity.securechannel.ChannelProcessingFilter&lt;/param-value&gt; <br />
7. &lt;/init-param&gt; <br />
8. &lt;/filter&gt;&lt;filter-mapping&gt; <br />
9. &lt;filter-name&gt;Acegi Channel Processing Filter&lt;/filter-name&gt; <br />
10. &lt;url-pattern&gt;/*&lt;/url-pattern&gt; <br />
11. &lt;/filter-mapping&gt; <br />
<br />
<br />
和平时一样，你同样需要在application context中配置filter <br />
java 代码 <br />
<br />
1. "channelProcessingFilter" class="org.acegisecurity.securechannel.ChannelProcessingFilter"&gt; <br />
2. "channelDecisionManager"&gt;"channelDecisionManager"/&gt; <br />
3. "filterInvocationDefinitionSource"&gt; <br />
4. <br />
5. CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON <br />
6. \A/secure/.*\Z=REQUIRES_SECURE_CHANNEL <br />
7. \A/acegilogin.jsp.*\Z=REQUIRES_SECURE_CHANNEL <br />
8. \A/j_acegi_security_check.*\Z=REQUIRES_SECURE_CHANNEL <br />
9. \A.*\Z=REQUIRES_INSECURE_CHANNEL <br />
10. <br />
11. <br />
12. <br />
13. <br />
14. "channelDecisionManager" class="org.acegisecurity.securechannel.ChannelDecisionManagerImpl"&gt; <br />
15. "channelProcessors"&gt; <br />
16. <br />
17. "secureChannelProcessor"/&gt; <br />
18. "insecureChannelProcessor"/&gt; <br />
19. <br />
20. <br />
21. <br />
22. <br />
23. "secureChannelProcessor" class="org.acegisecurity.securechannel.SecureChannelProcessor"/&gt; <br />
24. <br />
25. "insecureChannelProcessor" class="org.acegisecurity.securechannel.InsecureChannelProcessor"/&gt; <br />
<br />
<br />
ChannelProcessingFilter和FilterSecurityInterceptor一样支持Apache Ant style paths。 <br />
ChannelProcessingFilter 的工作方式是过滤所有的web请求，并将判断将适合的配置属性应用于其上。然后它代理到 ChannelDecisionManager。默认的实现类ChannelDecisionManagerImpl应该能够满足大多数需求。它就代理到 配置好的ChannelProcessor实例列表。ChannelProcessor会检视请求，如果它不满意请求（例如请求是发送自不正确的传输协 议）它将会重定向，抛出异常或者采取其他任何恰当的措施。 <br />
Acegi Security 包括ChannelProcessor两个实体类实现：SecureChannelProcessor 保证配置了REQUIRES_SECURE_CHANNEL 属性的请求都是从HTTPS发送过来的。而InsecureChannelProcessor 保证配置了REQUIRES_INSECURE_CHANNEL 属性的请求都是从HTTP发送过来的。如果没有使用请求的协议，这两个实现都会转到ChannelEntryPoint，而两个 ChannelEntryPoint 实现所作的就是简单的把请求相应按照HTTP 和 HTTPS重定向。 <br />
要注意重定向是绝对（例如 http://www.company.com:8080/app/page ） 而不是相对的(例如 /app/page)。在测试中发现Internet Explorer 6 Service Pack 1 有一个bug，因此如果在重定向的时候也改变使用的端口，它就不能正确响应。对应这个bug，在很多Acegi Security bean中都会使用的PortResolverImpl也使用绝对URL。请参阅PortResolverImpl的JavaDoc以获取更多信息。 <br />
你 要注意使用为了在登录过程中保证用户名和密码的安全，要使用安全信道。如果你配合基于表单的登录使用 ChannelProcessingFilter，请记得一定要把你的登录页面设置为REQUIRES_SECURE_CHANNEL，并且 AuthenticationProcessingFilterEntryPoint.forceHttps属性设置为true。 <br />
4.3. 结论 <br />
一 旦配置好了，使用安全信道是非常简单的。只要请求页面，不用管使用什么协议（HTTP 或 HTTPS）或什么端口（80, 8080, 443, 8443等）。显然你只要确定初始请求(获取通过在web.xml 中的 或一个众所周知的主页URL)，完成以后filter会执行你application context定义的重定向。 <br />
你也可以在ChannelDecisionManagerImpl中增加自己的ChannelProcessor实现。例如，你可能通过"输入图片中的内容"检测到一个个人类用户，然后在HttpSession中设置一个属性。 <br />
要判断一个安全检查应该是或者ChannelProcessor或是 AccessDecisionVoter 记得前者是设计用来处理认证或者未认证的请求，而后者是设计用来处理已认证的请求。因此后者可以访问已认证的principal被授予的权限。 <br />
另 外，ChannelProcessor检测到问题后一般是引发一个HTTP/HTTPS重定向这样他的请求可以被满足，而 AccessDecisionVoter将则会跑出一个AccessDeniedException异常(取决于支配的 AccessDecisionManager)。 <br />
acegi参考手册(v1.0.4)[译]-第五章 标签库 <br />
5.1. 概述 <br />
Acegi Security带有若干个可以降低JSP编写难度的JSP标签库。标签库的标志是authz，它提供了一些各不相同的服务。 <br />
5.2. 配置 <br />
所 有的标签库类都包含在acegi-security-xx.jar文件中，authz.tld在JAR的META-INF目录。这意味着如果在 JSP1.2以上的wb容器中，你只要把JAR文件放到WEB-INF/lib目录它就可用了。如果你使用JSP1.1容器，你需要在web.xml文件 中声明JSP标签库，并在WEB-INF/lib中包含authz.tld文件。将如下片段加入到web.xml中： <br />
<br />
java 代码 <br />
1. <br />
2. http://acegisecurity.org/authz <br />
3. /WEB-INF/authz.tld <br />
4. <br />
第六章. 通用认证服务 <br />
6.1. Mechanisms, Providers 和 Entry Points <br />
如果你使用Acegi Security提供的认证方法，那么通常你需要配置一个web filter，一个AuthenticationProvider <br />
以及AuthenticationEntryPoint。在本节我们将要浏览一个示例应用，它需要支持基于form的认证（例如提供给用户登录的HTML页面）以及基础认证（例如web service或者类似的可以访问受保护资源）。 <br />
<br />
在web.xml中，这个应用需要一个单独的Acegi Security filter来使用FilterChainProxy。几乎所有的Acegi Security应用都有一个类似的项，看起来象下面这样： <br />
<br />
xml 代码 <br />
1. &lt;filter&gt; <br />
2. &lt;filter-name&gt;Acegi Filter Chain Proxy&lt;/filter-name&gt; <br />
3. &lt;filter-class&gt;org.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt; <br />
4. &lt;init-param&gt; <br />
5. &lt;param-name&gt;targetClass&lt;/param-name&gt; <br />
6. &lt;param-value&gt;org.acegisecurity.util.FilterChainProxy&lt;/param-value&gt; <br />
7. &lt;/init-param&gt; <br />
8. &lt;/filter&gt; <br />
9. &lt;filter-mapping&gt; <br />
10. &lt;filter-name&gt;Acegi Filter Chain Proxy&lt;/filter-name&gt; <br />
11. &lt;url-pattern&gt;/*&lt;/url-pattern&gt; <br />
12. &lt;/filter-mapping&gt; <br />
<br />
上 述声明将使每个web请求都要经过Acegi Security的FilterChainProxy。正如在本手册的filter那节中所说，FilterChainProxy是一个通用类，它使得 web请求按照URL模式被发送到不同的filter。那些被委派的filter是由application context管理的，因此它们可以享受依赖注射的好处。我们来看看在你的application context中FilterChainProxy的定义会是什么样的： <br />
<br />
xml 代码 <br />
1. &lt;bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy"&gt; <br />
2. &lt;property name="filterInvocationDefinitionSource"&gt; <br />
3. &lt;value&gt; <br />
4. CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON <br />
5. PATTERN_TYPE_APACHE_ANT <br />
6. /**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,basicProcessingFilter,securityContextHolderAwareRequestFilter,&lt;/value&gt; <br />
7. &lt;/property&gt; <br />
8. &lt;/bean&gt; <br />
<br />
在内部，Acegi Security会使用PropertyEditor来将上述XML片段中的字符串转化为一个 FilterInvocationDefinitionSource对象。在这个阶段需要注意的是，一系列的filter会按照定义的顺序运行，并且这些 filter实际就是application context中的bean的。所以，在我们的例子中，会在application context出现另外一些bean，它们会被命名为httpSessionContextIntegrationFilter, logoutFilter 等。Filter出现的顺序会在手册中filter那一节讨论，虽然上述的例子中它们是正确的。 <br />
<br />
在我们的 例子中，我们使用了AuthenticationProcessingFilter和BasicProcessingFilter。它们分别对应了基于 form的认证和BASIC HTTP header-based认证的&#8220;认证机制&#8221;（我们在手册的前面部分讨论了认证机制扮演的角色）。如果你既不使用form也不使用BASIC认证，就不需 要定义这些bean了。取而代之的是你要定义对应你所需要的认证环境的filter，例如DigestProcessingFilter 或者CasProcessingFilter。请对照手册中对应的章节来了解如何配置这些认证机制。 <br />
<br />
让我们回忆一下，在 HttpSessionContextIntegrationFilter中保存了每个HTTP session调用中的SecurityContext。这意味着认证机制只会在principal最初尝试认证的时候被使用一次。在余下的时间内，认证 机制只是静静的待在那里，将请求发往filter链中的下一个filter。这个基于实际的需求源于这样的一个事实，很少有认证实现在每一个，每一次的调 用的时候都会进行认证（BASIC认证是一个值得注意的例外），但是如果一个pricipal在最初的认证步骤之后帐号被取消了，或者被禁用了，或者被修 改了（例如GrantedAuthority[]中增加或者减少）会怎么样呢？让我们来看看现在这些情况是如何处理的。 <br />
<br />
前面已经介绍 了安全对象的主要认证provider AbstractSecurityInterceptor。这个类需要能够访问一个AuthenticationManager。它同时有个可选配置可以 设定一个认证对象每次安全对象调用的时候是否需要重新认证。如果Authentication.isAuthenticated()返回true，那么它 默认在SecurityContextHolder中的认证对象是已认证的。这样做对于提高性能是非常好的，但是对于即时的认证验证是不理想的。在这样的 情况下你可能需要将AbstractSecurityInterceptor.alwaysReauthenticate属性设置为true。 <br />
<br />
你 可能会问自己&#8220;这个AuthenticationManager是什么？&#8221;我们之前没有见过它，但是我们曾经讨论过 AuthenticationProvider的概念。非常简单，AuthenticationManager负责在 AuthenticationProvider链之间传递请求。它非常象我们之前讨论过的filter链，虽然有一些不同。Acegi Security只提供了一个AuthenticationManager实现，因此让我们看看对于我们这章的例子，它是如何配置的： <br />
<br />
xml 代码 <br />
1. &lt;bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager"&gt; <br />
2. &lt;property name="providers"&gt; <br />
3. &lt;list&gt; <br />
4. &lt;ref local="daoAuthenticationProvider"/&gt; <br />
5. &lt;ref local="anonymousAuthenticationProvider"/&gt; <br />
6. &lt;ref local="rememberMeAuthenticationProvider"/&gt; <br />
7. &lt;/list&gt; <br />
8. &lt;/property&gt; <br />
9. &lt;/bean&gt; <br />
<br />
在这个时候，可能值得提到的是你的认证机制（通常是filter）也被注入了一个AuthenticationManager的引用。所以和认证机制都会使用上述的ProviderManager来轮询一系列的AuthenticationProvider。 <br />
<br />
在 我们例子中有三个provider。它们按照上述的顺序调用（使用list而不是set来显示是按照顺序调用的），每个provider都能够尝试认证， 或者仅仅返回一个null来跳过认证。如果所有的实现都返回null，ProviderManager会抛出一个相应的异常。如果你想了解更多 chaining providers的信息，请参阅ProviderManager的JavaDoc。 <br />
<br />
authentication mechanism使用的那些provider有时候是可以互换的，而有时候它们又依赖于特定的authentication mechanism。例如，DaoAuthenticationProvider只需要一个基于字符串的用户名和密码。若干个认证机制会产生基于字符串的 用户名和密码的集合，包括（但不限于）BASIC 和 form 认证。同时，有些认证机制会产生一个只能和特定类型的AuthenticationProvider交互的认证请求对象。一个这种一对一映射的例子是JA -SIG CAS，它使用service ticket的概念，只能被Common Authentication Services CasAuthenticationProvider认证。一个更加深入的一对一映射的例子是LDAP认证机制，它只能由 LdapAuthenticationProvider处理。这种特定的对应关系在每个类的JavaDoc以及在本手册的特定认证方法章节中有详细说明。 你不用担心这些实现的细节，因为如果你忘记注册一个合适的provider，你在尝试认证时只会收到一个 ProviderNotFoundException异常。 <br />
<br />
当你在FilterChainProxy中正确配置了认证机制，并且确保 注册了对应的AuthenticationProvider，你的最后一步是配置一个AuthenticationEntryPoint。回忆一下早先我 们讨论过的ExceptionTranslationFilter的角色，当一个基于HTTP的请求收到一个HTTP头或者一个HTTP重定向以开始认证 时它被使用。继续我们早先的例子： <br />
<br />
xml 代码 <br />
1. &lt;bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter"&gt; <br />
2. &lt;property name="authenticationEntryPoint"&gt;&lt;ref <br />
3. local="authenticationProcessingFilterEntryPoint"/&gt;&lt;/property&gt; <br />
4. &lt;property name="accessDeniedHandler"&gt; <br />
5. &lt;bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl"&gt; <br />
6. &lt;property name="errorPage" value="/accessDenied.jsp"/&gt; <br />
7. &lt;/bean&gt; <br />
8. &lt;/property&gt; <br />
9. &lt;/bean&gt; <br />
10. &lt;bean id="authenticationProcessingFilterEntryPoint" <br />
11. class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint"&gt; <br />
12. &lt;property name="loginFormUrl"&gt;&lt;value&gt;/acegilogin.jsp&lt;/value&gt;&lt;/property&gt; <br />
13. &lt;property name="forceHttps"&gt;&lt;value&gt;false&lt;/value&gt;&lt;/property&gt; <br />
14. &lt;/bean&gt; <br />
<br />
注 意到ExceptionTranslationFilter需要两个协作者。第一个AccessDeniedHandlerImpl，使用一个 RequestDispatcher导向显示特定的访问拒绝的错误页面。我们使用forwad所以SecurityContextHolder中仍然保留 principal的详细信息，这些对于显示给用户来说是有用的（在Acegi Security的老版本中，我们依赖rervlet容器来处理403错误信息，它缺乏这个有用的上下文信息）。 AccessDeniedHandlerImpl同时将会将HTTP头设置为403，它是访问拒绝的正式错误代码。至于 AuthentionEntryPoint，这里设置如果一个未受认证的principal尝试执行一个受保护的操作时，我们需要执行那些动作。因为在我 们的例子中要使用基于form的认证，因此我们设定AuthenticationProcessinFilterEntryPoint以及登录页面的 URL。你的应用系统通常只需要一个entry point，并且大多数的认证方法都定义了自己特有的AuthenticationEntryPoint。每个认证方式所对应的特定entry point的详细情况会在本手册特定的认证方法章节中介绍。 <br />
6.2. UserDetails 和 Associated Types <br />
正如在第一部分中提到的，大多数认证provider要用到UserDetails 和UserDetailsService 接口。后面那个接口只包含一个方法： <br />
<br />
java 代码 <br />
1. public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, <br />
2. DataAccessException; <br />
<br />
<br />
返 回值UserDetails是一个接口，它提供了若干个getter保证返回非null值，例如用户名，密码，授予的权限以及用户是启用还是禁用状态。大 部分认证provider都会使用一个，即使它在认证判断过程中实际并不使用用户名和密码。通常这些provider只会使用返回的 UserDetails中的GrantedAuthority[]信息，因为有些系统（例如LDAP 或 X509 或 CAS）已经承担了实际的身份验证的责任。 <br />
<br />
Acegi Security提供了一个UserDetails的实体类实现－User。Acegi Security用户需要确定什么时候实现UserDetailsService以及返回什么样的UserDetails实体类。通常，直接使用User 类或者继承User类就可以了，尽管有一些特殊情况(例如 object relational mappers)，需要用户从头写他们自己的UserDetails实现。这种情况也时有发生，用户只要返回他们正常的代表系统用户的领域对象就可以了。 特别是UserDetails经常被用来存储额外的principal相关属性（例如他们的电话号码以及email地址），这样它们可以很容易被web视 图使用。 <br />
<br />
特定的UserDetailsService实现起来是很简单的，它应该很容易由用户来选择持久化策略来获取认证信息。说到这里，Acegi Security确实包含了一些有用的基础实现，下面让我们看一下。 <br />
<br />
6.2.1. In-Memory 认证 <br />
虽 然用户可以创建一个定制的UserDetailsService实现来从一个持久化引擎中获取信息，很多应用不需要这种复杂性。特别是如果你正在进行快速 原型开发或者刚开始集成Acegi Security，当你不需要花费时间来进行数据库配置或者写UserDetailsService的实现。这种情况之下，你有一个简单的选择，就是配置 InMemoryDaoImpl实现。 <br />
<br />
xml 代码 <br />
1. &lt;bean id="inMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl"&gt; <br />
2. &lt;property name="userMap"&gt; <br />
3. &lt;value&gt; <br />
4. marissa=koala,ROLE_TELLER,ROLE_SUPERVISOR <br />
5. dianne=emu,ROLE_TELLER <br />
6. scott=wombat,ROLE_TELLER <br />
7. peter=opal,disabled,ROLE_TELLER <br />
8. &lt;/value&gt; <br />
9. &lt;/property&gt; <br />
10. &lt;/bean&gt; <br />
<br />
在 上面的例子中，userMap属性包含了每个用户的用户名，密码，一个授权列表以及一个可选的启用/禁用关键词。使用逗号分隔。用户名必须在等号的左侧， 密码必须在等号右侧第一个出现。启用和禁用关键词（大小写敏感）可以出现在第二个或者之后任意位置。剩余的字符串被看作是授予的权限，这些权钱被创建为 GrantedAuthorityImpl对象（仅供参考－大多数的应用不需要自定义的GrantedAuthority实现，所以使用默认的实现就可以 了）。注意如果一个用户没有密码及或没有被授予权限，该用户不会在in-memory 认证库中创建。 <br />
<br />
InMemoryDaoImpl 也提供了一个setUserProperties(Properties)方法，可以允许你用另一个Spring的配置好的bean或者一个外部的 properties文件来实例化属性。你可能要使用Spring的PropertiesFactoryBean，它在加载外部属性文件的时候非常有用。 这个setter可能对于有大量用户的应用，或者开发期配置变更有所助益，但是不要指望使用整个数据库来处理认证细节。 <br />
<br />
6.2.2. JDBC 认证 <br />
也 包括了一个从JDBC数据源获取认证信息的UserDetailsService。使用Spring内部的JDBC，避免了仅仅为了存储用户信息而使用复 杂的对象关系Common Authentication Services 映射（ORM）。如果你确实使用ORM工具，你可能要写一个定制的UserDetailsService来重用你已经创建的映射文件。回到 JdbcDaoImpl，下面是一个配置的例子： <br />
<br />
xml 代码 <br />
1. &lt;bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"&gt; <br />
2. &lt;property name="driverClassName"&gt;&lt;value&gt;org.hsqldb.jdbcDriver&lt;/value&gt;&lt;/property&gt; <br />
3. &lt;property name="url"&gt;&lt;value&gt;jdbc:hsqldb:hsql://localhost:9001&lt;/value&gt;&lt;/property&gt; <br />
4. &lt;property name="username"&gt;&lt;value&gt;sa&lt;/value&gt;&lt;/property&gt; <br />
5. &lt;property name="password"&gt;&lt;value&gt;&lt;/value&gt;&lt;/property&gt; <br />
6. &lt;/bean&gt; <br />
7. &lt;bean id="jdbcDaoImpl" class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl"&gt; <br />
8. &lt;property name="dataSource"&gt;&lt;ref bean="dataSource"/&gt;&lt;/property&gt; <br />
9. &lt;/bean&gt; <br />
10. <br />
你 可能要修改上述的DriverManagerDataSource来使用不同的关系数据库管理系统。你还可以使用从JNDI获取的全局数据源，如上的常规 Spring选项。不论是使用什么数据库以及如何获取数据源，必须使用一个按照dbinit.txt中写明的数据库模式。你可以从Acegi Security网站下载这个文件。 <br />
<br />
如果你的默认数据库模式不能满足需要，JdbcDaoImpl提供了两个属性允许定制SQL语 句。如果需要进一步定制，你可以继承JdbcDaoImpl。请参考JavaDocs获取详情，不过请注意这个类并不是为了复杂的自定义继承而写的。如果 你的需求比较复杂(例如数据库结构比较特殊或者需要返回一个特定的UserDetails实现)，那么你最好写自己的 UserDetailsService实现。Acegi Security提供的基础实现只是为了典型场景，并没有提供无限的配置灵活性。 <br />
<br />
6.3. 并行Concurrent Session 处理 <br />
Acegi Security能够限定次数防止一个principal多次并行认证到同一个应用。许多ISV利用这一点来加强授权管理，网管也喜欢这个特性因为可以防止一个用户名被重复使用。例如，你可以限制&#8220;Batman&#8221;用户从两个不同的session登录系统。 <br />
<br />
使用并行session支持，你需要在web.xml中增加如下内容： <br />
<br />
xml 代码 <br />
1. &lt;listener&gt; <br />
2. &lt;listener-class&gt;org.acegisecurity.ui.session.HttpSessionEventPublisher&lt;/listener-class&gt; <br />
3. &lt;/listener&gt; <br />
<br />
而 且，你需要在中FilterChainProxy增加 org.acegisecurity.concurrent.ConcurrentSessionFilter to your FilterChainProxy。ConcurrentSessionFilter需要两个属性，sessionRegistry用来指向一个 SessionRegistryImpl实例，expiredUrl指向一个session实效时显示的页面。 <br />
<br />
当一个 HttpSession开始或者结束的时候web.xml HttpSessionEventPublisher发送一个ApplicationEvent到Spring ApplicationContext。这很关键，因为它确保session终止的时候SessionRegistryImpl会收到通知。 <br />
<br />
你还要装配ConcurrentSessionControllerImpl并在ProviderManager中引用： <br />
<br />
xml 代码 <br />
1. &lt;bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager"&gt; <br />
2. &lt;property name="providers"&gt; <br />
3. &lt;!-- your providers go here --&gt; <br />
4. &lt;/property&gt; <br />
5. &lt;property name="sessionController"&gt;&lt;ref bean="concurrentSessionController"/&gt;&lt;/property&gt; <br />
6. &lt;/bean&gt; <br />
7. &lt;bean id="concurrentSessionController" <br />
8. class="org.acegisecurity.concurrent.ConcurrentSessionControllerImpl"&gt; <br />
9. &lt;property name="maximumSessions"&gt;&lt;value&gt;1&lt;/value&gt;&lt;/property&gt; <br />
10. &lt;property name="sessionRegistry"&gt;&lt;ref local="sessionRegistry"/&gt;&lt;/property&gt; <br />
11. &lt;/bean&gt; <br />
12. &lt;bean id="sessionRegistry" class="org.acegisecurity.concurrent.SessionRegistryImpl"/&gt; <br />
6.4. 认证标签库 <br />
AuthenticationTag只是用来把principal的Authentication.getPrincipal()对象的属性显示到web页面。 <br />
<br />
下面的JSP片段展示了如何使用AuthenticationTag： <br />
java 代码 <br />
1. "username"/&gt; <br />
<br />
这个标签将会显示pricipal的名字。这里我们假设Authentication.getPrincipal()是一个UserDetails对象，这在使用典型的DaoAuthenticationProvider时候的一般状况。<br />
[转载自 dxjsunday]<img src ="http://www.blogjava.net/mlh123caoer/aggbug/142743.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-09-04 21:13 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/09/04/142743.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EJB3.0入门</title><link>http://www.blogjava.net/mlh123caoer/archive/2007/09/02/142067.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Sun, 02 Sep 2007 06:22:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/09/02/142067.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/142067.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/09/02/142067.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/142067.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/142067.html</trackback:ping><description><![CDATA[<p><span style="word-spacing: 0px; font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 16px; line-height: normal; font-size-adjust: none; font-stretch: normal; text-transform: none; color: #000000; text-indent: 0px; white-space: normal; letter-spacing: normal; border-collapse: separate; orphans: 2; widows: 2;" class="Apple-style-span">作者： Lynn Munsinger<br />
翻译：草儿<br />
时间：2007年8月29日（My Birthday）<br />
原文地址：<span style="word-spacing: 0px; font-family: 'Lucida Grande'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 12px; line-height: normal; font-size-adjust: none; font-stretch: normal; text-transform: none; color: #000000; text-indent: 0px; white-space: pre; letter-spacing: normal; border-collapse: separate; orphans: 2; widows: 2;" class="Apple-style-span"><a href="http://www.oracle.com/technology/tech/java/newto/introejb.htm">http://www.oracle.com/technology/tech/java/newto/introejb.htm</a></span></span></p>
<p><br />
EJB3.0规范使开发EJB比过去更容易，可能诱惑你考虑开发第一个EJB。如果真是这种情况，那么祝贺你，<br />
你经成功避免了在你以前EJB开发者的很多挫折，并且享受到EJB3.0开发的便利性。但是你开始开发以前，<br />
你可能想知道EJB是什么和它们用于什么目的。本篇文章解释了EJB的基础和你如何在一个J2EE程序中使用<br />
它们。<br />
<br />
<span class="boldbodycopy">什么是EJB？</span></p>
<p>一个企业JavaBean (EJB)是一个可重用的，可移植的J2EE组件。 EJB由封装了业务逻辑的多个方法组成。<br />
例如，一个EJB可以有包括一个更新客户数据库中数据的方法的业务逻辑。多个远程和本地客户端可以调用这<br />
个方法。另外，EJB运行在一个容器里，允许开发者只关注与bean中的业务逻辑而不用考虑象事务支持，安全<br />
性和远程对象访问等复杂和容易出错的事情。EJB以POJO或者普通旧的Java对象形式开发，开发者可以用元数<br />
据注释来定义容器如何管理这些Bean。</p>
<p><span class="boldbodycopy">EJB类型</span></p>
<p>EJB主要有三种类型：会话Bean，实体Bean和消息驱动Bean。会话Bean完成一个清晰的解耦的任务，例如<br />
检查客户账户历史记录。实体Bean是一个代表存在于数据库中业务对象的复杂业务实体。消息驱动Bean用于<br />
接收异步JMS消息。让我们更详细的认识这些类型。</p>
<p>会话<span class="italicbodycopy">Bean</span></p>
<p>会话Bean一般代表着业务流程中象"处理订单"这样的动作。会话Bean基于是否维护过度状态分为有状<br />
态或者无状态。<br />
无状态会话Bean 没有中间状态。它们不保持追踪一个方法调用另一个方法传递的信息。因此一个无状<br />
态业务方法的每一次调用都独立于它的前一个调用；例如，税费计算或者转移账款。 当计算税费额的方法被<br />
调用时，税费值被计算并返回给调用的方法，没有必要存储调用者为将来调用备用的内部状态。因为它们不<br />
维护状态，所以这些Bean是仅仅由容器管理。当客户端请求一个无状态的Bean实例时，它可以接收来自由容器管理的无状态会话Bean实例集中的一个实例。也因为无状态会话Bean能够被共享，所以容器可以维护更少<br />
数量的实例来为大量的客户端服务。简单地象该Bean增加元注释<span style="font-family: Courier New;">@Stateless</span> 来指定一个 Java Bean作为一个<br />
无状态会话Bean被部署和管理。<br />
一个有状态的会话Bean维护一个跨越多个方法调用的会话状态；例如在线购物篮应用。当客户开始在线<br />
购物时，客户的详细信息从数据库获得。相同的信息对于当客户从购物篮中增加或者移除商品等等操作时被调用的其他方法也是可访问的 。但是因为该状态不是在会话结束，系统崩溃或者网络失败时保留，所以有状<br />
态会话Bean是暂时的。当一个客户端请求一个有状态会话Bean实例时，客户端将会得到一个会话实例，该Bean的状态只为给客户端维持。通过向方法增加元注释<span style="font-family: Courier New;">@Remove来告诉容器当某个方法调用结束一个有状态<br />
会话Bean实例应该被移除。</span></p>
<h4>会话Bean实例</h4>
<blockquote>
<table border="1" width="100%">
    <tbody>
        <tr>
            <td>
            <p><code>import javax.ejb.Stateless.*;</code></p>
            <p><code>/**<br />
            * 一个简单无状态会话Bean实现了CalculateEJB接口的incrementValue()方法<br />
            </code><code>**/<br />
            <br />
            @Stateless(name="CalculateEJB")<br />
            public class CalculateEJBBean<br />
            implements CalculateEJB<br />
            {<br />
            int value = 0;<br />
            public String incrementValue()<br />
            {<br />
            value++;<br />
            return "value incremented by 1";<br />
            }<br />
            }</code></p>
            </td>
        </tr>
    </tbody>
</table>
</blockquote>
<p><span class="italicbodycopy">实体Bean</span></p>
<p>实体Bean是管理持久化数据的一个对象，潜在使用一些相关的Java对象并且可以依靠主键被唯一识别。通<br />
过包括<span style="font-family: Courier New;">@Entity</span> 元注释来指定一个类是一个实体Bean。实体Bean表示来自数据库的持久化数据，例如客户表<br />
中的一个记录，或者一个员工表中的一个员工记录。实体Bean也可以被多个客户端共享。例如一个员工实体<br />
能够被多个计算一个员工每年工资总额或者更新员工地址的客户端使用。实体Bean对象特定变量能够保持持<br />
久化。实体Bean中所有没有<span style="font-family: Courier New;">@Transient</span> 元注释的变量需要考虑持久化。EJB3.0的一个主要特色是创建包含使用元数据注释的对象/关系映射实体Bean的能力。例如，指定实体Bean的empId变量映射到employee表中的<br />
EMPNO属性，象下面实例中一样用<span style="font-family: Courier New;">@Table(name="Employees")</span> 注释这个表的名字和用<span style="font-family: Courier New;">@Column<br />
(name="EMPNO")注释empId变量。另外，EJB3.0中的一个特色是你可以很容易的在开发时测试实体<br />
Bean，可以用<span style="font-family: Times New Roman;">Oracle Application Server Entity Test Harness</span>在容器外部运行一个实体Bean。</span></p>
<h4>实体Bean实例</h4>
<blockquote>
<table border="1" width="100%">
    <tbody>
        <tr>
            <td>
            <p><code>import javax.persistence.*;<br />
            import java.util.ArrayList;<br />
            import java.util.Collection;</code></p>
            <p><code>@Entity<br />
            @Table(name = "EMPLOYEES")<br />
            public class Employee implements java.io.Serializable<br />
            {<br />
            private int empId;<br />
            private String eName;<br />
            private double sal;<br />
            <br />
            @Id<br />
            @Column(name="EMPNO", primaryKey=true)<br />
            public int getEmpId()<br />
            </code><code>{<br />
            return empId;<br />
            </code><code>}</code></p>
            <p><code>public void setEmpId(int empId)<br />
            {<br />
            this.empId = empId;<br />
            }</code></p>
            <p><code>public String getEname()<br />
            {<br />
            return eName;<br />
            }</code></p>
            <p><code>public void setEname(String eName)<br />
            {<br />
            this.eName = eName;<br />
            }<br />
            <br />
            public double getSal()<br />
            {<br />
            return sal;<br />
            }</code><br />
            <br />
            <code>public void setSal(double sal)<br />
            {<br />
            this.sal = sal;<br />
            }<br />
            <br />
            public String toString()<br />
            {<br />
            StringBuffer buf = new StringBuffer();<br />
            buf.append("Class:")<br />
            .append(this.getClass().getName()).append(" :: ").append(" empId:").append(getEmpId()).append(" ename:").append(getEname()).append("sal:").append(getSal());<br />
            return buf.toString();<br />
            }<br />
            }</code></p>
            </td>
        </tr>
    </tbody>
</table>
</blockquote>
<p><span class="italicbodycopy">消息驱动Bean</span></p>
<p>驱动Bean (MDB) 提供了一个实现异步通信比直接使用Java消息服务（JMS）更容易地方法。创建MDB接<br />
收异步JMS消息。容器处理为JMS队列和主题所要求加载处理的大部分工作。它向相关的MDB发送所有的消<br />
息。一个MDB允许J2EE应用发送异步消息，该应用能处理这些消息。实现<span style="font-family: Courier New;"><span style="font-family: Courier New;">javax.jms.<br />
</span></span><span style="font-family: Courier New;">MessageListener接口和使用<code>@MessageDriven注释该Bean来</code></span>指定一个Bean是消息驱动Bean。</p>
<h4>消息驱动Bean实例</h4>
<blockquote>
<table border="1" width="100%">
    <tbody>
        <tr>
            <td>
            <p><code>import javax.ejb.MessageDriven;<br />
            import javax.ejb.ActivationConfigProperty;<br />
            import javax.ejb.Inject;<br />
            import javax.jms.*;<br />
            import java.util.*;<br />
            import javax.ejb.TimedObject;<br />
            import javax.ejb.Timer;<br />
            import javax.ejb.TimerService;<br />
            @MessageDriven(<br />
            activationConfig = {<br />
            @ActivationConfigProperty(propertyName="connectionFactoryJndiName", propertyValue="jms/TopicConnectionFactory"),<br />
            @ActivationConfigProperty(propertyName="destinationName", propertyValue="jms/myTopic"),<br />
            @ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Topic"),<br />
            @ActivationConfigProperty(propertyName="messageSelector", propertyValue="RECIPIENT = 'MDB'")</code><br />
            <code>}<br />
            )</code></p>
            <p><code>/**<br />
            *监听可配置JMS队列或者主题和通过当一个消息发送到队列或者主题<br />
            *</code><code>调用它的onMessage()方法得到提醒的一个简单的消息驱动<br />
            *该Bean打印消息的内容<br />
            </code><code>*/</code></p>
            <p><code>public class MessageLogger implements MessageListener, TimedObject<br />
            {</code></p>
            <p><code>@Inject javax.ejb.MessageDrivenContext mc;<br />
            <br />
            public void onMessage(Message message)<br />
            {<br />
            System.out.println("onMessage() - " + message);<br />
            try<br />
            </code><code>{<br />
            </code><code>String subject = message.getStringProperty("subject");<br />
            String inmessage = message.getStringProperty("message");<br />
            System.out.println("Message received\n\tDate: " + new java.util.Date() + "\n\tSubject: " + subject + "\n\tMessage: " + inmessage + "\n");<br />
            System.out.println("Creating Timer a single event timer");<br />
            TimerService ts = mc.getTimerService();<br />
            Timer timer = ts.createTimer(30000, subject);<br />
            System.out.println("Timer created by MDB at: " + new Date(System.currentTimeMillis()) +" with info: "+subject);<br />
            }<br />
            catch (Throwable ex)<br />
            {<br />
            ex.printStackTrace();<br />
            }<br />
            }<br />
            </code><code><br />
            public void ejbTimeout(Timer timer)<br />
            {<br />
            System.out.println("EJB 3.0: Timer with MDB");<br />
            </code><code>System.out.println("ejbTimeout() called at: " + new Date(System.currentTimeMillis()));<br />
            </code><code>return;<br />
            }</code><code><br />
            }</code></p>
            </td>
        </tr>
    </tbody>
</table>
<br />
</blockquote>
<p><span class="boldbodycopy">使用EJB</span></p>
<p>客户端是访问Bean的应用程序。虽然没有必要保存在客户层，但是能够作为一个独立的应用，JSP，<br />
Servlet，或者另一个EJB。客户端通过Bean的远程或者本地接口访问EJB中的方法，主要取决于客户端和Bean<br />
运行在同一个还是不同的JVM中。这些接口定义了Bean中的方法，而由Bean类实际实现这些方法。当一个<br />
客户端访问该Bean类中的一个方法时，容器生成Bean的一个代理，被叫做远程对象或者本地对象。远程或者<br />
本地对象接收请求，委派它到相应的Bean实例，返回结果给客户端。调用一个Bean中的方法，客户端使用定<br />
义在EJB不是描述文件的名字查找到Bean。在以下实例中，客户端使用上下文对象找到命名为"StateLessejb"<br />
Bean。</p>
<p>EJB 客户端实例</p>
<blockquote>
<table border="1" width="100%">
    <tbody>
        <tr>
            <td>
            <p><code>import javax.naming.Context;<br />
            import javax.naming.InitialContext;</code></p>
            <p><code>/**<br />
            * 一个调用无状态会话Bean中方法的简单的Bean客户端<br />
            */</code></p>
            <p><code>public class CalculateejbClient<br />
            {<br />
            public static void main(String [] args)<br />
            {<br />
            Context context = new InitialContext();</code><br />
            <code>CalculateEJB myejb =<br />
            (CalculateEJB)context.lookup("java:comp/env/ejb/CalculateEJB");<br />
            myejb.incrementValue();<br />
            }<br />
            }</code></p>
            </td>
        </tr>
    </tbody>
</table>
<br />
</blockquote>
<p><span class="boldbodycopy">总结</span></p>
<p>EJB3.0开发企业JavaBean是相当容易的。此规范使用元数据注释定义Bean的类型和暴露给客户端的方法。<br />
因此，无论你将创建一个执行特定任务的会话Bean还是映射一个表到实体Bean来更新数据，你都能象使用普<br />
通Java对象和接口一样进行处理，在业务方法中使用元注释向客户端暴露方法。既然你已经理解了EJB的基础,<br />
可以到OTN中<a href="http://www.oracle.com/technology/tech/java/ejb30.html">EJB 3.0 Resources Page</a>发现更多信息。</p><img src ="http://www.blogjava.net/mlh123caoer/aggbug/142067.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-09-02 14:22 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/09/02/142067.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>eclipse中优秀的插件 </title><link>http://www.blogjava.net/mlh123caoer/archive/2007/08/25/139316.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Sat, 25 Aug 2007 13:14:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/08/25/139316.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/139316.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/08/25/139316.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/139316.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/139316.html</trackback:ping><description><![CDATA[<br>1 EMF,GEF - Graphical Editor Framework,UML2,VE - Visual Editor都在这里下载<br><a href="http://www.eclipse.org/downloads/index.php"><font color=#000000><u>http://www.eclipse.org/downloads/index.php</u></font></a>
<p>2&nbsp; lomboz J2EE插件,开发JSP,EJB<br><a href="http://forge.objectweb.org/projects/lomboz"><font color=#000000><u>http://forge.objectweb.org/projects/lomboz</u></font></a><br></p>
<p>3&nbsp; MyEclipse J2EE开发插件，支持SERVLET/JSP/EJB/数据库操纵等 <br><a href="http://www.myeclipseide.com/"><font color=#000000><u>http://www.myeclipseide.com</u></font></a></p>
<p>4&nbsp; Properties Editor&nbsp; 编辑java的属性文件，并可以自动存盘为Unicode格式 <br><a href="http://propedit.sourceforge.jp/index_en.html"><font color=#000000><u>http://propedit.sourceforge.jp/index_en.html</u></font></a></p>
<p>5&nbsp; Colorer Take&nbsp; 为上百种类型的文件按语法着色 <br><a href="http://colorer.sourceforge.net/"><font color=#000000><u>http://colorer.sourceforge.net/</u></font></a></p>
<p>6&nbsp; XMLBuddy 编辑xml文件<br><a href="http://www.xmlbuddy.com/"><font color=#000000><u>http://www.xmlbuddy.com</u></font></a></p>
<p>7&nbsp; Code Folding&nbsp; 加入多种代码折叠功能（比eclipse自带的更多） <br><a href="http://www.coffee-bytes.com/servlet/PlatformSupport"><font color=#000000><u>http://www.coffee-bytes.com/servlet/PlatformSupport</u></font></a></p>
<p>8&nbsp; Easy Explorer&nbsp; 从eclipse中访问选定文件、目录所在的文件夹 <br><a href="http://easystruts.sourceforge.net/"><font color=#000000><u>http://easystruts.sourceforge.net/</u></font></a></p>
<p>9&nbsp; Fat Jar 打包插件，可以方便的完成各种打包任务，可以包含外部的包等 <br><a href="http://fjep.sourceforge.net/"><font color=#000000><u>http://fjep.sourceforge.net/</u></font></a></p>
<p>10&nbsp; RegEx Test 测试正则表达式 <br><a href="http://brosinski.com/stephan/archives/000028.php"><font color=#000000><u>http://brosinski.com/stephan/archives/000028.php</u></font></a></p>
<p>11&nbsp; JasperAssistant 报表插件(要钱的哦～)<br><a href="http://www.jasperassistant.com/"><font color=#000000><u>http://www.jasperassistant.com/</u></font></a></p>
<p>12&nbsp; Jigloo GUI Builder JAVA的GUI编辑插件 <br><a href="http://cloudgarden.com/jigloo/"><font color=#000000><u>http://cloudgarden.com/jigloo/</u></font></a></p>
<p>13&nbsp; Profiler 性能跟踪、测量工具，能跟踪、测量B/S程序 <br><a href="http://sourceforge.net/projects/eclipsecolorer/"><font color=#000000><u>http://sourceforge.net/projects/eclipsecolorer/</u></font></a></p>
<p>14&nbsp; AdvanQas 提供对if/else等条件语句的提示和快捷帮助(自动更改结构等)<br><a href="http://eclipsecolorer.sourceforge.net/advanqas/index.html"><font color=#000000><u>http://eclipsecolorer.sourceforge.net/advanqas/index.html</u></font></a></p>
<p>15&nbsp; Log4E Log4j插件，提供各种和Log4j相关的任务，如为方法、类添加一个logger等 <br><a href="http://log4e.jayefem.de/index.php/Main_Page"><font color=#000000><u>http://log4e.jayefem.de/index.php/Main_Page</u></font></a></p>
<p>16&nbsp; VSSPlugin VSS插件 <br><a href="http://sourceforge.net/projects/vssplugin"><font color=#000000><u>http://sourceforge.net/projects/vssplugin</u></font></a></p>
<p>17&nbsp; Implementors 提供跳转到一个方法的实现类，而不是接口的功能（实用!） <br><a href="http://eclipse-tools.sourceforge.net/implementors/"><font color=#000000><u>http://eclipse-tools.sourceforge.net/implementors/</u></font></a> </p>
<p>18&nbsp; Call Hierarchy 显示一个方法的调用层次（被哪些方法调，调了哪些方法） <br><a href="http://eclipse-tools.sourceforge.net/call-hierarchy/index.html"><font color=#000000><u>http://eclipse-tools.sourceforge.net/call-hierarchy/index.html</u></font></a> </p>
<p>19&nbsp; EclipseTidy 检查和格式化HTML/XML文件 <br><a href="http://eclipsetidy.sourceforge.net/"><font color=#000000><u>http://eclipsetidy.sourceforge.net/</u></font></a></p>
<p>20&nbsp; Checkclipse 检查代码的风格、写法是否符合规范 <br><a href="http://www.mvmsoft.de/content/plugins/checkclipse/checkclipse.htm"><font color=#000000><u>http://www.mvmsoft.de/content/plugins/checkclipse/checkclipse.htm</u></font></a></p>
<p>21&nbsp; Hibernate Synchronizer Hibernate插件，自动映射等 <br><a href="http://www.binamics.com/hibernatesync/"><font color=#000000><u>http://www.binamics.com/hibernatesync/</u></font></a> </p>
<p>22&nbsp; VeloEclipse&nbsp; Velocity插件 <br><a href="http://propsorter.sourceforge.net/"><font color=#000000><u>http://propsorter.sourceforge.net/</u></font></a>&nbsp;<br>&nbsp; <br>23&nbsp; EditorList 方便的列出所有打开的Editor <br><a href="http://editorlist.sourceforge.net/"><font color=#000000><u>http://editorlist.sourceforge.net/</u></font></a>&nbsp;<br>&nbsp; <br>24&nbsp; MemoryManager 内存占用率的监视 <br><a href="http://cloudgarden.com/memorymanager/"><font color=#000000><u>http://cloudgarden.com/memorymanager/</u></font></a>&nbsp;<br>&nbsp;<br>25&nbsp; swt-designer java的GUI插件<br><a href="http://www.swt-designer.com/"><font color=#000000><u>http://www.swt-designer.com/</u></font></a><br>&nbsp;<br>26&nbsp; TomcatPlugin 支持Tomcat插件 <br><a href="http://www.sysdeo.com/eclipse/tomcatPlugin.html"><font color=#000000><u>http://www.sysdeo.com/eclipse/tomcatPlugin.html</u></font></a><br>&nbsp;<br>27&nbsp; XML Viewer <br><a href="http://tabaquismo.freehosting.net/ignacio/eclipse/xmlview/index.html"><font color=#000000><u>http://tabaquismo.freehosting.net/ignacio/eclipse/xmlview/index.html</u></font></a><br>&nbsp;<br>28&nbsp; quantum 数据库插件<br><a href="http://quantum.sourceforge.net/"><font color=#000000><u>http://quantum.sourceforge.net/</u></font></a><br>&nbsp;<br>29&nbsp; Dbedit 数据库插件<br><a href="http://sourceforge.net/projects/dbedit"><font color=#000000><u>http://sourceforge.net/projects/dbedit</u></font></a><br>&nbsp;<br>30&nbsp; clay.core 可视化的数据库插件 <br><a href="http://www.azzurri.jp/en/software/index.jsp"><font color=#000000><u>http://www.azzurri.jp/en/software/index.jsp</u></font></a> <br><a href="http://www.azzurri.jp/eclipse/plugins"><font color=#000000><u>http://www.azzurri.jp/eclipse/plugins</u></font></a><br>&nbsp;<br>31&nbsp; hiberclipse hibernate插件 <br><a href="http://hiberclipse.sourceforge.net/"><font color=#000000><u>http://hiberclipse.sourceforge.net</u></font></a><br><a href="http://www.binamics.com/hibernatesync"><font color=#000000><u>http://www.binamics.com/hibernatesync</u></font></a><br>&nbsp;<br>32&nbsp; struts-console Struts插件<br><a href="http://www.jamesholmes.com/struts/console/"><font color=#000000><u>http://www.jamesholmes.com/struts/console/</u></font></a><br>&nbsp;<br>33&nbsp; easystruts Struts插件<br><a href="http://easystruts.sourceforge.net/"><font color=#000000><u>http://easystruts.sourceforge.net</u></font></a>&nbsp;<br>&nbsp;<br>34&nbsp; veloedit Velocity插件<br><a href="http://veloedit.sourceforge.net/"><font color=#000000><u>http://veloedit.sourceforge.net/</u></font></a><br>&nbsp;<br>35&nbsp; jalopy 代码整理插件<br><a href="http://jalopy.sourceforge.net/"><font color=#000000><u>http://jalopy.sourceforge.net/</u></font></a><br>&nbsp;<br>36&nbsp; JDepend 包关系分析<br><a href="http://andrei.gmxhome.de/jdepend4eclipse/links.html"><font color=#000000><u>http://andrei.gmxhome.de/jdepend4eclipse/links.html</u></font></a><br>&nbsp;<br>37&nbsp; Spring IDE Spring插件<br><a href="http://springide-eclip.sourceforge.net/updatesite/"><font color=#000000><u>http://springide-eclip.sourceforge.net/updatesite/</u></font></a><br>&nbsp;<br>38&nbsp; doclipse 可以产生xdoclet 的代码提示<br><a href="http://beust.com/doclipse/"><font color=#000000><u>http://beust.com/doclipse/</u></font></a></p>
<p>39&nbsp; SQLExplorer,在Eclipse 中连接各种数据库进行操作使用<br><a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=124&amp;threadID=31124" target=_blank><font color=#000000><u>http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=124&amp;threadID=31124</u></font></a></p>
<p><font size=2>40&nbsp; JSEclipse<br></font></p>
<div>插件主页：<a href="http://www.interaktonline.com/Products/Eclipse/JSEclipse/Overview/"><font color=#000000><u>http://www.interaktonline.com/Products/Eclipse/JSEclipse/Overview/</u></font></a></div>
<div>插件介绍：JSEclipse是个Eclipse下的免费Javascript脚本编辑器<br>41&nbsp; subversion<br>版本控制，相当于CVS<br>安装：<a href="http://subclipse.tigris.org/install.html"><font color=#000000><u>http://subclipse.tigris.org/install.html</u></font></a><br><font size=2>Name: Subclipse<br>URL:&nbsp; http://subclipse.tigris.org/update_1.0.x<br><br><br></font>42&nbsp;&nbsp; CSS Editor for Eclipse<br><a href="http://csseditor.sourceforge.net/"><font color=#000000><u>http://csseditor.sourceforge.net/</u></font></a><br><br>43&nbsp;&nbsp; FacesIDE<br>FacesIDE是一个用于开发JSF的Eclispe插件.它可以可视化编辑faces-config.xml文件并且提供代码编辑与校验,预览JSF的JSP文件.FacesIDE包含MyFaces来作为JSF的实现<br><a href="http://amateras.sourceforge.jp/cgi-bin/fswiki_en/wiki.cgi?page=FacesIDE"><font color=#000000 size=2><u>http://amateras.sourceforge.jp/cgi-bin/fswiki_en/wiki.cgi?page=FacesIDE</u></font></a><br><br><span><font size=2>44&nbsp;&nbsp;&nbsp; <strong>Eclipse SQLExplorer plugin</strong><br>一个数据库管理插件<br></font></span><a href="http://sourceforge.net/projects/eclipsesql"><font color=#000000 size=2><u>http://sourceforge.net/projects/eclipsesql</u></font></a><br><br><font size=2>45&nbsp;&nbsp;<strong> Poperties Editor</strong><br>一个在编辑完成后可以将资源文件中的中文编码格式转换为unicode编码的插件，在开发国际化应用程序的时候非常有用<br></font><a href="http://propedit.sourceforge.jp/eclipse/updates/"><font color=#000000 size=2><u>http://propedit.sourceforge.jp/eclipse/updates/</u></font></a></div>
<p><font size=2>46&nbsp; <strong>eclipseME</strong><br>&nbsp; </font><a href="http://eclipseme.org/updates/"><font color=#000000><u><font size=2>http://eclipseme.org/updates/</font> </u></font></a><br></p>
<p><font size=2>47&nbsp;&nbsp; <strong>Eclipse加速插件KeepResident</strong></font> <a href="http://suif.stanford.edu/pub/keepresident/"><br><font color=#000000><u><font size=2>http://suif.stanford.edu/pub/keepresident/</font> </u></font></a><br><font size=2>&nbsp;<br>48&nbsp;&nbsp;<strong> MyEclipse&nbsp; J2EE开发插件，支持SERVLET/JSP/EJB/数据库操纵等<br></strong></font><a href="http://www.myeclipseide.com/"><font color=#000000><u><font size=2>www.myeclipseide.com</font> </u></font></a><br><font size=2>&nbsp;<br>49&nbsp;<strong>&nbsp; Properties Editor&nbsp; 编辑java的属性文件，并可以自动存盘为Unicode格式</strong><br></font><a href="http://propedit.sourceforge.jp/index_en.html"><font color=#000000><u><font size=2>http://propedit.sourceforge.jp/index_en.html</font> </u></font></a><br><a href="http://propedit.sourceforge.jp/eclipse/updates/"><font color=#000000><u><font size=2>http://propedit.sourceforge.jp/eclipse/updates/</font> </u></font></a><br><font size=2>&nbsp;<br><strong>50 Colorer Take&nbsp; 为上百种类型的文件按语法着色</strong><br></font><a href="http://colorer.sourceforge.net/"><font color=#000000><u><font size=2>http://colorer.sourceforge.net/</font> </u></font></a><br><font size=2>&nbsp;<br><strong>51 XMLBuddy 编辑xml文件</strong><br></font><a href="http://www.xmlbuddy.com/"><font color=#000000><u><font size=2>www.xmlbuddy.com</font> </u></font></a><br><font size=2>&nbsp;<br>52&nbsp;<strong>&nbsp; Code Folding&nbsp; 加入多种代码折叠功能（比eclipse自带的更多）</strong><br></font><a href="http://www.coffee-bytes.com/servlet/PlatformSupport"><font color=#000000><u><font size=2>http://www.coffee-bytes.com/servlet/PlatformSupport</font> </u></font></a><br><font size=2>&nbsp;<br>53 <strong>Easy Explorer&nbsp; 从eclipse中访问选定文件、目录所在的文件夹</strong><br></font><a href="http://easystruts.sourceforge.net/"><font color=#000000><u><font size=2>http://easystruts.sourceforge.net/</font> </u></font></a><br><font size=2>&nbsp;<br><strong>54&nbsp; Fat Jar 打包插件，可以方便的完成各种打包任务，可以包含外部的包等</strong><br></font><a href="http://fjep.sourceforge.net/"><font color=#000000><u><font size=2>http://fjep.sourceforge.net/</font> </u></font></a><br><font size=2>&nbsp;<br>55 <strong>RegEx Test 测试正则表达式</strong><br></font><a href="http://brosinski.com/stephan/archives/000028.php"><font color=#000000><u><font size=2>http://brosinski.com/stephan/archives/000028.php</font> </u></font></a><br><font size=2>&nbsp;<br>56<strong>&nbsp; JasperAssistant 报表插件（强，要钱的）</strong><br></font><a href="http://www.jasperassistant.com/"><font color=#000000><u><font size=2>http://www.jasperassistant.com/</font> </u></font></a><br><font size=2>&nbsp;<br>57&nbsp;<strong>&nbsp; Jigloo GUI Builder ＪＡＶＡ的ＧＵＩ编辑插件</strong><br></font><a href="http://cloudgarden.com/jigloo/"><font color=#000000><u><font size=2>http://cloudgarden.com/jigloo/</font> </u></font></a><br><font size=2>&nbsp;<br>58&nbsp;&nbsp; <strong>Profiler 性能跟踪、测量工具，能跟踪、测量ＢＳ程序</strong><br></font><a href="http://sourceforge.net/projects/eclipsecolorer/"><font color=#000000><u><font size=2>http://sourceforge.net/projects/eclipsecolorer/</font> </u></font></a><br><font size=2>&nbsp;<br>59&nbsp; <strong>AdvanQas 提供对if/else等条件语句的提示和快捷帮助（自动更改结构等）</strong><br></font><a href="http://eclipsecolorer.sourceforge.net/advanqas/index.html"><font color=#000000><u><font size=2>http://eclipsecolorer.sourceforge.net/advanqas/index.html</font> </u></font></a><br><font size=2>&nbsp;<br>60&nbsp; Log4E&nbsp;&nbsp;&nbsp;&nbsp; Log4j插件，提供各种和Log4j相关的任务，如为方法、类添加一个logger等<br></font><a href="http://log4e.jayefem.de/index.php/Main_Page"><font color=#000000><u><font size=2>http://log4e.jayefem.de/index.php/Main_Page</font>&nbsp;</u></font></a><br><font size=2>&nbsp;</font><font size=2><br>61 Implementors&nbsp;&nbsp; 提供跳转到一个方法的实现类，而不是接中的功能（实用!）<br></font><a href="http://eclipse-tools.sourceforge.net/implementors/"><font color=#000000><u><font size=2>http://eclipse-tools.sourceforge.net/implementors/</font> </u></font></a><br><font size=2>&nbsp;<br>62&nbsp; Call Hierarchy 显示一个方法的调用层次（被哪些方法调，调了哪些方法）<br></font><a href="http://eclipse-tools.sourceforge.net/call-hierarchy/index.html"><font color=#000000><u><font size=2>http://eclipse-tools.sourceforge.net/call-hierarchy/index.html</font> </u></font></a><br><font size=2>&nbsp;<br>63EclipseTidy 检查和格式化HTML/XML文件<br></font><a href="http://eclipsetidy.sourceforge.net/"><font color=#000000><u><font size=2>http://eclipsetidy.sourceforge.net/</font> </u></font></a><br><font size=2>&nbsp;<br>64 Checkclipse 检查代码的风格、写法是否符合规范<br></font><a href="http://www.mvmsoft.de/content/plugins/checkclipse/checkclipse.htm"><font color=#000000><u><font size=2>http://www.mvmsoft.de/content/plugins/checkclipse/checkclipse.htm</font> </u></font></a><br><font size=2>&nbsp;<br>64&nbsp; Hibernate Synchronizer Hibernate插件，自动映射等<br></font><a href="http://www.binamics.com/hibernatesync/"><font color=#000000><u><font size=2>http://www.binamics.com/hibernatesync/</font> </u></font></a><br><font size=2>&nbsp;<br>65&nbsp; spring updatesite 插件<br></font><a href="http://springide.org/updatesite/"><font color=#000000><u><font size=2>http://springide.org/updatesite/</font> </u></font></a></p>
<p><font size=2>66 VeloEclipse&nbsp; Velocity插件<br></font><a href="http://propsorter.sourceforge.net/"><font color=#000000><u><font size=2>http://propsorter.sourceforge.net/</font> </u></font></a><br><font size=2>&nbsp;<br>67&nbsp; EditorList&nbsp;&nbsp; 方便的列出所有打开的Editor<br></font><a href="http://editorlist.sourceforge.net/"><font color=#000000><u><font size=2>http://editorlist.sourceforge.net/</font> </u></font></a><br><font size=2>&nbsp;<br>68&nbsp; MemoryManager 内存占用率的监视<br></font><a href="http://cloudgarden.com/memorymanager/"><font color=#000000><u><font size=2>http://cloudgarden.com/memorymanager/</font> </u></font></a></p>
<p><font size=2>69 Eclipse的游戏插件<br></font><a href="http://eclipse-games.sourceforge.net/"><font color=#000000><u><font size=2>http://eclipse-games.sourceforge.net/</font> </u></font></a></p>
<p><font size=2>70&nbsp; JBoss-IDE<br></font><a href="http://jboss.sourceforge.net/jbosside/updates/"><font color=#000000><u><font size=2>http://jboss.sourceforge.net/jbosside/updates/</font> </u></font></a></p>
<p><font size=2>71自动反编译class，安装后要设定class文件缺省关联到jode<br></font><a href="http://www.technoetic.com/eclipse/update"><font color=#000000><u><font size=2>http://www.technoetic.com/eclipse/update</font> </u></font></a></p>
<p><br><font size=2>72&nbsp; jigloo swing/sw设计工具，里面自带的form/anchor布局很好用！<br></font><a href="http://cloudgarden.soft-gems.net/update-site/"><font color=#000000><u><font size=2>http://cloudgarden.soft-gems.net/update-site/</font> </u></font></a></p>
<p><font size=2>73&nbsp; jinto的资源文件编辑工具，同时编辑多种语言，而且自动转换成iso8859-1编码。很好用！<br></font><a href="http://www.guh-software.de/eclipse/"><font color=#000000><font size=2><u>http://www.guh-software.de/eclipse/</u></font></font></a><a href="http://www.guh-software.de/eclipse/"><font color=#000000><u> </u></font></a></p>
&nbsp;<br><img src ="http://www.blogjava.net/mlh123caoer/aggbug/139316.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-08-25 21:14 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/08/25/139316.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>XMLBeans 2.0</title><link>http://www.blogjava.net/mlh123caoer/archive/2007/08/21/138303.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Tue, 21 Aug 2007 03:06:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/08/21/138303.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/138303.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/08/21/138303.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/138303.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/138303.html</trackback:ping><description><![CDATA[Apache XMLBeans是一个非常有价值的工具，它提供一种在Java中使用XML的简便方法。在本文中，我们将介绍XMLBeans以及XMLBeans 2.0中的一些有用特性。
<h3>XMLBeans简介</h3>
<p>　　W3C XML Schema是一个XML文档，该文档定义一组其他XML文档必须遵守才合法的规则。与早期XML模式语言如文档类型定义（document type definition，DTD）或简单对象XML（simple object XML，SOX）相比，W3C XML Schema具有许多优点，它还提供了可供用户以多种方式使用的丰富特性集。</p>
<p>　　XMLBeans是完全与模式兼容的XML-Java绑定工具，使用这个工具可以以对Java友好的方式访问XML的全部特性。XMLBean解决方案是独一无二的，因为它提供XML数据的双重视图。XMLBeans维护一个信息和结构均未更改的原始XML文档，并提供一个基于Java的XML数据视图。</p>
<p>　　现在我们通过显示一些代码示例来演示XMLBeans 2.0中的一些特性。在每个示例中，我们都会提供模式以及一些操纵模式的XMLBean表示的Java代码。模式和Java示例都可供下载。</p>
<p>　　下面我们来看下面的模式片断：</p>
<p>　　&nbsp;</p>
<pre class=code>　　1 &lt;xs:element name="order"&gt;
2   &lt;xs:complexType&gt;
3     &lt;xs:sequence&gt;
4       &lt;xs:element name="orderNo" type="xs:string"/&gt;
5       &lt;xs:element name="item" nillable="true"
6          maxOccurs="unbounded" type="tns:itemType"/&gt;
7       &lt;xs:element name="address" type="tns:addressType"/&gt;
8       &lt;xs:element name="quantity" type="tns:quantityType"/&gt;
10     &lt;/xs:sequence&gt;
11   &lt;/xs:complexType&gt;
12 &lt;/xs:element&gt;</pre>
<p>　　要生成XMLBeans类，需要对模式进行编译。使用scomp实用工具可以很轻松地完成这个任务，因为它可以为所有简单和复杂的类型生成接口。所有类和接口的包名均派生自模式中指定的targetNamespace值。详细情况请阅读Hetal Shah的<a href="http://dev2dev.bea.com.cn/techdoc/2005031005.html"><u><font color=#0000ff>Configuring XMLBeans</font></u></a>（中文版，Dev2Dev，2005年3月）。</p>
<p>　　现在我们看看如何生成实例文档，如何针对模式检查文档的有效性，以及如何将实例保存到文件系统。</p>
<p>　　下面所生成的OrderDocument接口是一个XMLBeans为任意全局元素或类型创建的特殊&#8220;文档&#8221;类型示例。</p>
<p>　　AddressType和ItemType是为全局复杂类型addressType和sizeType创建的接口：</p>
<p>　　&nbsp;</p>
<pre class=code>　　 1 OrderDocument orderDoc = OrderDocument.Factory.newInstance();
2 Order order = orderDoc.addNewOrder();
3 order.setOrderNo("ORD1234");
4 order.setQuantity(4);
5
6 AddressType aType = order.addNewAddress();
7 aType.setCity("Kirkland");
8
9 ItemType iType = order.addNewItem();
10 iType.setId("ITEM003");
11
12 boolean isValid = orderDoc.validate(xopt);
13
14 orderDoc.save(new File("sample.xml"),xopt);
</pre>
<p>　　运行此示例会导致构建一个实例文档，该文档将被验证并以&#8220;sample. xml&#8221;为名保存在本地文件系统中。该程序还会将此实例文档的内容以及验证测试的结果显示到命令提示符或Unix shell中：</p>
<p>　　&nbsp;</p>
<pre class=code>　　 1 &lt;sam:order xmlns:sam="http://temp.openuri.org/Sample"&gt;
2   &lt;sam:orderNo&gt;ORD1234&lt;/sam:orderNo&gt;
3   &lt;sam:item&gt;
4     &lt;sam:id&gt;ITEM003&lt;/sam:id&gt;
5     &lt;sam:description&gt;Latest Item&lt;/sam:description&gt;
6     &lt;sam:size&gt;Large&lt;/sam:size&gt;
7   &lt;/sam:item&gt;
8   &lt;sam:address&gt;
9     &lt;sam:Name&gt;BEA Systems, Inc&lt;/sam:Name&gt;
10     &lt;sam:Street&gt;10230 NE Points Drive, Ste 300&lt;/sam:Street&gt;
11     &lt;sam:City&gt;Kirkland&lt;/sam:City&gt;
12     &lt;sam:Zip&gt;98033&lt;/sam:Zip&gt;
13     &lt;sam:State&gt;WA&lt;/sam:State&gt;
14     &lt;sam:Country&gt;USA&lt;/sam:Country&gt;
15   &lt;/sam:address&gt;
16   &lt;sam:quantity&gt;4&lt;/sam:quantity&gt;
17 &lt;/sam:order&gt;</pre>
<p>　　这是一个有效的实例文档。在编译一个模式时，从模式生成的API会与表示底层XML模式的XMLBeans类型系统相集成。对模型相关信息的访问权限可通过使用模式类型系统API获取。</p>
<p>　　在下一个示例中，我们将展示如何使用getEnumerationValues()方法编程式地访问特定模式类型的多个枚举值。我们使用的模式类型是sizeType，它是带有三个可能值的枚举类型。该模式片断如下所示：</p>
<p>　　&nbsp;</p>
<pre class=code>　　 1 &lt;xs:simpleType name="sizeType"&gt;
2   &lt;xs:restriction base="xs:token"&gt;
3     &lt;xs:enumeration value="Small"/&gt;
4     &lt;xs:enumeration value="Medium"/&gt;
5     &lt;xs:enumeration value="Large"/&gt;
6   &lt;/xs:restriction&gt;
7 &lt;/xs:simpleType&gt;</pre>
<p>　　SizeType是SchemaType类，它包含关于simpleType模式类型的信息：</p>
<pre class=code>　　SchemaType schType = null;
XmlAnySimpleType [] xmlarray = null;
SizeType sType = SizeType.Factory.newInstance();
schType = sType.schemaType();
xmlarray = schType.getEnumerationValues();
</pre>
<p>　　运行此代码示例（EnumerationSample.java）将导致编程式地获取枚举值并将其重定向到System.out：</p>
<pre class=code>　　Enumeration values for ItemType :
Small
Medium
Large
</pre>
<p>　　XmlCursor是XMLBeans中的一个有趣特性；它们提供一种操作或导航XML实例文档的直观方法。XmlCursor还提供了一种执行XQuery表达式的方法。一旦加载了XML文档，就可以创建一个游标来表示XML中的特定位置。因为用户可以使用具有或不具有对应于XML的模式的游标，因此游标是处理XML的理想方法。</p>
<p>　　下一个示例演示如何使用游标操作XMLBean实例。此示例分析在第一个示例中创建的sample.xml。一旦将该文件保存到内存中，就会使用XmlCursor API导航到quantity元素并将值更改为104：</p>
<pre class=code>　　orderDoc = OrderDocument.Factory.parse(new File("sample.xml"));
XmlCursor xcursor = orderDoc.newCursor();
xcursor.toFirstChild();
xcursor.toChild(3);
xcursor.toEndToken();
xcursor.toPrevChar(1);
xcursor.insertChars("10");
xcursor.disp ose();
</pre>
<p>　　运行此示例会生成下面的输出，它显示修改后的XMLBean文档为什么会无效：</p>
<pre class=code>　　Message: decimal
value (104) is greater than maxInclusive facet (5) for
quantityType in namespace http://temp.openuri.org/Sample
Location of invalid XML:
&lt;xml-fragment xmlns:sam="http://temp.openuri.org/Sample"/&gt;</pre>
<p>　　到目前为止，我们已经简要介绍了XMLBeans，现在介绍一下2.0版本中的新特性。</p>
<h3>XMLBeans 2.0中的新特性</h3>
<p>　　通常，通过观察产品的实际运行来了解其中的新特性是比较简便的方法。我们将通过介绍一个利用了XMLBeans的某些重要特性的项目来介绍这些新特性。众所周知，XMLBeans是一个Apache项目，所以它使用Atlassian的Jira问题跟踪和项目管理应用程序来跟踪bug、特性和其他问题。BEA对XMLBeans项目进行了投资，并拥有一个提供高质量软件的标准。这意味着BEA很关注XMLBeans之类项目的质量。由于XMLBeans是开源项目，并且它使用Apache的常见工具如Jira，所以问题就在于BEA如何跟踪XMLBeans的质量指标。</p>
<p>　　用于揭示XMLBeans 2.0中的一些新特性的计划就是对这个问题的回答：如何方便地从Jira收集质量指标？</p>
<p>　　下面的屏幕快照显示了XMLBeans的项目主页面。请看图片的右边，在Project Summary区域下可以看到一些与我们关心的质量指标问题相关的选项。</p>
<p align=center><a href="http://dev2dev.bea.com/images/2006/05/JiraProjectPage.png" target=_blank><img height=300 alt="图1：XMLBeans Jira项目页面" src="http://dev2dev.bea.com.cn/images/image060713002.gif" width=449 vspace=4 border=0></a><br>图1：XMLBeans Jira项目页面（单击图像查看大图）</p>
<p>　　Jira的一个好处就是它能提供问题数据的不同视图。在下图中，请看名为<strong>Current View</strong>的标题。在屏幕快照中，目前选择的是Browser视图，但还有其他选项，包括一个打印视图、一个XML视图，甚至还有一个Excel电子表格视图：</p>
<p align=center><a href="http://dev2dev.bea.com/images/2006/05/JiraIssueNav.png" target=_blank><img height=245 alt="图2：XMLBeans Jira Issue Navigator" src="http://dev2dev.bea.com.cn/images/image060713004.gif" width=449 vspace=4 border=0></a><br>图2：XMLBeans Jira Issue Navigator（单击图像查看大图）</p>
<p>　　熟悉Jira以及XMLBeans跟踪质量指标的方式后，我们可以通过多种方式收集质量指标。我们的选项包括屏幕抓取HTML、分析电子表格以及从URL获取XML。我们认为最合理的是从URL（通过从Issue Navigator页面单击XML链接而提供）使用XML视图。该URL的内容看起来与下面的XML文档类似：</p>
<pre class=code>　　&lt;?xml version="1.0" encoding="utf-8" ?&gt;
&lt;!--  RSS generated by JIRA 98 at Sun Dec 04 18:08:34 CET 2005
--&gt;
&lt;rss version="0.92"&gt;
&lt;channel&gt;
&lt;title&gt;ASF JIRA&lt;/title&gt;
&lt;link&gt;http://issues.apache.org/jira&lt;/link&gt;
&lt;description&gt;This file is an XML representation of some
issues&lt;/description&gt;
&lt;language&gt;en&lt;/language&gt;
&lt;item&gt;
&lt;title&gt;[XMLBEANS-232] Fast Xml Infoset&lt;/title&gt;
&lt;link&gt;http://issues.apache.org/jira/browse/x&lt;/link&gt;
&lt;description&gt;
&lt;!-- left out for brevity --&gt;
&lt;/description&gt;
&lt;environment&gt;&lt;![CDATA[]]&gt;&lt;/environment&gt;
&lt;key id="12326193"&gt;XMLBEANS-232&lt;/key&gt;
&lt;summary&gt;Fast Xml Infoset&lt;/summary&gt;
&lt;type id="4"&gt;Improvement&lt;/type&gt;
&lt;priority id="3"&gt;Major&lt;/priority&gt;
&lt;status id="1"&gt;Open&lt;/status&gt;
&lt;resolution&gt;Unresolved&lt;/resolution&gt;
&lt;assignee&gt;Unassigned&lt;/assignee&gt;
&lt;reporter username="rrusin"&gt;Rafal
Rusin&lt;/reporter&gt;
&lt;created&gt;Wed, 30 Nov 2005 13:29:44 +0100
(CET)&lt;/created&gt;
&lt;updated&gt;Sat, 3 Dec 2005 18:15:10 +0100
(CET)&lt;/updated&gt;
&lt;version&gt;unspecified&lt;/version&gt;
&lt;fixVersion&gt;unspecified&lt;/fixVersion&gt;
&lt;component&gt;XmlObject&lt;/component&gt;
&lt;due&gt;&lt;/due&gt;
&lt;votes&gt;0&lt;/votes&gt;
&lt;comments&gt;
&lt;comment author="dandiep" created="Sat, 3 Dec 2005
18:15:10 +0100 (CET)" level=""&gt;
&lt;!-- ... --&gt;
&lt;/comment&gt;
&lt;/comments&gt;
&lt;customfields&gt;
&lt;/customfields&gt;
&lt;/item&gt;
&lt;item&gt;
&lt;!-- left out for brevity --&gt;
&lt;/item&gt;
&lt;/channel&gt;
&lt;/rss&gt;</pre>
<p>　　如果从上面的XML feed查看片断，会发现它被定义为RSS feed。我们的第一步是找到一个RSS 0.92版本的XML Schema模式，这样就可以编译模式，并通过使用XMLBeans的类似于JavaBean的简单API来使用XMLBeans分析URL。我们无法找到官方模式，但可以找到规范，并可由此开始创建模式。随后，我们发现根据规范创建的模式与从Jira获取的RSS feed不匹配。我们该怎么做呢？我们实际上惟一可以选择的就是为此RSS feed创建一个模式，但这费时且容易出错。进行了进一步的调查后，我们偶然发现了新增的inst2xsd特性。</p>
<h3>模式到实例再到模式的过程</h3>
<p>　　 inst2xsd工具可作为命令行实用工具使用，但用户也可以编程式地使用API。其目的是采用一个XML实例并创建一个合法模式集。该工具也是可配置的，它提供了用于指定使用哪种设计模式的选项（包括Russian Doll、Salami Slice、Venetian Blind；详细信息请参见<a href="http://www.xfront.com/GlobalVersusLocal.html" target=_blank><u><font color=#0000ff>模式设计指导原则</font></u></a>）。</p>
<p>　　该工具还能够将枚举映射到重复值，并能够根据数据类型的最小公分母创建类型。</p>
<p>　　我们使用lcd:val这个值作为创建最小公分母类型的示例。该文本可由多个内置XML Schema数据类型表示，例如字符串派生的类型（xsd:string、xsd:normalizedString、xsd:token，等等）以及QName类型。在本例中，inst2xsd特性确定类型的方式是查找前缀为lcd的命名空间声明。如果找到该前缀，该类型将是QName，而不是某个可能基于字符串的类型。</p>
<p>　　现在看一下我们从Jira接收的RSS feed的结果是什么。如果我们已经将feed保存到名为jiraRssFeed.xml的实例中并已将XMLBEANS_HOME\bin放在我们的路径中，工作流将如下：</p>
<pre class=code>　　/home/user&gt;inst2xsd
Generates XMLSchema from instance xml documents.
Usage: inst2xsd [opts] [instance.xml]*
Options include:
-design [rd|ss|vb] - XMLSchema design type
rd  - Russian Doll Design - local elements and local types
ss  - Salami Slice Design - global elements and local
types
vb  - Venetian Blind Design (default) - local elements and
global complex types
-simple-content-types [smart|string] - Simple content types
detection (leaf text). Smart is the default
-enumerations [never|NUMBER] - Use enumerations. Default
value is 10.
-outDir [dir] - Directory for output files. Default is '.'
-outPrefix [file_name_prefix] - Prefix for output file names.
Default is 'schema'
-validate - Validates input instances against generated
schemas.
-verbose - print more informational messages
-license - print license information
-help - help information
/home/user&gt;inst2xsd jiraRssFeed.xml -enumerations never
-design rd -verbose -validate
# this generates a schema named schema0.xsd
</pre>
<p>　　这将生成名为schema0.xsd的（可配置）文件，并且模式将与下面的片断类似：</p>
<pre class=code>　　 1 &lt;?xml version="1.0" encoding="UTF-8"?&gt;
2 &lt;xs:schema attributeFormDefault="unqualified"
elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema"&gt;
3  &lt;xs:element name="rss"&gt;
4    &lt;xs:annotation&gt;
5      &lt;xs:documentation&gt;RSS generated by JIRA 98...
&lt;/xs:documentation&gt;
6    &lt;/xs:annotation&gt;
7    &lt;xs:complexType&gt;
8      &lt;xs:sequence&gt;
9        &lt;xs:element name="channel"&gt;
10          &lt;xs:complexType&gt;
11            &lt;xs:sequence&gt;
12              &lt;xs:element type="xs:string" name="title"/&gt;
13              &lt;xs:element type="xs:anyURI" name="link"/&gt;
14              &lt;xs:element type="xs:string" name="description"/&gt;
15              &lt;xs:element type="xs:string" name="language"/&gt;
15              &lt;xs:element name="item" maxOccurs="unbounded"
minOccurs="0"&gt;</pre>
<p>　　从这个片断中我们发现Jira RSS feed所需的所有元素均已定义。</p>
<p>　　如果用户想要通过其他方式工作，例如从XML Schema开始，XMLBeans的最新版本就提供了这种功能。xsd2inst工具就为用户提供了从模式和全局元素创建示例文档的方式；该实例将包含简单类型的值。上述两种工具的使用使得使用XML实例和模式变得非常简单。</p>
<p>　　在项目的这个阶段，我们就拥有了一个模式，使用这个模式可以通过scomp实用工具创建一个XMLBeans类型jar，并可开始处理业务逻辑以及先前尝试收集的质量指标。</p>
<p>　　通过查看Jira RSS feed实例，我们发现我们关注的bug详细信息放在名为item的元素中，而且生成的模式将item元素作为数组。这意味着，如果我们想要获得可能出现在所有项中的信息，就需要迭代所有项。现在我们看看如何通过一些代码实现这个目标。在下面的代码中，我们会遇到名字被指定为方法参数的用户导致的所有问题：</p>
<pre class=code>　　 1 public Vector getItemsFromReporter(String reporter) {
2
3  // Get the Jira RSS feed instance from a URL
4  URL jiraFeedUrl; = new URL("<jirafeedurl>");
5
6  // Get instance objects
7  RssDocument rssDoc = RssDocument.Factory.parse(jiraFeedUrl);
8  RssDocument.Rss rss = rssDoc.getRss();
9  RssDocument.Rss.Channel channel = rss.getChannel();
10
11  // We will use this object to get most of our data
12  RssDocument.Rss.Channel.Item[] items = channel.getItemArray();
13
14  //We will store all of the valid results in a vector
15  Vector results = new Vector();
16
17  for (int i = 0; i &lt; items.length; i++) {
18   RssDocument.Rss.Channel.Item item = items[i];
19
20   //Add item to results vector when reporter == username
21   if(item.getReporter().getUsername().compareTo(reporter) == 0)
22     results.add(item);
23   }
24  }
25
26  return results;
27 }
</pre>
<p>　　可以看出，这是非常整洁的Java代码。但是，当项数变大时，使用此代码也会影响性能。在最新的XMLBeans版本中，新增了两个新特性来帮助解决这些问题。第一个特性是对JDK 5.0泛型的支持，第二个特性是对XPath和Xquery的支持。我们来看看如何将泛型用于XMLBeans。</p>
<h3>将泛型用于XMLBeans</h3>
<p>　　很明显，JDK 5.0泛型可帮助创建参数化的类和方法。Collections API是XMLBeans中首批使用泛型的API之一。在XML Schema中，当元素包含的maxOccurs属性的值大于1时，默认情况下XMLBeans将针对这些类型创建一个Java数组。为了启用泛型，需要将一个附加参数添加到scomp，并需要使用一个兼容JDK 5.0的虚拟机。</p>
<p>　　默认情况下，用于从channel获取item元素的API包含如下方法：</p>
<table cellSpacing=0 cellPadding=0 width="100%">
    <tbody>
        <tr>
            <th class=right colSpan=2>&nbsp;</th>
        </tr>
        <tr>
            <td class=left width="40%">RssDocument.Rss.Channel.Item</td>
            <td class=right width="60%">getItemArray(int i)<br>获取item元素</td>
        </tr>
        <tr>
            <td class=left>RssDocument.Rss.Channel.Item[]</td>
            <td class=right>getItemArray()<br>获取所有item元素的数组</td>
        </tr>
        <tr>
            <td class=left>void</td>
            <td class=right>setItemArray(int i,RssDocument.Rss.Channel.Item item)<br>设置item元素</td>
        </tr>
        <tr>
            <td class=left>void</td>
            <td class=right>setItemArray(RssDocument.Rss.Channel.Item[] itemArray)<br>设置所有item元素的数组</td>
        </tr>
    </tbody>
</table>
<p>　　但是，执行了启用泛型的编译步骤后，API会有所变化：</p>
<pre class=code>　　/home/user&gt;scomp
Compiles a schema into XML Bean classes and metadata.
Usage: scomp [opts] [dirs]* [schema.xsd]* [service.wsdl]*
[config.xsdconfig]*
Options include:
...
-javasource [version] - generate java source compatible for a
Java version (1.4 or 1.5)
...
#This is all it takes to enable Generics in your use of XMLBeans
/home/user&gt;scomp -javasource 1.5 schema0.xsd
</pre>
<p>　　使用上面的示例，可用的新方法将如下所示：</p>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td width="40%">java.util.List&lt;RssDocument.Rss.Channel.Item&gt;</td>
            <td width="60%">getItemList<br>获取item元素的列表</td>
        </tr>
    </tbody>
</table>
<p>　　现在我们来看看泛型的使用如何能够简化用于实现获取单个用户报告的所有项的方法的代码：</p>
<pre class=code> 1 public List<item> getItemsFromReporter(String reporter) {
2
3  // We already loaded the data as above
4  // ...
5  RssDocument.Rss.Channel channel = rss.getChannel();
6
7  // We will use this object to get most of our data
8  List&lt;RssDocument.Rss.Channel.Item&gt; items =
channel.getItemList();
9
10  for (int i = 0; i &lt; items.size(); i++) {
11    RssDocument.Rss.Channel.Item item =  items.get(i);
12
13    //Remove results from list
14    if (item.getReporter().getUsername().compareTo(reporter)
!= 0)
15        items.remove(i);
16    }
17  }
18
19  return items;
20 }
</pre>
<p>　　这种方法非常不错，但还有一种更加简单的获取每个用户的项信息的方法——当您了解XPath和/或XQuery之后。</p>
<h3>XQuery和XPath</h3>
<p>　　XMLBeans与XQuery和XPath的集成在2.0版本中有了变化。版本1中使用了Jaxen（一种XPath实现），但与XMLBeans的集成不支持命名空间和前缀。最新版本构建于Saxon 8.1.1版本所提供的XQuery实现的基础之上。由于XQuery在Xpath之上构建，所以Saxon还为XMLBeans提供了XPath实现。为了使用XQuery和XPath的特性，XmlObject类（所有XMLBeans类型都派生自它）提供了两个执行实例的查询和语句的方法。XmlObject API的execQuery()和selectPath()方法返回一个匹配组件的数组。这些方法在XmlCursor对象上也存在，但返回对象是使用匹配值列表填充的另一个XmlCursor对象：</p>
<pre class=code> 1 String xq = "for $e in //employee
where $e/name='Bob' return $e ";
2
3 // Input is a valid xml instance
4 XmlObject o = XmlObject.Factory.parse(input);
5
6 XmlObject[] xObjres = o.execQuery(xq);
7 XmlCursor xCurres = o.newCursor.selectPath(xq);
</pre>
<p>　　从上面的代码片断中可以看出API相当易用，而且您可以采取最方便的方式处理生成的数据。我们在第4行中构建了自己的查询语句，并在第6和第7行中使用不同的API运行该查询。XQuery是一个强大的工具，从下面的代码中可以看出获取项数据变得多么简单：</p>
<pre class=code>　　 1 public XmlObject[] getItemsFromReporter(String reporter) {
2
3  //Load Jira RSS feed data
4  URL jiraFeedUrl; = new URL("<jirafeedurl>");
5
6  //This is the only object we need
7  RssDocument rssDoc = RssDocument.Factory.parse(jiraFeedUrl);
8
9  //Build the statement for the xpath engine
10  String xpathStatement =
"//item[reporter/@username='"+reporter+"']";
11
12  //Execute the statement on the instance
13  //We could cast this to an Item[] if we wanted
14  XmlObject[] queryResult = rssDoc.selectPath(xpathStatement);
15
16  return queryResult;
17 }
</pre>
<p>　　将XQuery与XMLBeans同时使用将使其如虎添翼，使对XML的处理变得简单得多。如果要获取更多有关XQuery的信息，有无数的资源可供参考。我们建议从<a href="http://xmlbeans.apache.org/samples/XQueryXPath.html" target=_blank><u><font color=#0000ff>Apache XMLBeans Web站点</font></u></a>上的XMLBeans示例开始。</p>
<p>　　到此时，由于XMLBeans提供的最新特性，XMLBeans的质量指标跟踪问题解决方案实现起来已经非常容易了。我们使用inst2xsd实用工具为实例创建模式，而不用从头编写，从而节省了时间。我们可以看到泛型的启用如何通过使业务逻辑变得容易编写而提高了生产力。最后，我们看到新增的XQuery集成如何提供操纵和查询XML的丰富特性。</p>
<p>　　这些仅仅是最新版本的XMLBeans中的基本新特性。一些其他特性使得XMLBeans成为可满足处理XML时的所有开发需要的理想工具。而下一个特性提供有关使用XML和XML Schema时可能接收到的错误的更详细信息，从而帮助开发人员提高生产力。</p>
<h3>错误代码</h3>
<p>　　错误代码是2.0版本中提供的另一个伟大特性。人们已创建了许多种方法，以便将这个新特性与scomp之类的工具集成，并允许编程式地访问以便（比如说）在IDE中使用。XML Schema规范的附录C定义了一个错误代码集，它定义了非法模式条款。在分析、验证和编译过程中，可使用错误监听程序编程式地访问错误代码。以前，错误消息的详细信息和模式一致性是越小越好。此外，还添加了有关错误所在位置以及模式规范中的相关内容的详细信息。错误代码本身以&#8220;cvc-complex-type.2.2&#8221;的形式定义，可参见http://www.w3c.org/TR/xmlschema-1/#cvc-complex-type条款2.2中的解释。下面我们来看看它的工作方式。我们从一个XML Schema开始，并针对它验证一个实例。然后我们将查看旧的错误，并与接收到的最新版本进行比较。</p>
<pre class=code>　　 1 &lt;!-- errorcode.xsd --&gt;
2 &lt;xs:schema
3   xmlns:xs="http://www.w3.org/2001/XMLSchema"
4   targetNamespace="http://xmlbeans.rocks.com/"
5   xmlns:tns="http://xmlbeans.rocks.com/" &gt;
6   &lt;xs:element name="address" type="tns:address"/&gt;
7   &lt;xs:complexType name="address"&gt;
8     &lt;xs:sequence&gt;
9       &lt;xs:element name="number" type="xs:unsignedInt"/&gt;
10       &lt;xs:element name="street" type="xs:string"/&gt;
11       &lt;xs:choice&gt;
12         &lt;xs:sequence&gt;
13           &lt;xs:element name="city" type="xs:string"/&gt;
14           &lt;xs:element name="state" type="xs:string"/&gt;
15         &lt;/xs:sequence&gt;
16         &lt;xs:element name="zipcode" type="xs:int"/&gt;
17       &lt;/xs:choice&gt;
18       &lt;xs:element name="country" type="xs:string"/&gt;
19     &lt;/xs:sequence&gt;
20   &lt;/xs:complexType&gt;
21 &lt;/xs:schema&gt;</pre>
<p>　　这个模式相当简单。注意xs:choice模型组的用法，因为下面的示例正是在对其进行定义时出错的。我们将要介绍一些错误代码，您很快就可以发现问题所在：</p>
<pre class=code>　　 1 &lt;!-- errorcode.xml --&gt;
2 &lt;t:address
3   xmlns:t="http://xmlbeans.rocks.com/" &gt;
4   &lt;number&gt;72&lt;/number&gt;
5   &lt;street&gt;156th NE&lt;/street&gt;
6   &lt;country&gt;USA&lt;/country&gt;
7 &lt;/t:address&gt;</pre>
<p>　　除了可从命令行使用的scomp实用工具，还存在一个可针对模式验证实例的实用工具。</p>
<pre class=code>　　/home/user&gt;validate
Validates the specified instance against the specified schema.
Contrast with the svalidate tool, which validates using a stream.
Usage: validate [-dl] [-nopvr] [-noupa] [-license]
schema.xsd instance.xml
Options:
-dl - permit network downloads for imports and
includes (default is off)
-noupa - do not enforce the unique particle attribution rule
-nopvr - do not enforce the particle valid (restriction) rule
-partial - allow partial schema type system
-license - print license information
</pre>
<p>　　如果使用XMLBeans的1.0版本运行validate实用工具，结果将如下所示：</p>
<pre class=code>　　/home/user&gt;validate errorcode.xsd errorcode.xml
errorcode.xml:0: error: Expected elements
city zipcode at the end of the content in element
address@http://xmlbeans.rocks.com/
</pre>
<p>　　上面的错误文本提到了实例的名称，并告诉我们地址的末尾缺少一些应有的元素。在这个小示例中，这是有点用处的，但没有行号很难找到起点。现在我们将这个代码文本与新版本中的新增错误代码特性进行比较：</p>
<pre class=code>　　 /home/user&gt;validate errorcode.xsd errorcode.xml
errorcode.xml:4: error: cvc-complex-type.2.4a: Expected elements
'city state' instead of 'country' here in element
address@http://xmlbeans.beaworld.com/
errorcode.xml:4: error: cvc-complex-type.2.4c: Expected elements
'zipcode' before the end of the content in element
address@http://xmlbeans.beaworld.com/
</pre>
<p>　　与XMLBeans的1.0版本中的错误文本相比，新的错误文本有很大的改进。两个错误文本都提到了实例，但新错误代码还提供了行号、问题严重程度、附录C模式参考以及更清楚的错误消息。而且，使用新的错误代码，我们发现错误代码cvc-complex-type.2.4a和cvc-complex-type.2.4c还提及更多造成故障的问题。同样，这些错误代码也分别对应于模式规范中一个可使用URL访问的位置。</p>
<p>　　刚刚我们介绍了如何通过命令行获取详细的错误文本，现在介绍如何以编程方式获取错误信息：</p>
<pre class=code>　　 1 // Create the error listener and XmlOptions
2 LinkedList list = new LinkedList();
3 XmlOptions opts = new XmlOptions().setErrorListener(list);
4
5 // Load the instance
6 File instance = new File("&lt;SOME_PATH&gt;\errorcodes.xml");
7 AddressDocument ad = AddressDocument.Factory.parse(instance);
8
9 // If there are errors, making a method call like this will
10 // populate the error listener
11 ad.validate(opts);
12
13 // Since we know there are errors, let's
14 // look at how to get at the data
15 for(int i=0; i &lt; errors.size(); i++) {
16
17   // Cast list object to an XmlError
// type XmlError e = (XmlError)
18   errors.get(i);
19
20   // Now, let's get at all the information about the error
21   // This will be the location of the error in the instance
22   System.out.println("["+e.getLine()+","+e.getColumn()+"]-" +
e.getSeverity())
23   // Information about the error
24   System.out.println(e.getErrorCode() + ": " +e.getMessage());
25 }</pre>
<p>　　请看此代码片断，以编程方式访问错误信息并不比从命令行获取类似信息困难多少。</p>
<h3>性能提升</h3>
<p>　　用户可能不会注意到以前的特性，但一定会注意到它对开发工作的影响。如果新版本无法带来性能提升，那它还有什么好处呢？</p>
<p>　　与在XMLBeans 1.0中一样，性能对于2.0版本极为重要。在大多数情况下，与1.0相比，2.0版本性能有了10%到60%的提升。导致性能提升的原因有许多，其中最重要的是完全不同的存储架构。在1.0版本中，使用了一个名为splay tree的数据结构使所有存储在XML Store中的内容与影响XML数据的操作同步。对于不熟悉它的用户，splay tree可以理解为支持O(log N)次Find、Insert和Delete操作的平衡树。这种数据结构与其他此类树的差别在于它不维持显式的平衡条件。其详细程度超出了用户在大多数情况下的需要。2.0版本使用了一个较为简单的架构，提供较少的复制和较少的对象。</p>
<p>　　在对XML数据执行任何操作时，XMLBeans都会加载一个XML Store。XMLBeans总是加载一个XML Store，然后在Store上提供一个绑定视图。与直接解组到Java对象的其他Java/XML绑定框架相比，此绑定视图与完整的XML Infoset真实性通常导致额外的开销。这使得XMLBeans的性能一直是一个障碍，从而消弱了额外的特性与信息所带来的好处。对于运行时性能，人们主要关注的就是XML Store方面，并尽可能地使Store的性能得到提高。</p>
<p>　　在对XML Store进行改写时，新增了一个特性，该特性使得使用XMLBeans进行编程可以有更好的性能，并且更易于使用。此特性即DOM Level II支持。DOM是Document Object Model（文档对象模型）的简写，它提供了一个用于处理XML数据的接口。Level II则指定哪些接口是可用的。它与SAX的区别在于XML信息保存在内存中。</p>
<h3>固有的DOM II支持</h3>
<p>　　在1.0版本中，对DOM的访问由Xerces处理，因此此类调用返回一个Xerces DOM Node。在2.0中，类似调用返回XMLBeans DOM表示，因为DOM II现在是天然实现的。这意味着在XMLBeans内无需协调两种不同的数据存储即可访问DOM表示和XMLBeans表示。</p>
<p>　　这还意味着可以通过以下三种方式中的任何一种来处理XML。第一种方式是使用XmlObject API中JavaBean风格的方法。第二种方式是通过XMLCursor API使用基于令牌的模型。而第三种方式是使用对熟悉DOM API的人来说非常熟悉的树模型。它有一个特别的好处，就是用户可以在这些方法之间来回切换，而不必担心实例的同步问题。从开发人员的角度来看，这就意味着他们可以使用最顺手的方式来处理XML。现在我们来了解一些可以在其中进行切换以便获得XML的底层视图的API：</p>
<pre class=code>　　//To get the live DOM Node:
Node  XmlObject.getDomNode()
Node  XmlCursor.getDomNode()
//To get back:
XmlObject XmlBeans.nodeToObject(Node n)
XmlCursor XmlBeans.nodeToCursor(Node n)
//XMLBeans 1.0 API returns a copy:
Node XmlObject.newDomNode()
</pre>
<p>　　从上面的代码中可以看出，在这些视图之间进行切换相当容易。</p>
<h3>结束语</h3>
<p>　　本文介绍了XMLBeans 2.0中可用的一些新特性。我们了解到XMLBeans提供了一个健壮且完全保真的Java到XML的绑定框架。我们还介绍了如何使用XMLBeans 2.0的一些新特性更方便快捷地完成项目。这些新特性可以提高开发人员的生产力。性能提升也有助于提高生产力，但更重要的是，这意味着花在对应用程序进行调试和分析瓶颈上的时间将会减少。</p>
<p>　　我们介绍的特性只是XMLBeans的最新版本所提供的一部分增强。请了解一下XMLBeans，看它是如何帮助改进开发人员的开发工作的。</p>
<h3>参考资料</h3>
<ul>
    <li><a href="http://xmlbeans.apache.org/sourceAndBinaries/index.html" target=_blank><u><font color=#0000ff>Apache XMLBeans</font></u></a>——XMLBeans官方网站
    <li>一个<a href="http://xmlbeans.apache.org/samples/XQueryXPath.html" target=_blank><u><font color=#0000ff>XQuery和XPath</font></u></a>示例
    <li>一些有用的<a href="http://www.xfront.com/GlobalVersusLocal.html" target=_blank><u><font color=#0000ff>模式设计指导原则</font></u></a>
    <li>Dev2Dev上的<a href="http://dev2dev.bea.com/opensource/" target=_blank><u><font color=#0000ff>开源</font></u></a>页面 </li>
</ul><img src ="http://www.blogjava.net/mlh123caoer/aggbug/138303.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-08-21 11:06 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/08/21/138303.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JLINQ: IBM's new paradigm for writing Java database applications</title><link>http://www.blogjava.net/mlh123caoer/archive/2007/08/19/137999.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Sun, 19 Aug 2007 14:57:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/08/19/137999.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/137999.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/08/19/137999.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/137999.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/137999.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Level: IntermediateAzadeh Ahadian (azadeh@us.ibm.com), Eclipse Application Development Tools , IBM16 Aug 2007The project code named Java&#8482; Language Integrated Query (JLINQ) gives database a...&nbsp;&nbsp;<a href='http://www.blogjava.net/mlh123caoer/archive/2007/08/19/137999.html'>阅读全文</a><img src ="http://www.blogjava.net/mlh123caoer/aggbug/137999.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-08-19 22:57 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/08/19/137999.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JavaFX编程语言基础</title><link>http://www.blogjava.net/mlh123caoer/archive/2007/08/17/137425.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Thu, 16 Aug 2007 16:39:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/08/17/137425.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/137425.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/08/17/137425.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/137425.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/137425.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: JavaFX Script&#8482; （下文中成为JavaFX）语言是一种声明式的静态类型编程语言。它具有第一级函数（first-classfunctions）、声明式的语法、列表推导（list-comprehensions）及基于依赖关系的增量式求值（incrementaldependency-based evaluation）等特征。JavaFX 脚本式语言特别适用于Java2D ...&nbsp;&nbsp;<a href='http://www.blogjava.net/mlh123caoer/archive/2007/08/17/137425.html'>阅读全文</a><img src ="http://www.blogjava.net/mlh123caoer/aggbug/137425.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-08-17 00:39 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/08/17/137425.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入学习JavaFX脚本语言-參考</title><link>http://www.blogjava.net/mlh123caoer/archive/2007/08/17/137424.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Thu, 16 Aug 2007 16:36:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/08/17/137424.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/137424.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/08/17/137424.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/137424.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/137424.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Translated by Liu Dan (cleverpig) and Tian Le (Tin) 本文档将讨论在JavaFX语言中可用的各种GUI组件，并提供示例代码，讨论JavaFX组件与Swing GUI组件相比的差异。前提条件如果你从前没有阅读过JavaFX脚本语言起步教程，那么我们强烈推荐你在继续阅读本文档之前首先阅读JavaFX脚本语言起步教程。你应该具有熟...&nbsp;&nbsp;<a href='http://www.blogjava.net/mlh123caoer/archive/2007/08/17/137424.html'>阅读全文</a><img src ="http://www.blogjava.net/mlh123caoer/aggbug/137424.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-08-17 00:36 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/08/17/137424.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JavaFX入门教程二</title><link>http://www.blogjava.net/mlh123caoer/archive/2007/08/09/135471.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Thu, 09 Aug 2007 05:36:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/08/09/135471.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/135471.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/08/09/135471.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/135471.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/135471.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 原作者： Anghel Leonard时间：08/01/2007翻译：Caoer2007年8月8日JavaFX 代码同Java代码极容易集成. 这有一个使用JavaFX装载一个图片到窗体例子，它允许使用者选择一个矩形区域保存这个矩形区域。这个捕捉保存操作由Java代码完成。源码列表 15import java.io.*;import javafx.ui.*;import jav...&nbsp;&nbsp;<a href='http://www.blogjava.net/mlh123caoer/archive/2007/08/09/135471.html'>阅读全文</a><img src ="http://www.blogjava.net/mlh123caoer/aggbug/135471.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-08-09 13:36 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/08/09/135471.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JavaFX入门教程一</title><link>http://www.blogjava.net/mlh123caoer/archive/2007/08/07/134905.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Tue, 07 Aug 2007 03:49:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/08/07/134905.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/134905.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/08/07/134905.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/134905.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/134905.html</trackback:ping><description><![CDATA[<p>&nbsp; </p>
<p><span>原作者：</span><span> <span><a href="http://www.onjava.com/pub/au/3140"><span>Anghel Leonard</span></a><br></span></span><span>时间：</span><st1:chsdate w:st="on" IsROCDate="False" IsLunarDate="False" Day="1" Month="8" Year="2007"><span>08/01/2007</span></st1:chsdate><br><span>翻译：</span><span>Caoer<br><st1:chsdate w:st="on" IsROCDate="False" IsLunarDate="False" Day="5" Month="8" Year="2007">2007<span><span>年</span></span>8<span><span>月</span></span>5<span><span>日</span></span></st1:chsdate></span></p>
<p><strong><span>什么是</span></strong><strong><span>JavaFX</span></strong><strong><span>？</span></strong><strong><span>SUN</span></strong><strong><span>（太阳公司）在</span></strong><strong><span>2007</span></strong><strong><span>年春天发布了一个叫</span></strong><strong><span>JavaFX</span></strong><strong><span>新框架。这是一个泛泛的名字，因为</span></strong><strong><span>JavaFX</span></strong><strong><span>主要包含</span></strong><strong><span>Script and Mobile</span></strong><strong><span>两个组件，在将来</span></strong><strong><span>SUN</span></strong><strong><span>将开发更多的组件。</span></strong><strong></strong></p>
<p><strong><span>JavaFX </span></strong><strong><span>的核心是</span></strong><strong><span> JavaFX </span></strong><strong><span>脚本，是一个声明式脚本语言。尽管同</span></strong><strong><span>Java</span></strong><strong><span>代码非常不同，但是同</span></strong><strong><span>Java</span></strong><strong><span>类具有很高的交互度。</span></strong><strong><span> JavaFX </span></strong><strong><span>中的很多类主要为了更容易实现</span></strong><strong><span>Swing</span></strong><strong><span>和</span></strong><strong><span>Java2D</span></strong><strong><span>而设计的。使用</span></strong><strong><span> JavaFX </span></strong><strong><span>脚本，您能很容易的为文本和图形开发</span></strong><strong><span>GUI</span></strong><strong><span>接口、动画和非常</span></strong><strong><span>COOL</span></strong><strong><span>的效果。并且，您能将</span></strong><strong><span>Java</span></strong><strong><span>和</span></strong><strong><span>HTML</span></strong><strong><span>代码包装到</span></strong><strong><span> JavaFX </span></strong><strong><span>脚本中。</span></strong><strong></strong></p>
<p><strong><span>第二个组件</span></strong><strong><span>- JavaFX Mobile</span></strong><strong><span>，是为移动设备开发</span></strong><strong><span>Java</span></strong><strong><span>应用的平台。它最终会成为开发</span></strong><strong><span> JavaFX </span></strong><strong><span>脚本的平台但是现在同这篇文章实用的技术还很不兼容。</span></strong><strong></strong></p>
<p><strong><span>JavaFX </span></strong><strong><span>应用的一些例子</span></strong><strong></strong></p>
<p align=left><strong><span>在开始学习一门新的语言前，让我们先看一下</span></strong><strong><span>JavaFX</span></strong><strong><span>代码的一些例子。</span></strong><strong><span><a href="https://openjfx.dev.java.net/"><span>JavaFX </span><span><span>官方站点</span></span></a></span></strong><strong><span>具有大量的</span></strong><strong><span>JavaFX </span></strong><strong><span>实例。请点击</span></strong><span><a href="http://download.java.net/general/openjfx/demos/tutorial.jnlp"><strong><span>JavaFX Script 2D Graphics Tutorial</span></strong></a></span><strong><span>下载该实例</span></strong><strong><span>. </span></strong><strong><span>下载完成以后，双击</span></strong><strong><em><span>tutorial.jnlp</span></em></strong><strong><span> </span></strong><strong><span>文件即可运行。几秒过后，你应该能够看到如图一的</span></strong><strong><span>JavaFX</span></strong><strong><span>实例运行场景（若没有出现该图片，你必须为</span></strong><strong><span>.jnlp</span></strong><strong><span>扩展名重新配置</span></strong><strong><span>Java Web</span></strong><span> <strong>Start</strong></span><strong><span>）。</span></strong><span>&nbsp;<br><span><span lang=EN-US style="FONT-SIZE: 10.5pt; COLOR: #333333; FONT-FAMILY: 'Times New Roman'; mso-fareast-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><v:shapetype id=_x0000_t75 stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype><img height=450 alt="Running the tutorial.jnlp" src="http://www.onjava.com/onjava/2007/07/27/graphics/tutorial.gif" width=450></span><br></span></span><em><span>图一、运行</span></em><em><span> tutorial.jnlp tutorial</span></em></p>
<p><strong><span>花些时间看一看这些例子和源代码。仅仅使用有限的几行</span></strong><strong><span>JavaFX</span></strong><strong><span>代码就能得到很多有趣的效果。如果你对于</span></strong><strong><span>JavaFX</span></strong><strong><span>的应用还是感到摸不着头脑，看一看下面的两个</span></strong><strong><span>demo</span></strong><strong><span>。它们是</span></strong><strong><span>StudioMoto </span></strong><strong><span>和</span></strong><strong><span> Tesla Motors </span></strong><strong><span>站点的部分重新实现。您可以从</span></strong><strong><span>OpenJFX </span></strong><strong><span>项目站点下载</span></strong><strong><span>OpenJFX </span></strong><strong><span>脚本</span></strong><strong><u><span>Studiomoto Demo</span></u></strong><strong><span> </span></strong><strong><span>和</span></strong><strong><span> <span><a href="http://download.java.net/general/openjfx/demos/tesla.jnlp"><span>Tesla Demo</span></a></span></span></strong><strong><span>。它们需要</span></strong><strong><span>Java Web Start </span></strong><strong><span>才能运行，但是也取决于你的机器配置它们可能自动运行，或者你必须找到和运行已经下载的</span></strong><strong><span>.jnlp</span></strong><strong><span>文件。</span></strong></p>
<p><strong><span>下载安装</span></strong><strong><span>JavaFX</span></strong></p>
<p><span><br></span><strong><span>如果你对于学习开发</span></strong><strong><span>JavaFX</span></strong><strong><span>应用程序，您应该了解至少使用</span></strong><strong><span>JavaFX</span></strong><strong><span>三个方法。同时了解</span></strong><strong><span>JavaFX</span></strong><strong><span>应用程序不是基于浏览器的也很重要。最简单最快捷的方法是基于叫</span></strong><strong><span>JavaFXPad</span></strong><strong><span>轻量级的工具。使用该工具的主要优势是你总能立即看到你在编辑器里所作更改的效果。你能从</span></strong><strong><span>JavaFX</span></strong><strong><span>项目网站下载到该工具（</span></strong><span> <span><a href="http://download.java.net/general/openjfx/demos/javafxpad.jnlp"><strong><span>JavaFXPad</span></strong></a> </span></span><strong><span>）。并且运行它需要</span></strong><strong><span>Java Web Start </span></strong><strong><span>（如图二）。</span></strong></p>
<p><span lang=EN-US style="FONT-SIZE: 10.5pt; COLOR: #333333; FONT-FAMILY: 'Times New Roman'; mso-fareast-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><v:shapetype id=_x0000_t75 stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600">&nbsp;<v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype><img height=450 alt="Running the javafxpad editor" src="http://www.onjava.com/onjava/2007/07/27/graphics/javafxpad.gif" width=450></span><span><br></span><em><span>图二、运行</span></em><em><span>JavaFXPad</span></em><em><span>编辑器</span></em></p>
<p><strong><span>使用</span></strong><strong><span>JavaFX</span></strong><strong><span>的另一种方式是使用</span></strong><strong><span>JavaFX</span></strong><strong><span>脚本</span></strong><strong><span>NetBeans 5.5</span></strong><strong><span>插件或者</span></strong><strong><span>Eclipse 3.2</span></strong><strong><span>插件（需要下载和安装</span></strong><strong><span>NetBeans 5.5 </span></strong><strong><span>或者</span></strong><strong><span> Eclipse <st1:chsdate w:st="on" IsROCDate="False" IsLunarDate="False" Day="30" Month="12" Year="1899">3.2.2</st1:chsdate></span></strong><strong><span>以上集成开发工具</span></strong><strong><span> </span></strong><strong><span>）。若您已经使用</span></strong><strong><span> NetBeans 5.5</span></strong><strong><span>开始你的</span></strong><strong><span>JavaFX</span></strong><strong><span>之旅</span></strong><strong><span>,OpenJFX</span></strong><strong><span>项目网站的对于</span></strong><span><a href="https://openjfx.dev.java.net/javafx-nb55-plugin-install.html"><strong><span>NetBean</span></strong><strong><span><span>开发</span></span></strong><strong><span>JavaFX</span></strong><strong><span><span>的说明</span></span></strong></a></span><strong><span>将会给予你帮助。</span></strong><strong><span> </span></strong><strong><span>相似的如果您使用基于</span></strong><strong><span>Eclipse</span></strong><strong><span>的</span></strong><strong><span>JavaFX</span></strong><strong><span>插件，您可以去</span></strong><strong><span>JavaFX</span></strong><strong><span>的</span></strong><span><a href="https://openjfx.dev.java.net/javafx-eclipse-plugin-install.html"><strong><span>Eclipse</span></strong><strong><span><span>插件</span></span></strong></a></span><strong><span>。注意这篇文章中的所有例子已经在</span></strong><strong><span>NetBeans5.5</span></strong><strong><span>的</span></strong><strong><span>JavaFX</span></strong><strong><span>插件中测试过，但是应该能够使用其他方法运行。</span></strong></p>
<p><strong><span>使用</span></strong><strong><span>NetBeans 5.5</span></strong><strong><span>下的</span></strong><strong><span>JavaFX</span></strong><strong><span>插件开发</span></strong><strong><span>Hello World </span></strong><strong><span>程序</span></strong></p>
<p><strong><span>每当开始学习一门新的语言时，我们必定要写</span></strong><strong><span>Hello World </span></strong><strong><span>小程序：</span></strong></p>
<p><strong><span>源码列表</span></strong><strong><span>1</span></strong></p>
<p><span>import javafx.ui.*;</span></p>
<p><span>import java.lang.System;</span></p>
<p><span>Frame {</span></p>
<p><span>centerOnScreen: true</span></p>
<p><span>visible: true</span></p>
<p><span>height: 50</span></p>
<p><span>width: 350</span></p>
<p><span>title: "HelloWorld application..."</span></p>
<p><span>background: yellow</span></p>
<p><span>onClose: operation() {System.exit(0);}</span></p>
<p><span>content: Label {</span></p>
<p><span>text: "Hello World"</span></p>
<p><span>}</span></p>
<p><span>}</span></p>
<p><strong><span>在</span></strong><strong><span>NetBeans5.5</span></strong><strong><span>开发和运行这个小程序步骤如下</span></strong><strong><span>:</span></strong></p>
<p><span><span>1.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><strong><span>启动</span></strong><strong><span>NetBeans 5.5.</span></strong></p>
<p><span><span>2.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><strong><span>从主菜单选择</span></strong><strong><span>File -&gt; New Project.</span></strong></p>
<p><span><span>3.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><strong><span>在新项目窗口</span></strong><strong><span>,</span></strong><strong><span>选择目录常规目录和</span></strong><strong><span> Java </span></strong><strong><span>应用项目</span></strong><strong><span>(</span></strong><strong><span>点击下一步</span></strong><strong><span>).</span></strong></p>
<p><span><span>4.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><strong><span>在新的</span></strong><strong><span>Java</span></strong><strong><span>应用程序窗口</span></strong><strong><span>,</span></strong><strong><span>在项目名文本框敲入</span></strong><strong><span> "FXExample".</span></strong></p>
<p><span><span>5.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><strong><span>在相同窗口，用浏览按钮选择项目的目录</span></strong><strong><span>.</span></strong></p>
<p><span><span>6.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><strong><span>取消</span></strong><strong><span> "Set as main project" </span></strong><strong><span>和</span></strong><strong><span> "Create main class" </span></strong><strong><span>复选框</span></strong><strong><span> (</span></strong><strong><span>点击完成</span></strong><strong><span>).</span></strong></p>
<p><span><span>7.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><strong><span>右击</span></strong><strong><span>FXExample -&gt; Source Packages </span></strong><strong><span>和选择</span></strong><strong><span> New -&gt; File/Folder.</span></strong></p>
<p><span><span>8.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><strong><span>在新的文件窗口，选择另一个目录和</span></strong><strong><span>JavaFX</span></strong><strong><span>文件类型（点击下一步）</span></strong><strong><span>.</span></strong></p>
<p><span><span>9.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><strong><span>在新的</span></strong><strong><span>JavaFX</span></strong><strong><span>文件窗口，敲入</span></strong><strong><span>"HelloWorld" </span></strong><strong><span>作为文件名和</span></strong><strong><span>"src"</span></strong><strong><span>作为目录</span></strong><strong><span>(</span></strong><strong><span>点击完成</span></strong><strong><span>).</span></strong></p>
<p><span><span>10.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><strong><span>拷贝源码列表</span></strong><strong><span>1</span></strong><strong><span>到</span></strong><strong><span> <em><span>HelloWorld.fx</span></em><span>.</span></span></strong></p>
<p><span><span>11.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><strong><span>右击</span></strong><strong><em><span>FXExample</span></em></strong><strong><span> </span></strong><strong><span>项目选择项目属性</span></strong><strong><span>.</span></strong></p>
<p><span><span>12.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><strong><span>在项目</span></strong><strong><span>FXExample</span></strong><strong><span>属性对话框</span></strong><strong><span> ,</span></strong><strong><span>选择从目录面板运行节点</span></strong><strong><span>.</span></strong></p>
<p><span><span>13.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><strong><span>在参数文本框敲入</span></strong><strong><span> "Hello World" (</span></strong><strong><span>点击完成</span></strong><strong><span>).</span></strong></p>
<p><span><span>14.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><strong><span>右击</span></strong><strong><em><span>FXExample</span></em></strong><strong><span> </span></strong><strong><span>项目选择运行项目选项</span></strong><strong><span>.</span></strong></p>
<p><strong><span>如果一切良好</span></strong><strong><span>,</span></strong><strong><span>你应该看到一个窗体如图三：</span></strong></p>
<span lang=EN-US style="FONT-SIZE: 10.5pt; COLOR: #333333; FONT-FAMILY: 'Times New Roman'; mso-fareast-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><v:shapetype id=_x0000_t75 stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype><img height=53 alt="Running the Hello World application" src="http://www.onjava.com/onjava/2007/07/27/graphics/helloworld.gif" width=352></span>
<p><span><br></span><em><span>图三、</span></em><em><span> </span></em><em><span>在</span></em><em><span>NetBeans 5.5</span></em><em><span>中运行</span></em><em><span> Hello World </span></em><em><span>应用程序</span></em></p>
<p><strong><span>现在你拥有了开发和运行任何</span></strong><strong><span>JavaFX</span></strong><strong><span>应用程序的</span></strong><strong><span>IDE</span></strong><strong><span>软件支持</span></strong><strong><span>.</span></strong></p>
<p><strong><span>JavaFX </span></strong><strong><span>语法</span></strong><strong></strong></p>
<p><strong><span>在正式开始学习</span></strong><strong><span>JavaFX</span></strong><strong><span>，让我们浏览一遍该语言的语法要点。如果你非常熟悉</span></strong><strong><span>Java</span></strong><strong><span>语言，这些语法的大多数会让你感到非常熟悉，但是有一些会相当不一样。</span></strong></p>
<p><strong><span>JavaFX </span></strong><strong><span>原始类型</span></strong><strong></strong></p>
<p><strong><span>JavaFX </span></strong><strong><span>支持原始类型：</span></strong><strong><span>String (</span></strong><strong><span>对应于</span></strong><strong><span> <span>java.lang.String), Boolean (</span></span></strong><strong><span>对应于</span></strong><strong><span> <span>java.lang.Boolean), Number (</span></span></strong><strong><span>对应于</span></strong><strong><span> <span>java.lang.Number) </span></span></strong><strong><span>和</span></strong><strong><span> <span>Integer (</span></span></strong><strong><span>对应于</span></strong><strong><span> <span>byte,short,int,long,BigInteger).</span></span></strong></p>
<p><strong><span>JavaFX </span></strong><strong><span>变量</span></strong><strong></strong></p>
<p><strong><span>一个</span></strong><strong><span>JavaFX</span></strong><strong><span>变量使用</span></strong><strong><span>var</span></strong><strong><span>关键字声明。看下面的例子：</span></strong></p>
<p><span>var x:Number = 0.9;</span></p>
<p><span>var name:String = "John";</span></p>
<p><span>var y:Integer = 0;</span></p>
<p><span>var flag:Boolean = true;</span></p>
<p><span>var numbers:Number = [1,2,3,4,5]</span><span>；</span></p>
<p><strong><span>JavaFX </span></strong><strong><span>操作符</span></strong><strong></strong></p>
<p><span><br></span><strong><span>众所周知的</span></strong><strong><span>Java</span></strong><strong><span>操作符</span></strong><strong><span>&amp;&amp;, || </span></strong><strong><span>和</span></strong><strong><span> </span></strong><strong><span>!</span></strong><strong><span> </span></strong><strong><span>在</span></strong><strong><span>JavaFX</span></strong><strong><span>中采用下面的形式：</span></strong></p>
<p><span><span>&#183;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>Java: </span><span>&amp;&amp;<br></span><span>JavaFX: </span><span>and</span></p>
<p><span><span>&#183;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>Java: </span><span>||<br></span><span>JavaFX: </span><span>or</span></p>
<p><span><span>&#183;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>Java: </span><span>!<br></span><span>JavaFX: </span><span>not</span></p>
<p><strong><span>JavaFX </span></strong><strong><span>方法</span></strong><strong></strong></p>
<p><span><br><strong>JavaFX </strong></span><strong><span>支持这些方法</span></strong><strong><span>. </span></strong><strong><span>具有参数、变量声明和返回值的方法举例：</span></strong></p>
<p><span>function taxes(x) { var t:Number = (19.0/100.0)*x; return t; }</span></p>
<p><strong><span>JavaFX if </span></strong><strong><span>语句</span></strong><strong></strong></p>
<p><span><br></span><span>在</span><strong><span>JavaFX</span></strong><strong><span>中，你你能通过使用</span></strong><strong><span>if</span></strong><strong><span>语句使用条件判断。</span></strong></p>
<p><span>if (</span><em><span>条件</span></em><span>) { //</span><span>动作</span><span> } else if (</span><span>条件</span><span>) { //</span><span>动作</span><span> } else { //</span><span>动作</span><span> }</span></p>
<p><strong><span>JavaFX while </span></strong><strong><span>语句</span></strong><strong></strong></p>
<p><span><br></span><strong><span>这个</span></strong><strong><span> </span></strong><strong><span>while</span></strong><strong><span> </span></strong><strong><span>语句同在</span></strong><strong><span>Java</span></strong><strong><span>中的</span></strong><strong><span>while</span></strong><strong><span>语句相似。</span></strong><strong><span> </span></strong><strong><span>while (</span></strong><strong><em><span>条件</span></em></strong><strong><span>) { //</span></strong><strong><span>动作</span></strong><strong><span>}</span></strong></p>
<p><strong><span>JavaFX for </span></strong><strong><span>语句</span></strong><strong></strong></p>
<p><span><br></span><strong><span>for</span></strong><strong><span> </span></strong><strong><span>语句用于循环和间隔（间隔使用方括号</span></strong><strong><span>[]</span></strong><strong><span>和</span></strong><strong><span> </span></strong><strong><span>..</span></strong><strong><span> </span></strong><strong><span>符号表示</span></strong><strong><span>).</span></strong></p>
<p><span>//i </span><span>将取值：</span><span> 0, 1, 2, 3, 4, 5</span><span>象在</span><span> (i in [0..5]) { //</span><em><span>伴随</span></em><em><span> i</span></em><em><span>的动作</span></em><span> }</span><span>代码块中</span></p>
<p><strong><span>JavaFX </span></strong><strong><span>过程</span></strong><strong></strong></p>
<p><span><br><strong>JavaFX </strong></span><strong><span>过程以</span></strong><strong><span>operation</span></strong><strong><span> </span></strong><strong><span>关键字为标志。一个简单的例子：</span></strong></p>
<p><span>operation startClock() {do{ while(true) {</span></p>
<p><span>if(seconds&gt;=360) {seconds = 0; seconds = [0,6..360] dur 60000 linear;}</span></p>
<p><span>if(minutes&gt;=360) {minutes = 0; minutes = [0,6..360] dur 3600000 linear;}</span></p>
<p><span>if(hours&gt;=360) {hours = 0; hours = [0,6..360] dur 43200000 linear;} } }}</span></p>
<p><strong><span>JavaFX </span></strong><strong><span>类</span></strong><strong></strong></p>
<p><span><br><strong>JavaFX </strong></span><strong><span>类使用</span></strong><strong><span>class</span></strong><strong><span>关键字</span></strong><strong><span>. </span></strong><strong><span>一个</span></strong><strong><span> JavaFX </span></strong><strong><span>类能够使用</span></strong><strong><span>extends</span></strong><strong><span> </span></strong><strong><span>关键字继承多个类使用逗号分割</span></strong><strong><span><br></span></strong><strong><span>这些类的名字。在花括号中间你可以放属性、方法和过程，例如下面的例子：</span></strong></p>
<p><span>class Order {</span></p>
<p><span>attribute order_nr: String;</span></p>
<p><span>attribute ordertype: Order inverse Order.products;</span></p>
<p><span>attribute products: Order* inverse Order.ordertype;</span></p>
<p><span>function getOrderNr(): String;</span></p>
<p><span>operation addOrder(order: Order);</span></p>
<p><span>}</span></p>
<p>&nbsp;</p>
<p><strong><span>注意属性使用</span></strong><strong><span>attribute</span></strong><strong><span>关键字声明，方法体和过程不在类体中，它们单元定义在类声明以后，在下文你很快就能看到。</span></strong><strong><span> <span>inverse</span></span></strong><strong><span> </span></strong><strong><span>子句是一个可选项</span></strong><strong><span> </span></strong><strong><span>，它表示一种同在类中另一个属性的双向关系。在这个案例中</span></strong><strong><span>JavaFX</span></strong><strong><span>将自动完成更新（插入、替代和删除）你能在</span></strong><strong><span>Java.net</span></strong><strong><span>上找到更完整的</span></strong><span><a href="https://openjfx.dev.java.net/JavaFX_Programming_Language.html"><strong><span><span>文档</span></span></strong></a></span><strong><span>。</span></strong></p>
<p><strong><span>熟悉</span></strong><strong><span>JavaFX</span></strong></p>
<p>&nbsp;</p>
<p><strong><span>在本小节，您将会看到一系列的小例子，这些例子覆盖</span></strong><strong><span>JavaFX</span></strong><strong><span>的各种特性和功能。主要目的是让你熟悉</span></strong><strong><span>JavaFX</span></strong><strong><span>代码和</span></strong><strong><span>JavaFX</span></strong><strong><span>应用程序的逻辑。第二个目标是当你需要开发仅仅需要几行代码就会有非常酷的</span></strong><strong><span>GUI</span></strong><strong><span>，动画和好的效果时候使你确信</span></strong><strong><span>JavaFX</span></strong><strong><span>值得好好研究一下。所有列出的例子将介绍关于</span></strong><strong><span>JavaFX</span></strong><strong><span>的技巧。每一个例子只使用很少的描述处理，所以不要想找到大量的注释。所有这些可访问的例子你都是你自己就能运行的，所以让我们开始吧。当我们需要使用</span></strong><strong><span>System.out.println</span></strong><strong><span> </span></strong><strong><span>打印属性值时候，你可以把它的名字放进含有引用的字符串，象源码列表</span></strong><strong><span>2</span></strong><strong><span>中所示的那样。</span></strong></p>
<p><span>源码列表</span><span>2</span></p>
<p><span>//</span><span>带有应用文本的表达式</span></p>
<p><span>import java.lang.System;<br>var mynumber:Number = 10;<br>System.out.println("</span><span>数字是</span><span>: {mynumber}");</span></p>
<p>&nbsp;</p>
<p><strong><span>结果</span></strong><strong><span>: </span></strong><strong><span>数字是</span></strong><strong><span>: 10<br><em>JavaFX</em> </span></strong><strong><span>支持变量的计数这样一个有用的功能。这个功能利用下面的三个操作符实现：</span></strong></p>
<p><span><span>&#183;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><strong><span>?</span></strong><strong><span>: </span></strong><strong><span>可选的</span></strong><strong><span>(</span></strong><strong><span>可能为</span></strong><strong><span> </span></strong><strong><span>null</span></strong><strong><span>)</span></strong></p>
<p><span><span>&#183;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><strong><span>+</span></strong><strong><span>: 1</span></strong><strong><span>或多个</span></strong></p>
<p><span><span>&#183;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><strong><span>*</span></strong><strong><span>: 0</span></strong><strong><span>或多个</span></strong></p>
<p><strong><span>源码列表</span></strong><strong><span>3</span></strong></p>
<p><span>//</span><span>变量计数</span></p>
<p><span>import java.lang.System;<br>var mynumbers:Number* = [1,2,7];<br>System.out.println("</span><span>数字是</span><span>: {mynumbers}");</span></p>
<p>&nbsp;</p>
<p><span>结果</span><span>: </span><span>数字是</span><span>: 1 2 7<br></span><strong><span>在</span></strong><strong><span>JavaFX</span></strong><strong><span>中</span></strong><strong><span>, </span></strong><strong><span>在声明部分不指定变量的类型是可能的。</span></strong><strong><span> </span></strong><strong><span>这不会产生错误，因为</span></strong><strong><span>JavaFX </span></strong><strong><span>将在该变量的使用中自动发现它的类型。</span></strong></p>
<p><strong><span>源码列表</span></strong><strong><span> 4</span></strong></p>
<p><span>//</span><span>变量类型是可选的</span></p>
<p><span>import java.lang.System; <br>var days = ["Monday,","Friday,","Sunday"]; <br>System.out.println("</span><span>你必须工作</span><span>: {days}");</span></p>
<p><span><br></span><span>结果</span><span>: </span><span>你必须工作</span><span>: Monday, Friday, Sunday<br></span><strong><span>你可以使用</span></strong><strong><span>sizeof</span></strong><strong><span> </span></strong><strong><span>操作符得到一个数组的大小：</span></strong></p>
<p><strong><span>源码列表</span></strong><strong><span> 5</span></strong></p>
<p><span>//</span><span>得到一个数组的大小</span></p>
<p><span>import java.lang.System;<br>var lotto = [21,30,11,40,5,6];<br>System.out.println("</span><span>数组大小</span><span>:{sizeof lotto}");</span></p>
<p>&nbsp;</p>
<p><span>结果</span><span>: </span><span>数组大小</span><span>: 6</span></p>
<p><strong><span>您能使用</span></strong><strong><span> </span></strong><strong><span>[]</span></strong><strong><span> </span></strong><strong><span>操作符得到满足指定条件的子数组。条件放在</span></strong><strong><span> </span></strong><strong><span>[]</span></strong><strong><span> </span></strong><strong><span>中作为布尔判断</span></strong><strong><span> </span></strong><strong><span>。这个与</span></strong><strong><span>XPath </span></strong><strong><span>谓词相似</span></strong><strong><span>.</span></strong></p>
<p><strong><span>源码列表</span></strong><strong><span> 6</span></strong></p>
<p><span>//</span><span>使用</span><span>[] </span><span>操作符</span><span> -</span><span>与</span><span> XPath</span><span>相似</span></p>
<p><span>import java.lang.System;<br>var mynumbers = [1,2,7,3,30,15,14,6,4];<br>var numbers = mynumbers[n|n &lt; 10]; <br>System.out.println("</span><span>小于</span><span>10</span><span>的数字为</span><span>: {numbers}");</span></p>
<p>&nbsp;</p>
<p><span>结果</span><span>: </span><span>小于</span><span>10</span><span>的数字为</span><span>: 1 2 7 3 6 4<br></span><strong><span>你可以使用</span></strong><strong><span>indexof</span></strong><strong><span> </span></strong><strong><span>操作符得到指定序数位置的数组中一个元素<em>：</em></span></strong></p>
<p><strong><span>源码列表</span></strong><strong><span> 7</span></strong></p>
<p><span>//</span><span>返回指定序数位置的数组中的元素</span></p>
<p><span>import java.lang.System;</span></p>
<p><span>var mynumbers = [1,2,7,3,30,15,14,6,4]; <br>var number_four = mynumbers[indexof . == 4]; <br>System.out.println("</span><span>数字</span><span>4:{number_four}");</span></p>
<p>&nbsp;</p>
<p><span>结果</span><span>: </span><span>数字</span><span>4: 30<br><br></span><strong><span>当您想要向一个数组中插入一个元素时，你可以使用下列</span></strong><strong><span> </span></strong><strong><span>insert</span></strong><strong><span> </span></strong><strong><span>语句中的一个</span></strong><strong><em><span>:</span></em></strong></p>
<p><span><span>&#183;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>as first</span><span>: </span><span>在第一个位置插入</span></p>
<p><span><span>&#183;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>as last</span><span>:</span><span>在最后一个位置</span><span>(</span><span>默认</span><span>)</span><span>插入</span></p>
<p><span><span>&#183;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>before</span><span>: </span><span>在前一个位置插入</span></p>
<p><span><span>&#183;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>after</span><span>:</span><span>在下一个位置插入</span></p>
<p><strong><span>你可以使用</span></strong><strong><span> </span></strong><strong><span>delete</span></strong><strong><span> </span></strong><strong><span>语句从一个数组中删除一个元素</span></strong><strong><span>.</span></strong></p>
<p><strong><span>源码列表</span></strong><strong><span>8</span></strong></p>
<p><span>//</span><span>插入和删除语句</span><span><br>import java.lang.System;<br>var mynumbers = [1,2,7]; <br>System.out.println("Before inserting anything: {mynumbers}");<br>insert 10 into mynumbers;<br>System.out.println("After inserting at the end the \"10\" value:{mynumbers}");<br>insert [8,6,90] as first into mynumbers; <br>System.out.println("After inserting at the first positions the \"8,6,90\" values:{mynumbers}");<br>insert 122 as last into mynumbers;<br>System.out.println("After inserting at the end the \"122\" value:{mynumbers}");<br>insert 78 before mynumbers[3];<br>insert 11 after mynumbers[3];<br>System.out.println("After inserting the \"78\" and \"11\" values before/after the 3rd element:{mynumbers}");<br>delete mynumbers[. == 122];<br>System.out.println("After deleting:{mynumbers}");</span></p>
<p><span>结果</span><span>:<br>Before inserting anything: 1 2 7<br>After inserting the 10 value at the end: 1 2 7 10<br>After inserting the 8, 6, and 90 values at the first positions: 8 6 90 1 2 7 10<br>After inserting the 122 value at the end: 8 6 90 1 2 7 10 122<br>After inserting the 78 and 11 values before/after the 3rd element: 8 6 90 78 11 1 2 7 10 122<br>After deleting: 8 6 90 78 11 1 2 7 10</span></p>
<p><em><span>JavaFX</span></em><em><span>中的一个非常好的功能是</span></em><em><span>list</span></em><em><span>。这个功能使用</span></em><span> </span><span>select</span><span> </span><span>和</span><span> </span><span>foreach</span><span> </span><span>操作符实现。这有两个例子（一个使用</span><span> </span><span>select</span><span> </span><span>和使用</span><span> </span><span>foreach</span><em><span>) </span></em><em><span>得到指定间隔的奇数。</span></em></p>
<p><strong><span>源码列表</span></strong><strong><span>9</span></strong></p>
<p><span>//JavaFX</span><span>中的</span><span> select </span><span>和</span><span> foreach </span><span>操作符</span></p>
<p><span>import java.lang.System; <br>function odd(p:Number) <br>{ return select i from i in [1.0 ..p]<br>&nbsp;where (i%2 == 0.0); <br>}</span></p>
<p><span>var result = odd(10.0); <br>System.out.println("Odd numbers:{result}");</span></p>
<p><span>结果</span><span>: Odd numbers: 2.0 4.0 6.0 8.0 10.0</span></p>
<p><strong><span>源码列表</span></strong><strong><span>10 (</span></strong><strong><span>同</span></strong><strong><span> </span></strong><strong><span>源码列表</span></strong><strong><span> 9</span></strong><strong><span>相同</span></strong><strong><span>, </span></strong><strong><span>但是有</span></strong><strong><span> foreach)</span></strong></p>
<p><span>//JavaFX</span><span>中的</span><span>select </span><span>和</span><span> foreach </span><span>操作符</span></p>
<p><span>import java.lang.System; <br>function odd(p:Number) { <br><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return foreach (i in [1.0 ..p] <br><span>&nbsp;&nbsp;&nbsp;&nbsp; </span>where (i%2 == 0.0)) i; <br><span>&nbsp;&nbsp;&nbsp;&nbsp; </span>} <br>var result = odd(10.0);<br>System.out.println("Odd numbers:{result}");</span></p>
<p><strong><span>这个例子显示了</span></strong><strong><span> </span></strong><strong><span>foreach</span></strong><strong><span> </span></strong><strong><span>对于创建好的效果非常有用。</span></strong></p>
<p><strong><span>源码列表</span></strong><strong><span>11</span></strong></p>
<p><span>//JavaFX</span><span>中的</span><span> select </span><span>和</span><span> foreach </span><span>操作符</span></p>
<p><span>import java.lang.*;<br>import javafx.ui.*; <br>import javafx.ui.canvas.*;<br>Frame { <br>centerOnScreen: true <br>visible: true <br>height: 500 <br>width: 500 <br>title: "Foreach demo..." <br>onClose: operation() {<br>System.exit(0);<br>} <br>content: ScrollPane { <br>background: white <br>view: Canvas {<br>&nbsp;content: bind <br>foreach (i in [1..8], j in [1..8]) <br>Rect { x: i*30 y: j*30 width:30 height:30 fill: Color {red: (100+i) green: (100+j) blue: (100+(i*j))<br>} <br>stroke:white <br>strokeWidth:1 } }</span></p>
<p><span>}</span></p>
<p><span>}</span></p>
<p><span lang=EN-US style="FONT-SIZE: 10.5pt; COLOR: #003366; FONT-FAMILY: 'Times New Roman'; mso-fareast-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><v:shapetype id=_x0000_t75 stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600">&nbsp;<v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype><img height=248 alt="Running listing 11" src="http://www.onjava.com/onjava/2007/07/27/graphics/grill.gif" width=249></span><span><br></span><em><span>图四</span></em><em><span>. </span></em><em><span>运行源码列表</span></em><em><span> 11</span></em></p>
<p><em><span>使用双箭头括号引用为</span></em><em><span>JavaFX</span></em><em><span>关键字的变量名或者属性名，如下所示。</span></em></p>
<p><strong><span>源码列表</span></strong><strong><span> 12</span></strong></p>
<p><span>//</span><span>标志符引用</span></p>
<p><span>import java.lang.System;</span></p>
<p><span>for (&lt;&lt;for&gt;&gt; in [0..3]) {</span></p>
<p><span>System.out.println("for = {&lt;&lt;for&gt;&gt;}");</span></p>
<p><span>}</span></p>
<p><span>结果</span><span>: for = 0 for = 1 for = 2 for = 3</span></p>
<p><em><span>当你需要开发</span></em><em><span>Swing</span></em><em><span>接口时，</span></em><em><span>JavaFX </span></em><em><span>是一个伟大的工具，因为</span></em><em><span> JavaFX </span></em><em><span>考虑了非常多用来降低代码量和同</span></em><span>javax.swing.*</span><span>包</span><em><span>并存友好。在上一节（使用</span></em><em><span>NetBeans5.5</span></em><em><span>中的</span></em><em><span>JavaFX</span></em><em><span>插件测试</span></em><em><span>Hello World</span></em><em><span>应用程序），你看到了创建一个窗体是如何容易。这有两个更好的例子：创建按钮和文本框。</span></em></p>
<p><span>源码列表</span><span> 13</span></p>
<p><span>import javafx.ui.*;</span></p>
<p><span>import java.lang.System;</span></p>
<p><span>Frame{</span></p>
<p><span>content: Button { text: "Exit" action: operation() { System.exit(0); } }</span></p>
<p><span>visible: true</span></p>
<p><span>}</span></p>
<p><span lang=EN-US style="FONT-SIZE: 10.5pt; COLOR: #003366; FONT-FAMILY: 'Times New Roman'; mso-fareast-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><v:shapetype id=_x0000_t75 stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600">&nbsp;<v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype><img height=59 alt=" Running listing 13" src="http://www.onjava.com/onjava/2007/07/27/graphics/button.gif" width=125></span><span><br></span><em><span>图五</span></em><em><span>. </span></em><em><span>运行源码</span></em><em><span> 13</span></em></p>
<p><strong><span>源码列表</span></strong><strong><span>14</span></strong></p>
<p><span>import javafx.ui.*;</span></p>
<p><span>Frame {</span></p>
<p><span>content: GroupPanel { var myRow = Row { alignment: BASELINE }</span></p>
<p><span>var label_col = Column { alignment: TRAILING }</span></p>
<p><span>var field_col = Column { alignment: LEADING }</span></p>
<p><span>rows: [myRow] columns: [label_col, field_col]</span></p>
<p><span>content: [SimpleLabel { row: myRow column: label_col text: "Type your text here:" }, TextField { row: myRow column: field_col columns: 50 }] }</span></p>
<p><span>visible: true</span></p>
<p><span>};</span></p>
<p><span lang=EN-US style="FONT-SIZE: 10.5pt; COLOR: #003366; FONT-FAMILY: 'Times New Roman'; mso-fareast-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><v:shapetype id=_x0000_t75 stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600">&nbsp;<v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype><img height=76 alt="Running listing 14" src="http://www.onjava.com/onjava/2007/07/27/graphics/textfield.gif" width=539></span><span><br></span><em><span>图六</span></em><em><span>. </span></em><em><span>运行源码</span></em><em><span> 14</span></em></p>
<p><span>Java.net </span><span>也有使用</span><span>JavaFx</span><span>创建</span><span> <span><a href="https://openjfx.dev.java.net/Getting_Started_With_JavaFX.html"><span>Swing</span><span><span>接口</span></span></a></span></span><span>的教程。</span></p>
<p>&nbsp;</p>
<p><br>&nbsp;</p><img src ="http://www.blogjava.net/mlh123caoer/aggbug/134905.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-08-07 11:49 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/08/07/134905.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>基于Struts1.2.9框架的登录页面的处理过程</title><link>http://www.blogjava.net/mlh123caoer/archive/2007/08/03/134201.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Fri, 03 Aug 2007 03:36:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/08/03/134201.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/134201.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/08/03/134201.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/134201.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/134201.html</trackback:ping><description><![CDATA[<p>Struts Web框架是现在构建Web应用必须的开发框架之一。以下是我们学习Struts框架时通常都会看到的登录页面程序的处理流程分析，希望和广大博友交流：</p>
<br>
<p>基于Struts框架登录程序应用的UML顺序图<br><img title=Struts交互图 height=480 alt=Struts交互图 src="http://www.blogjava.net/images/blogjava_net/mlh123caoer/24610/r_struts%e4%ba%a4%e4%ba%92%e5%9b%be.jpg" width=640></p>
<p>处理步骤：</p>
<p>1、客户从浏览器客户端向Web服务器发出请求，服务器将请求转发到Web容器，比如：Tomcat；根据请求路径URL找到ActionServlet，Web容器调用Servlet的servic()方法，根据请求参数的不同调用doGet()或者doPost()方法。</p>
<p>2、而ActionServlet的doGet()或者doPost()方法调用process()方法处理请求和响应，生成RequestProcess对象处理配置文件struts-config.xml中的配置信息，依次调用processMapping()-查找处理此次请求的Action信息并返回ActionMapping对象；processActionForm()--创建此次请求的ActionForm对象；processActionCreate()--创建处理此次请求的Action实例（LoginAction对象）；processActionPerform()--执行Action实例的execute()方法。</p>
<p>3、通过调用execute()方法获取LoginForm存储的用户和密码等数据信息，其中将ActionForm Bean、ActionMapping、request、response对象传递给LoginAction对象（Action实例）；执行完必要的逻辑处理比如查询数据库后，返回一个ActionForward对象，由该对象调用RequestProcess对象中的processForwardConfig()方法解析配置文件中跳转参数，转发到相应的View页面success.jsp或者failure.jsp。</p>
<br><br><img src ="http://www.blogjava.net/mlh123caoer/aggbug/134201.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-08-03 11:36 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/08/03/134201.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA组件过滤器Filter</title><link>http://www.blogjava.net/mlh123caoer/archive/2007/07/25/132293.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Wed, 25 Jul 2007 05:56:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/07/25/132293.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/132293.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/07/25/132293.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/132293.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/132293.html</trackback:ping><description><![CDATA[<p>同servlet非常类似，Filter就是JAVA组件，请求发送到servlet前，可以使用过滤器Filter截获和处理请求，同时servlet结束以后，响应发回以前同样可以使用过滤器Filter处理响应。WEB容器可以用web.xml部署文件声明何时调用过滤器Filter。</p>
<p>过滤器Filter主要功能是：1、完成安全检查；2、重新格式化请求首部或体；3、建立请求审计或记录日志---请求过滤器Filter</p>
<p>1、压缩响应流；2、追加或者修改响应流；3、创建一个定制响应---响应过滤器Filter</p>
<p><br>同servlet一样，过滤器Filter也具有生命周期：init()-&gt;doFilter()-&gt;destroy().要实现模块化，FilterChain功不可末，它可以采用不同的方式组合过滤器，协调完成一些事情，它由部署文件中的filter元素驱动，和Filter都在javax.servlet包中。在servlet2.4中，过滤器同样可以用于请求分派器，但须在web.xml中声明，&lt;dispatcher&gt;INCLUDE或FORWARD或REQUEST或ERROR&lt;/dispatcher&gt;该元素位于filter-mapping中。</p>
<br>
<p>1、实现一個Filter，代码如下：</p>
<p><code><code>public class MyFilter implements Filter {</code></code></p>
<p><code><code>public void init(FilterConfig arg0) throws ServletException {</code></code></p>
<p><code>}<br></code></p>
<p><code>public void doFilter(ServletRequest request, ServletResponse response,<br>FilterChain chain) throws IOException, ServletException{</code></p>
<p><code><br>HttpServletRequest httpRequest = (HttpServletRequest) request;<br>HttpServletResponse httpResponse = (HttpServletResponse)response;<br>CachedResponseWrapper wrapper = new CachedResponseWrapper(httpResponse);<br>// 写入wrapper:<br>chain.doFilter(request, wrapper);<br>// 首先判断status, 只对200状态处理：<br>if(wrapper.getStatus()==HttpServletResponse.SC_OK) {<br>// 对响应进行处理，这里是进行GZip压缩:<br>byte[] data = GZipUtil.gzip(wrapper.getResponseData());<br>httpResponse.setContentType(getContentType());<br>httpResponse.setContentLength(data.length);<br>httpResponse.setHeader("Content-Encoding", "gzip");</code><code><br>ServletOutputStream output = response.getOutputStream();<br>output.write(data);<br>output.flush();<br>}<br>}<br></code></p>
<p><code>public void destroy() {</code></p>
<p><code>}</code></p>
<p><code>}</code></p>
<br>
<p>2、实现一个HttpServletResponseWrapper</p>
<p><code>public class CheckFrameHttpServletResponseWrapper extends<br>HttpServletResponseWrapper {</code></p>
<p><code>public CheckFrameHttpServletResponseWrapper(HttpServletResponse response) {</code></p>
<p><code>super(response);<br>}</code></p>
<p><code>public PrintWriter getWriter() throws IOException{<br>return new CheckFrameWriter(super.getWriter());<br>}</code></p>
<p><code>}</code></p>
<p>3、实现一个Writer</p>
<p><code>public class CheckFrameWriter extends PrintWriter {<br>String checkString = "&lt;script&gt;\n if(window.top.frames.length==0){\n"<br>+ "window.location.href=\"<a href="https://aix:9080/sso/mainlayout.faces">https://aix:9080/sso/mainlayout.faces</a>?"<br>+ "contentURL=http://aix:9080/security/paramsMaintain/"<br>+ "addParams.faces?roleId=0001\"\n" + "}\n&lt;/script&gt;\n";</code></p>
<p><code>public CheckFrameWriter(Writer out) {<br>super(out);<br>}</code></p>
<p><code>public void write(int c) {<br>super.write((char) c);<br>}</code></p>
<p><code>public void write(char buf[], int off, int len) {<br>StringBuffer sb = new StringBuffer(len);<br>for (int i = 0; i &lt; len; i++) {<br>sb.append(buf[off + i]);<br>}<br>String s = sb.toString();<br>int bodyIndex = s.indexOf("&lt;body&gt;");<br>if (bodyIndex &gt; -1) {<br>String part1 = s.substring(0, bodyIndex);<br>String part2 = s.substring(bodyIndex );<br>s = part1 + checkString + part2;<br>}<br>for (int i = 0; i &lt; s.length(); i++) {<br>write(s.charAt(i));<br>}<br>}</code></p>
<p><code>public void write(String s, int off, int len) {<br>for (int i = 0; i &lt; len; i++) {<br>write(s.charAt(off + i));<br>}<br>}<br>}</code></p>
<br>
<p>在Writer中，你便可以随心所欲的修改Response的內容了。</p>
<p>4、在Web.xml中加入相应的配置元素，对JSP进行拦截。</p><img src ="http://www.blogjava.net/mlh123caoer/aggbug/132293.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-07-25 13:56 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/07/25/132293.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JSP在TOMCAT中的处理生命周期</title><link>http://www.blogjava.net/mlh123caoer/archive/2007/07/14/130271.html</link><dc:creator>草儿</dc:creator><author>草儿</author><pubDate>Sat, 14 Jul 2007 06:43:00 GMT</pubDate><guid>http://www.blogjava.net/mlh123caoer/archive/2007/07/14/130271.html</guid><wfw:comment>http://www.blogjava.net/mlh123caoer/comments/130271.html</wfw:comment><comments>http://www.blogjava.net/mlh123caoer/archive/2007/07/14/130271.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/mlh123caoer/comments/commentRss/130271.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mlh123caoer/services/trackbacks/130271.html</trackback:ping><description><![CDATA[<div>1、将WEB应用部署到TOMCAT容器，容器启动读取应用的部署文件web.xml,但不对.jsp文件做任何处理请求。</div>
<div>2、客户点击连接请求某个.jsp文件，容器开始将.jsp文件转换为一个servrlet类的.java源代码。查看指令，得到转换的可能需要的信息。创建一个HttpServlet子类，对于Tomcat5所生成的servlet会扩展org.apache.jasper.runtime.HttpJspBase类。若有一个page指令有import属性，生成的类文件的最上面会写入import语句。例如在Tomcat5中加入包语句：package org.apache.jsp；若有声明容器将这些声明写道类文件，通常放在服务方法的下面。Tomca5声明了自己的一个静态方法和一个实例方法。然后建立服务方法，方法名为_jspService()。所生成的servlet会覆盖servlet超类的service()方法。_jspService()直接由service()调用，要接收HttpServletRequest和HttpServletResponse参数。在建立这个方法的时候，容器会声明并初始化所有的隐式对象。将普通的HTML（模板文件）、scrptlet和表达式放到服务方法里，进行格式化，并写至PrintWrite响应输出。</div>
<div>3、容器尝试将这个servlet.java源文件编译为.class文件。</div>
<div>4、容器家在新生成的servlet类。</div>
<div>5、容器实例化servlet，并导致servlet的jspInit()方法运行。对象现在已成为一个完整的servlet准备就绪，接受客户的请求。</div>
<div>6、容器创建一个新线程来处理客户请求，servlet的service()方法运行。以后的处理同普通的servlet处理过程。最终servlet向客户返回一个响应。</div>
<div>需要注意的是：在JSP生命周期中，JSP的转换和编译过程只发生一次。一旦第一次编译完成，以后的调用同普通的servlet一样。大多数容器开发商提供预转化和编译的办法，是这些工作提前完成。</div><img src ="http://www.blogjava.net/mlh123caoer/aggbug/130271.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mlh123caoer/" target="_blank">草儿</a> 2007-07-14 14:43 <a href="http://www.blogjava.net/mlh123caoer/archive/2007/07/14/130271.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>