﻿<?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-snowolf-随笔分类-学习</title><link>http://www.blogjava.net/snowolf/category/7078.html</link><description>        这样的一种生活</description><language>zh-cn</language><lastBuildDate>Thu, 29 Nov 2007 12:05:08 GMT</lastBuildDate><pubDate>Thu, 29 Nov 2007 12:05:08 GMT</pubDate><ttl>60</ttl><item><title>prototype.js常用函数及其用法</title><link>http://www.blogjava.net/snowolf/archive/2007/05/11/116896.html</link><dc:creator>snowolf</dc:creator><author>snowolf</author><pubDate>Fri, 11 May 2007 14:53:00 GMT</pubDate><guid>http://www.blogjava.net/snowolf/archive/2007/05/11/116896.html</guid><wfw:comment>http://www.blogjava.net/snowolf/comments/116896.html</wfw:comment><comments>http://www.blogjava.net/snowolf/archive/2007/05/11/116896.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/snowolf/comments/commentRss/116896.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/snowolf/services/trackbacks/116896.html</trackback:ping><description><![CDATA[&nbsp;prototype.js常用函数:
<table height=1194 cellSpacing=0 cellPadding=0 width=943 border=1>
    <tbody>
        <tr>
            <td width=208>函数名</td>
            <td width=385>&nbsp;解释</td>
            <td width=340>&nbsp;举例</td>
        </tr>
        <tr>
            <td>&nbsp;Element.toggle</td>
            <td>&nbsp;交替隐藏或显示</td>
            <td>&nbsp;Element.toggle(''div1'',''div2'')</td>
        </tr>
        <tr>
            <td>&nbsp;Element.hide</td>
            <td>&nbsp;隐藏</td>
            <td>&nbsp;Element.hide(''div1'',''div2'')</td>
        </tr>
        <tr>
            <td>&nbsp;Element.show</td>
            <td>显示</td>
            <td>&nbsp;Element.show(''div1'',''div2'')</td>
        </tr>
        <tr>
            <td>&nbsp;Element.remove</td>
            <td>&nbsp;删除</td>
            <td>&nbsp;Element.remove(''div1'',''div2'')</td>
        </tr>
        <tr>
            <td>&nbsp;Element.getHeight</td>
            <td>&nbsp;取得高度</td>
            <td>&nbsp;Element.getHeight(''div1'')</td>
        </tr>
        <tr>
            <td>&nbsp;Toggle.display</td>
            <td>&nbsp;和Element.toggle相同</td>
            <td>&nbsp;Toggle.display(''div1'',''div2'')</td>
        </tr>
        <tr>
            <td>&nbsp;Insertion.Before</td>
            <td>&nbsp;在DIV前插入文字</td>
            <td>&nbsp;Insertion.Before(''div1'',''my content'')</td>
        </tr>
        <tr>
            <td>&nbsp;Insertion.After</td>
            <td>&nbsp;在DIV后插入文字</td>
            <td>&nbsp;Insertion.After(''div1'',''my content'')</td>
        </tr>
        <tr>
            <td>&nbsp;Insertion.Top</td>
            <td>&nbsp;在DIV里最前插入文字</td>
            <td>&nbsp;Insertion.Top(''div1'',''this is a text'')</td>
        </tr>
        <tr>
            <td>&nbsp;Insertion.Bottom</td>
            <td>&nbsp;在DIV里最后插入文字</td>
            <td>&nbsp;Insertion.Bottom(''div1'',''this is a text'')</td>
        </tr>
        <tr>
            <td>&nbsp;PeriodicalExecuter</td>
            <td>&nbsp;以给定频率调用一段JavaScript</td>
            <td>&nbsp;PeridicalExecutor(test, 1)"这里test是Javascript的函数,1是频率(1秒).</td>
        </tr>
        <tr>
            <td>&nbsp;$</td>
            <td>&nbsp;取得一个DIV, 相当于getElementById()</td>
            <td>&nbsp;$(''div1'')</td>
        </tr>
        <tr>
            <td>&nbsp;Field.clear</td>
            <td>&nbsp;清空一个输入框</td>
            <td>&nbsp;Field.clear(''textfield1'')</td>
        </tr>
        <tr>
            <td>&nbsp;Field.focus</td>
            <td>把&nbsp;焦点集中在输入框上</td>
            <td>&nbsp;Field.focus(''select1'')</td>
        </tr>
        <tr>
            <td>&nbsp;Field.present</td>
            <td>&nbsp;判断内容是否为空</td>
            <td>&nbsp;alert(Field.present(''textfield1''))"</td>
        </tr>
        <tr>
            <td>&nbsp;Field.select</td>
            <td>&nbsp;选择输入框的内容</td>
            <td>&nbsp;Field.select(''textfield1'')"</td>
        </tr>
        <tr>
            <td>&nbsp;Field.activate</td>
            <td>&nbsp;把&nbsp;焦点集中在输入框上并选择输入框的内容</td>
            <td>&nbsp;Field.activate(''textfield1'')"</td>
        </tr>
        <tr>
            <td>&nbsp;Form.serialize</td>
            <td>&nbsp;把表格内容转化成string</td>
            <td>&nbsp;</td>
        </tr>
        <tr>
            <td>&nbsp;Form.getElements</td>
            <td>&nbsp;取得表格内容为数组形式</td>
            <td>&nbsp;</td>
        </tr>
        <tr>
            <td>&nbsp;Form.disable</td>
            <td>&nbsp;disable表格所有内容</td>
            <td>&nbsp;Form.disable(''form1'') (这个好象不work)</td>
        </tr>
        <tr>
            <td>&nbsp;Form.focusFirstElement</td>
            <td>&nbsp;把焦点集中在表格第一个元素上</td>
            <td>&nbsp;Form.focusFirstElement(''form1'')</td>
        </tr>
        <tr>
            <td>&nbsp;Form.reset</td>
            <td>&nbsp;Reset表格</td>
            <td>Form.reset(''form1'')</td>
        </tr>
        <tr>
            <td>&nbsp;Form.Element.getValue</td>
            <td>&nbsp;取得表格输入框的值</td>
            <td>&nbsp;Form.Element.getValue(''text1'')</td>
        </tr>
        <tr>
            <td>&nbsp;Form.Element.serialize</td>
            <td>&nbsp;&nbsp;把表格中输入框内容转化成string</td>
            <td>&nbsp;Form.Element.serialize(''text1'')</td>
        </tr>
        <tr>
            <td>&nbsp;$F</td>
            <td>&nbsp;等同于Form.Element.getValue()</td>
            <td>&nbsp;$F(''text1'')</td>
        </tr>
        <tr>
            <td>&nbsp;Effect.Highlight</td>
            <td>&nbsp;高亮特效.</td>
            <td>&nbsp;Effect.Highlight(''text1'')</td>
        </tr>
        <tr>
            <td>&nbsp;Effect.Fade</td>
            <td>&nbsp;褪色特效</td>
            <td>&nbsp;</td>
        </tr>
        <tr>
            <td>&nbsp;Effect.Scale</td>
            <td>&nbsp;放大缩小(百分比）</td>
            <td>
            <p>Effect.Scale(''text1'', 200)<br>这里200 = 200%, 即两倍</p>
            </td>
        </tr>
        <tr>
            <td>&nbsp;Effect.Squish</td>
            <td>&nbsp;消失特效．文字缩小后消失</td>
            <td>&nbsp;Effect.Squish(''text1'')</td>
        </tr>
        <tr>
            <td>&nbsp;Effect.Puff</td>
            <td>&nbsp;消失特效．文字放大后消失</td>
            <td>&nbsp;Effect.Puff(''text1'')</td>
        </tr>
        <tr>
            <td>&nbsp;Effect.Appear</td>
            <td>&nbsp;出现特效</td>
            <td>&nbsp;</td>
        </tr>
        <tr>
            <td>&nbsp;Effect.ContentZoom</td>
            <td>&nbsp;ZOOM特效．</td>
            <td>&nbsp;</td>
        </tr>
        <tr>
            <td>&nbsp;Ajax.Request</td>
            <td>&nbsp;传送Ajax请求给服务器</td>
            <td>&nbsp;Ajax.Request(''http://server/s.php'')</td>
        </tr>
        <tr>
            <td>&nbsp;Ajax.Updater</td>
            <td>&nbsp;传送Ajax请求给服务器并用答复的结果更新指定的Container</td>
            <td>&nbsp;Ajax.Updater(''text1'',''http://server/s.php'')</td>
        </tr>
    </tbody>
</table>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 基本用法:prototype.js给每个主要的类都分了一个Class,使用起来很方便.要产生特定的效果,只要用new Class.function(&lt;argument&gt;)就可以了.例如:</p>
<pre>&lt;DIV id="div1"&gt;&lt;a href="#" onclick="new Element.toggle('div2')"&gt;Click Me&lt;/a&gt;&lt;/DIV&gt;<br>
&lt;DIV id="div2"&gt;Hello!&lt;/DIV&gt;</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当点击Click Me的时候,div2就会交替隐藏或显示.注意,你可以给toggle加上无限个parameter,比如Element.toggle(''div2'',''div3'',''div4'',...)</p>
<img src ="http://www.blogjava.net/snowolf/aggbug/116896.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/snowolf/" target="_blank">snowolf</a> 2007-05-11 22:53 <a href="http://www.blogjava.net/snowolf/archive/2007/05/11/116896.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>prototype.js　1.4版开发者手册</title><link>http://www.blogjava.net/snowolf/archive/2007/05/11/116893.html</link><dc:creator>snowolf</dc:creator><author>snowolf</author><pubDate>Fri, 11 May 2007 14:47:00 GMT</pubDate><guid>http://www.blogjava.net/snowolf/archive/2007/05/11/116893.html</guid><wfw:comment>http://www.blogjava.net/snowolf/comments/116893.html</wfw:comment><comments>http://www.blogjava.net/snowolf/archive/2007/05/11/116893.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/snowolf/comments/commentRss/116893.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/snowolf/services/trackbacks/116893.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 开发者手册 对应版本1.4.0 original article by sp('Sergio Pereira') Sergio Pereiralast update: March 30th 2006中文版：THIN最后更新：2006-3-31&nbsp;看到一个很好的东西在国内没有被很多人使用起来，实在是不爽，所以花了很大功夫把这个手册翻译成中文，由于这篇文...&nbsp;&nbsp;<a href='http://www.blogjava.net/snowolf/archive/2007/05/11/116893.html'>阅读全文</a><img src ="http://www.blogjava.net/snowolf/aggbug/116893.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/snowolf/" target="_blank">snowolf</a> 2007-05-11 22:47 <a href="http://www.blogjava.net/snowolf/archive/2007/05/11/116893.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在MS SQL SERVER中取得表中最大自增长ID</title><link>http://www.blogjava.net/snowolf/archive/2006/08/03/61547.html</link><dc:creator>snowolf</dc:creator><author>snowolf</author><pubDate>Thu, 03 Aug 2006 09:38:00 GMT</pubDate><guid>http://www.blogjava.net/snowolf/archive/2006/08/03/61547.html</guid><wfw:comment>http://www.blogjava.net/snowolf/comments/61547.html</wfw:comment><comments>http://www.blogjava.net/snowolf/archive/2006/08/03/61547.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/snowolf/comments/commentRss/61547.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/snowolf/services/trackbacks/61547.html</trackback:ping><description><![CDATA[
		<h1>
				<a name="_ident_current(t-sql)">
				</a>
				<sup>
				</sup>
				<font size="4">IDENT_CURRENT</font>
		</h1>
		<p>返回为任何会话和任何作用域中的指定表最后生成的标识值。 </p>
		<h5>语法</h5>
		<p>IDENT_CURRENT<b>('</b><i>table_name</i><b>')</b></p>
		<h5>参数</h5>
		<p>
				<i>table_name</i>
		</p>
		<p class="indent">是将要返回其标识值的表的名称。<i>table_name</i> 的数据类型为 <b>varchar</b>，没有默认值。</p>
		<h5>返回类型</h5>
		<p>
				<strong>sql_variant<br /><br />--------------------------------------------------------------------------------------------------<br /></strong>
		</p>
		<h1>
				<a name="_scope_identity_(t-sql)">
				</a>
				<font size="4">SCOPE_IDENTITY</font>
		</h1>
		<p>返回插入到同一作用域中的 IDENTITY 列内的最后一个 IDENTITY 值。一个作用域就是一个模块——存储过程、触发器、函数或批处理。因此，如果两个语句处于同一个存储过程、函数或批处理中，则它们位于相同的作用域中。</p>
		<h5>语法</h5>
		<p>
				<code>SCOPE_IDENTITY( )</code>
		</p>
		<h5>返回类型</h5>
		<p>
				<strong>sql_variant<br /><br /></strong>IDENT_CURRENT 不受作用域和会话的限制，而受限于指定的表。<br /></p>
<img src ="http://www.blogjava.net/snowolf/aggbug/61547.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/snowolf/" target="_blank">snowolf</a> 2006-08-03 17:38 <a href="http://www.blogjava.net/snowolf/archive/2006/08/03/61547.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Tomcat配置技巧Top 10</title><link>http://www.blogjava.net/snowolf/archive/2006/06/13/52538.html</link><dc:creator>snowolf</dc:creator><author>snowolf</author><pubDate>Tue, 13 Jun 2006 09:49:00 GMT</pubDate><guid>http://www.blogjava.net/snowolf/archive/2006/06/13/52538.html</guid><wfw:comment>http://www.blogjava.net/snowolf/comments/52538.html</wfw:comment><comments>http://www.blogjava.net/snowolf/archive/2006/06/13/52538.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/snowolf/comments/commentRss/52538.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/snowolf/services/trackbacks/52538.html</trackback:ping><description><![CDATA[作者：Jason Brittain &amp; Ian F. Darwin<br />出处：http://www.orielly.com<br />译者：陈光<br />2003-12-31<br /><br />编者按：现在开发Java Web应用，建立和部署Web内容是一件很简单的工作。使用Jakarta Tomcat作为Servlet和JSP容器的人已经遍及全世界。Tomcat具有免费、跨平台等诸多特性，并且更新得很快，现在非常的流行。<br /><br />你所需要做的就是：按照你的需求配置Tomcat，只要你正确配置，Tomcat一般都能适合你的要求。下面是一系列关于Tomcat的配置技巧，这些技巧源自于我的书：《Tomcat权威指南》，希望对你有所帮助。—— Jason Brittain<br /><br />1． 配置系统管理（Admin Web Application）<br />大多数商业化的J2EE服务器都提供一个功能强大的管理界面，且大都采用易于理解的Web应用界面。Tomcat按照自己的方式，同样提供一个成熟的管理工具，并且丝毫不逊于那些商业化的竞争对手。Tomcat的Admin Web Application最初在4.1版本时出现，当时的功能包括管理context、data source、user和group等。当然也可以管理像初始化参数，user、group、role的多种数据库管理等。在后续的版本中，这些功能将得到很大的扩展，但现有的功能已经非常实用了。<br /><br />Admin Web Application被定义在自动部署文件：CATALINA_BASE/webapps/admin.xml 。<br />（译者注：CATALINA_BASE即tomcat安装目录下的server目录）<br /><br />你必须编辑这个文件，以确定Context中的docBase参数是绝对路径。也就是说，CATALINA_BASE/webapps/admin.xml 的路径是绝对路径。作为另外一种选择，你也可以删除这个自动部署文件，而在server.xml文件中建立一个Admin Web Application的context，效果是一样的。你不能管理Admin Web Application这个应用，换而言之，除了删除CATALINA_BASE/webapps/admin.xml ，你可能什么都做不了。<br /><br />如果你使用UserDatabaseRealm（默认），你将需要添加一个user以及一个role到CATALINA_BASE/conf/tomcat-users.xml 文件中。你编辑这个文件，添加一个名叫“admin”的role 到该文件中，如下：<br /><br />&lt;role name="admin"/&gt;<br /><br />你同样需要有一个用户，并且这个用户的角色是“admin”。象存在的用户那样，添加一个用户（改变密码使其更加安全）：<br /><br />&lt;user name="admin" password="deep_dark_secret" roles="admin"/&gt;<br /><br />当你完成这些步骤后，请重新启动Tomcat，访问http://localhost:8080/admin，你将看到一个登录界面。Admin Web Application采用基于容器管理的安全机制，并采用了Jakarta Struts框架。一旦你作为“admin”角色的用户登录管理界面，你将能够使用这个管理界面配置Tomcat。<br /><br />2．配置应用管理（Manager Web Application）<br />Manager Web Application让你通过一个比Admin Web Application更为简单的用户界面，执行一些简单的Web应用任务。<br /><br />Manager Web Application被被定义在一个自动部署文件中：<br /><br />CATALINA_BASE/webapps/manager.xml 。<br /><br />你必须编辑这个文件，以确保context的docBase参数是绝对路径，也就是说CATALINA_HOME/server/webapps/manager的绝对路径。<br />（译者注：CATALINA_HOME即tomcat安装目录）<br /><br />如果你使用的是UserDatabaseRealm，那么你需要添加一个角色和一个用户到CATALINA_BASE/conf/tomcat-users.xml文件中。接下来，编辑这个文件，添加一个名为“manager”的角色到该文件中：<br /><br />&lt;role name=”manager”&gt;<br /><br />你同样需要有一个角色为“manager”的用户。像已经存在的用户那样，添加一个新用户（改变密码使其更加安全）：<br /><br />&lt;user name="manager" password="deep_dark_secret" roles="manager"/&gt;<br /><br />然后重新启动Tomcat，访问http://localhost/manager/list，将看到一个很朴素的文本型管理界面，或者访问http://localhost/manager/html/list，将看到一个HMTL的管理界面。不管是哪种方式都说明你的Manager Web Application现在已经启动了。<br /><br />Manager application让你可以在没有系统管理特权的基础上，安装新的Web应用，以用于测试。如果我们有一个新的web应用位于/home/user/hello下在，并且想把它安装到 /hello下，为了测试这个应用，我们可以这么做，在第一个文件框中输入“/hello”（作为访问时的path），在第二个文本框中输入“file:/home/user/hello”（作为Config URL）。<br /><br />Manager application还允许你停止、重新启动、移除以及重新部署一个web应用。停止一个应用使其无法被访问，当有用户尝试访问这个被停止的应用时，将看到一个503的错误——“503 - This application is not currently available”。<br /><br />移除一个web应用，只是指从Tomcat的运行拷贝中删除了该应用，如果你重新启动Tomcat，被删除的应用将再次出现（也就是说，移除并不是指从硬盘上删除）。<br /><br />3．部署一个web应用<br />有两个办法可以在系统中部署web服务。<br />1&gt; 拷贝你的WAR文件或者你的web应用文件夹（包括该web的所有内容）到$CATALINA_BASE/webapps目录下。<br />2&gt; 为你的web服务建立一个只包括context内容的XML片断文件，并把该文件放到$CATALINA_BASE/webapps目录下。这个web应用本身可以存储在硬盘上的任何地方。<br /><br />如果你有一个WAR文件，你若想部署它，则只需要把该文件简单的拷贝到CATALINA_BASE/webapps目录下即可，文件必须以“.war”作为扩展名。一旦Tomcat监听到这个文件，它将（缺省的）解开该文件包作为一个子目录，并以WAR文件的文件名作为子目录的名字。接下来，Tomcat将在内存中建立一个context，就好象你在server.xml文件里建立一样。当然，其他必需的内容，将从server.xml中的DefaultContext获得。<br /><br />部署web应用的另一种方式是写一个Context XML片断文件，然后把该文件拷贝到CATALINA_BASE/webapps目录下。一个Context片断并非一个完整的XML文件，而只是一个context元素，以及对该应用的相应描述。这种片断文件就像是从server.xml中切取出来的context元素一样，所以这种片断被命名为“context片断”。<br /><br />举个例子，如果我们想部署一个名叫MyWebApp.war的应用，该应用使用realm作为访问控制方式，我们可以使用下面这个片断：<br /><br />&lt;!--  <br /> Context fragment for deploying MyWebApp.war  <br />--&gt;<br />&lt;Context path="/demo" docBase="webapps/MyWebApp.war" <br />        debug="0" privileged="true"&gt;<br /> &lt;Realm className="org.apache.catalina.realm.UserDatabaseRealm"                <br />        resourceName="UserDatabase"/&gt; <br />&lt;/Context&gt;<br /><br />把该片断命名为“MyWebApp.xml”，然后拷贝到CATALINA_BASE/webapps目录下。<br /><br />这种context片断提供了一种便利的方法来部署web应用，你不需要编辑server.xml，除非你想改变缺省的部署特性，安装一个新的web应用时不需要重启动Tomcat。<br /><br /><br />4．配置虚拟主机（Virtual Hosts）<br />关于server.xml中“Host”这个元素，只有在你设置虚拟主机的才需要修改。虚拟主机是一种在一个web服务器上服务多个域名的机制，对每个域名而言，都好象独享了整个主机。实际上，大多数的小型商务网站都是采用虚拟主机实现的，这主要是因为虚拟主机能直接连接到Internet并提供相应的带宽，以保障合理的访问响应速度，另外虚拟主机还能提供一个稳定的固定IP。<br /><br />基于名字的虚拟主机可以被建立在任何web服务器上，建立的方法就是通过在域名服务器（DNS）上建立IP地址的别名，并且告诉web服务器把去往不同域名的请求分发到相应的网页目录。因为这篇文章主要是讲Tomcat，我们不准备介绍在各种操作系统上设置DNS的方法，如果你在这方面需要帮助，请参考《DNS and Bind》一书，作者是Paul Albitz and Cricket Liu (O'Reilly)。为了示范方便，我将使用一个静态的主机文件，因为这是测试别名最简单的方法。<br />在Tomcat中使用虚拟主机，你需要设置DNS或主机数据。为了测试，为本地IP设置一个IP别名就足够了，接下来，你需要在server.xml中添加几行内容，如下：<br /><br />&lt;Server port="8005" shutdown="SHUTDOWN" debug="0"&gt;<br /> &lt;Service name="Tomcat-Standalone"&gt;<br />   &lt;Connector className="org.apache.coyote.tomcat4.CoyoteConnector"<br />port="8080" minProcessors="5" maxProcessors="75"<br />enableLookups="true" redirectPort="8443"/&gt;<br />   &lt;Connector className="org.apache.coyote.tomcat4.CoyoteConnector"<br />port="8443" minProcessors="5" maxProcessors="75"<br />acceptCount="10" debug="0" scheme="https" secure="true"/&gt;<br />     &lt;Factory className="org.apache.coyote.tomcat4.CoyoteServerSocketFactory"<br />clientAuth="false" protocol="TLS" /&gt;<br />   &lt;/Connector&gt;<br />   &lt;Engine name="Standalone" defaultHost="localhost" debug="0"&gt;<br />     &lt;!-- This Host is the default Host --&gt;<br />     &lt;Host name="localhost" debug="0" appBase="webapps"<br />     unpackWARs="true" autoDeploy="true"&gt;<br />       &lt;Context path="" docBase="ROOT" debug="0"/&gt;<br />       &lt;Context path="/orders" docBase="/home/ian/orders" debug="0"<br />                      reloadable="true" crossContext="true"&gt;<br />       &lt;/Context&gt;<br />     &lt;/Host&gt;<br /><br />     &lt;!-- This Host is the first "Virtual Host": www.example.com --&gt;<br />     &lt;Host name="www.example.com" appBase="/home/example/webapp"&gt;<br />       &lt;Context path="" docBase="."/&gt;<br />     &lt;/Host&gt;<br /><br />   &lt;/Engine&gt;<br /> &lt;/Service&gt;<br />&lt;/Server&gt;<br /><br />Tomcat的server.xml文件，在初始状态下，只包括一个虚拟主机，但是它容易被扩充到支持多个虚拟主机。在前面的例子中展示的是一个简单的server.xml版本，其中粗体部分就是用于添加一个虚拟主机。每一个Host元素必须包括一个或多个context元素，所包含的context元素中必须有一个是默认的context，这个默认的context的显示路径应该为空（例如，path=””）。<br /><br />5．配置基础验证（Basic Authentication）<br />容器管理验证方法控制着当用户访问受保护的web应用资源时，如何进行用户的身份鉴别。当一个web应用使用了Basic Authentication（BASIC参数在web.xml文件中auto-method元素中设置），而有用户访问受保护的web应用时，Tomcat将通过HTTP Basic Authentication方式，弹出一个对话框，要求用户输入用户名和密码。在这种验证方法中，所有密码将被以64位的编码方式在网络上传输。<br /><br />注意：使用Basic Authentication通过被认为是不安全的，因为它没有强健的加密方法，除非在客户端和服务器端都使用HTTPS或者其他密码加密码方式（比如，在一个虚拟私人网络中）。若没有额外的加密方法，网络管理员将能够截获（或滥用）用户的密码。但是，如果你是刚开始使用Tomcat，或者你想在你的web应用中测试一下基于容器的安全管理，Basic Authentication还是非常易于设置和使用的。只需要添加&lt;security-constraint&gt;和&lt;login-config&gt;两个元素到你的web应用的web.xml文件中，并且在CATALINA_BASE/conf/tomcat-users.xml 文件中添加适当的&lt;role&gt;和&lt;user&gt;即可，然后重新启动Tomcat。<br /><br />下面例子中的web.xml摘自一个俱乐部会员网站系统，该系统中只有member目录被保护起来，并使用Basic Authentication进行身份验证。请注意，这种方式将有效的代替Apache web服务器中的.htaccess文件。<br /><br />&lt;!--<br /> Define the Members-only area, by defining<br /> a "Security Constraint" on this Application, and<br /> mapping it to the subdirectory (URL) that we want<br /> to restrict.<br />--&gt;<br />&lt;security-constraint&gt;<br /> &lt;web-resource-collection&gt;<br />   &lt;web-resource-name&gt;<br />     Entire Application<br />   &lt;/web-resource-name&gt;<br />   &lt;url-pattern&gt;/members/*&lt;/url-pattern&gt;<br /> &lt;/web-resource-collection&gt;<br /> &lt;auth-constraint&gt;<br />     &lt;role-name&gt;member&lt;/role-name&gt;<br /> &lt;/auth-constraint&gt;<br />&lt;/security-constraint&gt;<br />&lt;!-- Define the Login Configuration for this Application --&gt;<br />&lt;login-config&gt;<br /> &lt;auth-method&gt;BASIC&lt;/auth-method&gt;<br /> &lt;realm-name&gt;My Club Members-only Area&lt;/realm-name&gt;<br />&lt;/login-config&gt;<br /><br />6．配置单点登录（Single Sign-On）<br />一旦你设置了realm和验证的方法，你就需要进行实际的用户登录处理。一般说来，对用户而言登录系统是一件很麻烦的事情，你必须尽量减少用户登录验证的次数。作为缺省的情况，当用户第一次请求受保护的资源时，每一个web应用都会要求用户登录。如果你运行了多个web应用，并且每个应用都需要进行单独的用户验证，那这看起来就有点像你在与你的用户搏斗。用户们不知道怎样才能把多个分离的应用整合成一个单独的系统，所有他们也就不知道他们需要访问多少个不同的应用，只是很迷惑，为什么总要不停的登录。<br /><br />Tomcat 4的“single sign-on”特性允许用户在访问同一虚拟主机下所有web应用时，只需登录一次。为了使用这个功能，你只需要在Host上添加一个SingleSignOn Valve元素即可，如下所示：<br /><br />&lt;Valve className="org.apache.catalina.authenticator.SingleSignOn"<br />      debug="0"/&gt;<br /><br />在Tomcat初始安装后，server.xml的注释里面包括SingleSignOn Valve配置的例子，你只需要去掉注释，即可使用。那么，任何用户只要登录过一个应用，则对于同一虚拟主机下的所有应用同样有效。<br /><br />使用single sign-on valve有一些重要的限制：<br />1&gt; value必须被配置和嵌套在相同的Host元素里，并且所有需要进行单点验证的web应用（必须通过context元素定义）都位于该Host下。<br />2&gt; 包括共享用户信息的realm必须被设置在同一级Host中或者嵌套之外。<br />3&gt; 不能被context中的realm覆盖。<br />4&gt; 使用单点登录的web应用最好使用一个Tomcat的内置的验证方式（被定义在web.xml中的&lt;auth-method&gt;中），这比自定义的验证方式强，Tomcat内置的的验证方式包括basic、digest、form和client-cert。<br />5&gt; 如果你使用单点登录，还希望集成一个第三方的web应用到你的网站中来，并且这个新的web应用使用它自己的验证方式，而不使用容器管理安全，那你基本上就没招了。你的用户每次登录原来所有应用时需要登录一次，并且在请求新的第三方应用时还得再登录一次。当然，如果你拥有这个第三方web应用的源码，而你又是一个程序员，你可以修改它，但那恐怕也不容易做。<br />6&gt; 单点登录需要使用cookies。<br /><br />7．配置用户定制目录（Customized User Directores）<br />一些站点允许个别用户在服务器上发布网页。例如，一所大学的学院可能想给每一位学生一个公共区域，或者是一个ISP希望给一些web空间给他的客户，但这又不是虚拟主机。在这种情况下，一个典型的方法就是在用户名前面加一个特殊字符（~），作为每位用户的网站，比如：<br /><br />http://www.cs.myuniversity.edu/~username<br />http://members.mybigisp.com/~username<br /><br />Tomcat提供两种方法在主机上映射这些个人网站，主要使用一对特殊的Listener元素。Listener的className属性应该是org.apache.catalina.startup.UserConfig，userClass属性应该是几个映射类之一。如果你的系统是Unix，它将有一个标准的/etc/passwd文件，该文件中的帐号能够被运行中的Tomcat很容易的读取，该文件指定了用户的主目录，使用PasswdUserDatabase 映射类。<br /><br />&lt;Listener className="org.apache.catalina.startup.UserConfig" <br />directoryName="public_html" <br />userClass="org.apache.catalina.startup.PasswdUserDatabase"/&gt;<br /><br />web文件需要放置在像/home/users/ian/public_html 或者 /users/jbrittain/public_html一样的目录下面。当然你也可以改变public_html 到其他任何子目录下。<br /><br />实际上，这个用户目录根本不一定需要位于用户主目录下里面。如果你没有一个密码文件，但你又想把一个用户名映射到公共的像/home一样目录的子目录里面，则可以使用HomesUserDatabase类。<br /><br />&lt;Listener className="org.apache.catalina.startup.UserConfig" <br />directoryName="public_html" homeBase="/home" <br />userClass="org.apache.catalina.startup.HomesUserDatabase"/&gt;<br /><br />这样一来，web文件就可以位于像/home/ian/public_html 或者 /home/jasonb/public_html一样的目录下。这种形式对Windows而言更加有利，你可以使用一个像c:\home这样的目录。<br /><br />这些Listener元素，如果出现，则必须在Host元素里面，而不能在context元素里面，因为它们都用应用于Host本身。<br /><br /><br />8．在Tomcat中使用CGI脚本<br />Tomcat主要是作为Servlet/JSP容器，但它也有许多传统web服务器的性能。支持通用网关接口（Common Gateway Interface，即CGI）就是其中之一，CGI提供一组方法在响应浏览器请求时运行一些扩展程序。CGI之所以被称为通用，是因为它能在大多数程序或脚本中被调用，包括：Perl，Python，awk，Unix shell scripting等，甚至包括Java。当然，你大概不会把一个Java应用程序当作CGI来运行，毕竟这样太过原始。一般而言，开发Servlet总要比CGI具有更好的效率，因为当用户点击一个链接或一个按钮时，你不需要从操作系统层开始进行处理。<br /><br />Tomcat包括一个可选的CGI Servlet，允许你运行遗留下来的CGI脚本。<br /><br />为了使Tomcat能够运行CGI，你必须做如下几件事：<br />1. 把servlets-cgi.renametojar （在CATALINA_HOME/server/lib/目录下）改名为servlets-cgi.jar。处理CGI的servlet应该位于Tomcat的CLASSPATH下。<br />2. 在Tomcat的CATALINA_BASE/conf/web.xml 文件中，把关于&lt;servlet-name&gt; CGI的那段的注释去掉（默认情况下，该段位于第241行）。<br />3. 同样，在Tomcat的CATALINA_BASE/conf/web.xml文件中，把关于对CGI进行映射的那段的注释去掉（默认情况下，该段位于第299行）。注意，这段内容指定了HTML链接到CGI脚本的访问方式。<br />4. 你可以把CGI脚本放置在WEB-INF/cgi 目录下（注意，WEB-INF是一个安全的地方，你可以把一些不想被用户看见或基于安全考虑不想暴露的文件放在此处），或者你也可以把CGI脚本放置在context下的其他目录下，并为CGI Servlet调整cgiPathPrefix初始化参数。这就指定的CGI Servlet的实际位置，且不能与上一步指定的URL重名。<br />5. 重新启动Tomcat，你的CGI就可以运行了。<br /><br />在Tomcat中，CGI程序缺省放置在WEB-INF/cgi目录下，正如前面所提示的那样，WEB-INF目录受保护的，通过客户端的浏览器无法窥探到其中内容，所以对于放置含有密码或其他敏感信息的CGI脚本而言，这是一个非常好的地方。为了兼容其他服务器，尽管你也可以把CGI脚本保存在传统的/cgi-bin目录，但要知道，在这些目录中的文件有可能被网上好奇的冲浪者看到。另外，在Unix中，请确定运行Tomcat的用户有执行CGI脚本的权限。<br /><br />9．改变Tomcat中的JSP编译器（JSP Compiler）<br />在Tomcat 4.1（或更高版本，大概），JSP的编译由包含在Tomcat里面的Ant程序控制器直接执行。这听起来有一点点奇怪，但这正是Ant有意为之的一部分，有一个API文档指导开发者在没有启动一个新的JVM的情况下，使用Ant。这是使用Ant进行Java开发的一大优势。另外，这也意味着你现在能够在Ant中使用任何javac支持的编译方式，这里有一个关于Apache Ant使用手册的javac page列表。使用起来是容易的，因为你只需要在&lt;init-param&gt; 元素中定义一个名字叫“compiler”，并且在value中有一个支持编译的编译器名字，示例如下：<br /><br />&lt;servlet&gt;<br />   &lt;servlet-name&gt;jsp&lt;/servlet-name&gt;<br />   &lt;servlet-class&gt;<br />     org.apache.jasper.servlet.JspServlet<br />   &lt;/servlet-class&gt;<br />   &lt;init-param&gt;<br />     &lt;param-name&gt;logVerbosityLevel&lt;/param-name&gt;<br />     &lt;param-value&gt;WARNING&lt;/param-value&gt;<br />   &lt;/init-param&gt;<br />   &lt;init-param&gt;<br />     &lt;param-name&gt;compiler&lt;/param-name&gt;<br />     &lt;param-value&gt;jikes&lt;/param-value&gt;<br />   &lt;/init-param&gt;<br />   &lt;load-on-startup&gt;3&lt;/load-on-startup&gt;<br />&lt;/servlet&gt;<br /><br />当然，给出的编译器必须已经安装在你的系统中，并且CLASSPATH可能需要设置，那处决于你选择的是何种编译器。<br /><br />10．限制特定主机访问（Restricting Access to Specific Hosts）<br />有时，你可能想限制对Tomcat web应用的访问，比如，你希望只有你指定的主机或IP地址可以访问你的应用。这样一来，就只有那些指定的的客户端可以访问服务的内容了。为了实现这种效果，Tomcat提供了两个参数供你配置：RemoteHostValve 和RemoteAddrValve。<br /><br />通过配置这两个参数，可以让你过滤来自请求的主机或IP地址，并允许或拒绝哪些主机/IP。与之类似的，在Apache的httpd文件里有对每个目录的允许/拒绝指定。<br />例如你可以把Admin Web application设置成只允许本地访问，设置如下：<br /><br />&lt;Context path="/path/to/secret_files" ...&gt;<br /> &lt;Valve className="org.apache.catalina.valves.RemoteAddrValve"<br />        allow="127.0.0.1" deny=""/&gt;<br />&lt;/Context&gt;<br /><br />如果没有给出允许主机的指定，那么与拒绝主机匹配的主机就会被拒绝，除此之外的都是允许的。与之类似，如果没有给出拒绝主机的指定，那么与允许主机匹配的主机就会被允许，除此之外的都是拒绝的。<br /><br />--------------------------------------<br /><br />作者简介：<br />Jason Brittain是CollabNet公司的一名资深软件工程师，主要负责软件底层架构的开发。他已经为Apache Jakarta项目做了很多贡献，多年以来，他一直是一名积极的开源软件开发者。<br /><br />Ian F. Darwin已经在计算机行业工作了30年：从1980年开始使用Unix，从1995年开始使用Java，从1998年开始使用OpenBSD。他是两本Oreilly图书的作者：Checking C Programs with lint 和 Java Cookbook，还与Jason Brittain合著了Tomcat: The Definitive Guide。<br /><br />译者简介：<br />陈光（Holen Chen），J2EE项目经理，熟悉知识管理及电子政务，致力于Apache Jakarta项目在国广的推广及深层次应用，可通过 holen@263.net与作者联系。<img src ="http://www.blogjava.net/snowolf/aggbug/52538.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/snowolf/" target="_blank">snowolf</a> 2006-06-13 17:49 <a href="http://www.blogjava.net/snowolf/archive/2006/06/13/52538.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>基于AJAX的动态树型结构的设计与实现</title><link>http://www.blogjava.net/snowolf/archive/2006/06/13/52537.html</link><dc:creator>snowolf</dc:creator><author>snowolf</author><pubDate>Tue, 13 Jun 2006 09:48:00 GMT</pubDate><guid>http://www.blogjava.net/snowolf/archive/2006/06/13/52537.html</guid><wfw:comment>http://www.blogjava.net/snowolf/comments/52537.html</wfw:comment><comments>http://www.blogjava.net/snowolf/archive/2006/06/13/52537.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/snowolf/comments/commentRss/52537.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/snowolf/services/trackbacks/52537.html</trackback:ping><description><![CDATA[作者：佚名  来源：转载<br /><br /><div class="ContentFont" id="NewaspContentLabel" style="PADDING-RIGHT: 10px; DISPLAY: block; PADDING-LEFT: 10px; PADDING-BOTTOM: 0px; PADDING-TOP: 0px"><font id="font_word" style="FONT-SIZE: 14px; FONT-FAMILY: 宋体, Verdana, Arial, Helvetica, sans-serif"><p><font size="3">　树型结构是一类应用非常广泛的数据结构。人类社会中宗族的族谱和现代企业的组织形式都是树型结构。在计算机领域中,文件系统中文件的管理结构、存储器管理中的页表、数据库中的索引等也都是树型结构。随着Internet的飞速发展，树型结构在浏览器/服务器（Browser/Server，简称B/S）应用系统的应用也越来越广泛。 <br /><br />　　目前，在互联网上广泛存在、应用的树型结构一般分为两种：静态和动态结构。静态结构存在最多、实现简单，但是静态导致不能改变树的结构和内容，无法反映树的节点信息的变化；而实现相对复杂的动态构造树，虽然可以动态增加、删除、更新节点信息，但是大部分不能直接拖放节点来改变树的结构以及节点间的次序，并且反复刷新整个页面，给用户维护带来了许多不便。本文提出了一种基于Ajax（Asynchronous JavaScript and XML）通用的、动态加载节点的解决方案。实现上采用J2EE多层架构，树节点的描述信息采用数据库存储，以可扩展标记语言（eXtensible Markup Language，简称XML）展现给JavaScript解析，支持无刷新地增加、删除、更新节点信息，以及拖放节点来改变树的结构和节点间的次序。文中第1部分简要介绍了Ajax技术；第2部分详细介绍了该方案的技术实现过程；第3部分分析了该方案的效率。<br /><br /><b>　　1、Ajax简介</b><br /><br />　　Ajax概念的最早提出者Jesse James Garrett认为：Ajax并不是一门新的语言或技术，它实际上是几项技术按一定的方式组合在共同的协作中发挥各自的作用，它包括：<br /><br />　　·使用扩展超媒体标记语言（eXtended Hypertext Markup Language，简称XHTML）和级联样式单（Cascading Style Sheet，简称CSS）标准化呈现；<br /><br />　　·使用文档对象模型（Document Object Model，简称DOM）实现动态显示和交互；<br /><br />　　·使用可扩展标记语言（eXtensible Markup Language，简称XML）和可扩展样式表转换（eXtensible Stylesheet Language Transformation，简称XSLT）进行数据交换与处理；<br /><br />　　·使用XMLHTTP组件XMLHttpRequest对象进行异步数据读取；<br /><br />　　·最后用JavaScript绑定和处理所有数据。<br /><br />　　Ajax的工作原理如图1所示，它相当于在用户和服务器之间加了一个中间层，使用户操作与服务器响应异步化。并不是所有的用户请求都提交给服务器，像—些数据验证和数据处理等都交给Ajax引擎处理，只有确定需要从服务器读取新数据时再由Ajax引擎代为向服务器提交请求。这样就把一些服务器负担的工作转嫁到客户端，利用客户端闲置的处理能力来处理，减轻服务器和带宽的负担，从而达到节约ISP的空间及带宽租用成本的目的。<br /><br /><table width="90%" align="center" border="0"><tbody><tr><td><div><img src="http://java.chinaitlab.com/UploadFiles_8734/200512/20051229100108136.gif" onload="return imgzoom(this,550)" border="0" /><br />图 1 未使用Ajax（a）和使用Ajax（b）的web应用比较</div></td></tr></tbody></table><br /><b>　　2、总体设计方案</b><br /><br />　　传统的服务器程序采用Model 1开发模型，通常将业务逻辑、服务器端处理过程和HTML代码集中在一起表示，快速完成应用开发。Model 1 在小规模应用开发时优势明显，但是应用实现一般是基于过程的，一组服务器页面实现一个流程，如果流程改动将导致多个地方修改，非常不利于应用的扩展和更新。此外业务逻辑和表示逻辑混合在服务器页面中，耦合紧密，无法模块化，导致代码无法复用。<br /><br />　　Model 2则解决了这些问题，它是面向对象的MVC模式（Model-View-Controller，模型-视图-控制器）在Web开发中的应用，Model表示应用的业务逻辑，View是应用的表示层页面，Controller是提供应用的处理过程控制。通过这种MVC设计模式把应用逻辑，处理过程和显示逻辑划分成不同的组件、模块实现，组件间可以进行交互和重用。<br /><br />　　本方案是采用J2EE的多层架构，设计时结合Struts框架将表示层、业务逻辑层和数据层划分成不同的模块。表示层专注于树的外观显示，业务逻辑层为服务器端处理程序，处理树的生成、变化，为减少耦合性，该程序全部模块化实现，不在表示页面嵌入服务器程序；模型层是数据的存储和表示。下面分别介绍各层实现。<br /><br /><b>　　2.1 表示层实现</b><br /><br />　　类似<a class="wordstyle" href="http://www.newasp.cn/" target="_blank">Windows</a>资源管理器的文件夹模式，节点的图片样式如表1所示。对于每个节点的DHTML 代码，需要包含节点的位置、前导图片、样式、针对该节点的其他操作等。同时为了节点显示的连贯性，还需一些前导图片。<br /><br />　　表1 树节点的前的图片样式表<br /><br /><table width="90%" align="center" border="0"><tbody><tr><td><div><img src="http://java.chinaitlab.com/UploadFiles_8734/200512/20051229100108564.gif" onload="return imgzoom(this,550)" border="0" /></div></td></tr></tbody></table><br />　 对于树的非叶子节点，图片和节点信息等，采用一个DIV ( division) 容器包含。DIV 等容器是DHTML 的基础，使用它可以通过脚本程序对其属性进行操作，如设置其style 样式的display 属性来控制子节点的展开和隐藏。节点的位置、前导图片、样式、针对该节点的其他的操作等都放入容器中，例：<br />＜ DIV id =mParentID＞<br />＜ IMG align = center border = 0 onclick =″nodeExpand (‘leafid’)″ name = m1Tree src =′Tplus.gif′＞<br />＜ IMG align = center border = 0 name = m1Folder src =′folderClosed. gif′＞ 计算机学院 ＜/DIV＞<br /><br />　　叶子节点无需容器直接输出即可。<br /><br />　　当点击某节点前的“ + ”、“ - ”图片时通过DIV 的style 样式的display 属性控制子节点的展开和隐藏。display：“none”(隐藏,不可见)，display：“block”(显示) 。相关JavaScript 代码如下：<br />if (expandChild.style.display = =″none″){<br />　// 当前为隐藏状态,执行展开动作<br />　this.Loading(parentObject);//判断该分支的数据是否已经加载<br />　expandChild.style.display =″block″;<br />if (para2 = =″last″)<br />　parentObject.src =″Lminus. gif″; // 最后一个节点<br />else<br />　parentObject.src = ″Tminus. gif″; // 显示┠<br />　expandFolder.src = ″folderOpen. gif″;<br />}else {<br />　// 将当前节点的子节点全部隐藏<br />　expandChild.style.display = ″none″;<br />　if (para2 = = ″last″)<br />　　parentObject.src = ″Lplus. gif″;<br />　else<br />　　parentObject.src = ″Tplus. gif″;<br />　　expandFolder.src = ″folderClosed. gif″;<br />}<br /><br /><b>　　2.2 树型表结构设计</b><br /><br />　　我们以数据库为载体记录节点的变化，树型表结构至少要有以下字段：节点的编号(CLASSID) ,对节点的描述(ClassName)，父节点的编号(ParentId)，这些是构建树结构所必须的信息。同时引入节点的类别代码（ClassCode），节点的级别（ClassLevel），是否叶子节点 (Terminated)等辅助字段，记录节点次序，实体关系图如图3所示。<br /><br /><table width="90%" align="center" border="0"><tbody><tr><td><div><img src="http://java.chinaitlab.com/UploadFiles_8734/200512/20051229100108927.gif" onload="return imgzoom(this,550)" border="0" /><br />图 3 树型表结构示意图</div></td></tr></tbody></table><div>　　树遍历的时间复杂度是O( <i>n </i>)，但是将树信息存放到数据库后，就不能按传统的方式遍历树，必须使用SQL 语句访问数据库表的内容，而一次性取的数据量越多，消耗的资源也越多，用户等待的时间就越长。如果将无序的数据从数据库中读出，在服务器端，必须将排序后的树送到客户端显示。因此，最好从数据库读出已排好序的树。<br /><br />　　我们知道，字符串排序是按照字典序形式。结合SQL 语句的特点和树结构特点，数据库表中，节点的类别代码采用多级字符串形式，如AAABBBCCC，从树根节点开始，每向下一级字符串就增加一级，并且子节点类别代码以父节点类别代码开始，再开始本级的类别代码。同级的节点按照生成的顺序编号，如节点类别代码为AAA 的下一级孩子类别代码为AAAAAA，AAAAAB 等，AAAAAB 的孩子节点为AAAAABAAA、AAAAABAAB等。每一级编号字符的宽度与实际的应用关联，如AAA～ZZZ 一级则有263 个节点，如果不够用再增加一个字符用于编码。该巧妙的编号方式。使得在执行SQL 语句select * from tree_class order by classcode 后，一次获得完整的先序树。</div><div><br />　　2.3.1 动态加载技术<br /><br />　　如果一次性获取完整的先序树，构造成xml提供给JavaScript解析，数据量越大，消耗的资源越多，客户端响应延迟时间就越长，因此对于大数据量的树，采用动态加载方式，即每次单击“+”图片时，判断是否已加载子节点数据，如果未加载则通过Ajax的XMLHTTP组件XMLHTTPRequest对象异步发送请求，连接服务器执行SQL 语句“select * from tree_class where parent = ？order by classcode ”获取节点数据。相关JavaScript 代码如下：<br />/*判断是否已经加载数据，未加载则访问服务器加载数据*/ 
<div><p>dhtmlTree.prototype.Loading=function(pObject){<br />　if(((pObject.XMLload==0)&amp;&amp;(this.XMLsource))&amp;&amp;(!this.XMLloading)){<br />　　pObject.XMLload=1;<br />　　this.loadXML(this.XMLsource+getUrlSymbol(this.XMLsource)+"id="+escape(pObject.id));<br />　}<br />}<br />dtmlXMLObject.prototype.loadXML=function(url){//加载数据<br />　try {<br />　　this.xmlDoc = new XMLHttpRequest();<br />　　/*通过GET方法异步连接到 url 加载数据*/<br />　　this.xmlDoc.open("GET", url,true);//true：异步；false：同步<br />　　this.xmlDoc.send(null);<br />　} catch(e){<br />　　this.xmlDoc = new ActiveXObject("Microsoft.XMLHTTP");//使用IE<br />　　this.xmlDoc.open("GET", url,true);//true：异步；false：同步<br />　　this.xmlDoc.send(null);<br />　}<br />　return this.xmlDoc.responseXML;<br />}<br /><br />　　每次只取同一个父节点ParentId的子节点序列，按XML格式封装成树的文档结构，例如：<br />＜tree id="0"＞<br />＜leaf child=”1" name="国防科技大学" id="1" im0="leaf.gif" im1="folderOpen.gif" im2=" folderClosed.gif"/＞<br />＜/tree＞<br /></p><p>　　提供给JavaScript的dhtmlTreeObject.prototype.insertItem（）解析并组织好html输出节点；其中child：1表示有子节点，0表示没有子节点；im0表示没有子节点时的图标；im1表示有子节点并且打开节点时的图标；im2表示有子节点并且关闭时的图标；所以还可以在构造XML时自定义图标。<br /><br />　　2.3.2 树型结构的构造<br /><br />　　从数据库中返回的是有序的先序树，而XML是完整的树型结构文档，所以将树型数据构造成预定义的XML格式，只需从根节点开始，遍历一遍树，即可将树全部生成。相关JavaScript代码如下：<br />/*动态加载树的构造方法*/</p><p>dtmlXMLObject.prototype.constructTree=function(){</p><p>//采用动态加载时获取的xml数据，解析树型数据</p><p>var node=this.XMLLoader.getXMLTopNode("tree");</p><p>var parentId=node.getAttribute("id");</p><p>for(var i=0;i＜node.childNodes.length;i++) { //逐个解析xml文件的leaf节点</p><p>　if((node.childNodes[i].nodeType==1)&amp;&amp;(node.childNodes[i].tagName == "leaf")){<br />　　var name=node.childNodes[i].getAttribute("text");<br />　　…………<br />　　var temp=dhtmlObject.a0Find(parentId);//获取父节点对象<br />　　temp.XMLload=1;//已加载<br />　　//构造html输出节点<br />　　dhtmlObject.insertItem(parentId,cId,name,im0,im1,im2,chd);<br />　　dhtmlObject.addDragger = this;//设置可拖放的对象<br />　};<br />}<br /><br />　　2.3.3 树型结构的维护<br /><br />　　在维护树型结构表时,删除节点较为简单，SQL 语句为: "delete from tree_class where classcode like′"+ classcode +"%′",即可将其节点和孩子一并删除；增加节点时,分为前插、后插、和插入子节点三种情况，前两种情况需要更新递归更新类别代码，后者只需找到父节点的孩子的最大类别代码加1 后,作为增加节点的类别代码；通过拖放来改变树的结构时，只需将拖动节点的parentId更新为目标节点的Classid即可，对应的SQL语句为："update tree_class set parentId = "+ classidTo+" where classid = "+ classidFrom。<br /><br /><b>　　3、效率分析</b><br /><br />　　对于树的存储一般有两种形式：二维表和链表，遍历方式一般也有深度遍历和广度遍历两种方式，遍历的时间复杂度都是O( <i>n </i>)。用二维表存储时，在内存中用数组的下标能准确定位节点的父节点、兄弟节点所在的数组下标。数据库中节点的定位也是准确的，但是将节点信息从数据库中读到内存中时，如果无法通过内存数组下标定位节点信息，那么就必须遍历一遍寻找一个节点，<i>n </i>个节点中寻找一个节点的时间是O(<i>n/</i>2)，<i>n </i>个节点排序的时间复杂度将是O( <i>n<sup></sup></i><sup>2</sup>/2)，这也是一般实现的B/S 模式的树结构效率低下的原因。本方案采用字典序编号方案，使得从数据库中取得的树是已经排序的，直接遍历生成客户页面程序，时间复杂度为O( <i>n </i>)。 <br /><br /><b>　　4、结 论</b><br /><br />　　本文讨论了基于Ajax的动态树型结构的实现方案，支持无刷新动态维护树的节点信息，支持拖放节点改变树的节点结构以及次序；同时采用数据库存储节点信息，保证了该方案有一定的通用性，此外结合XML描述树的节点信息，使得任何按本方案预定的xml文档描述的信息都可以通过树来展现。本方案已经应用在我校的数字迎新系统以及老百姓大药房信息系统中。</p></div></div></font></p></font></div><img src ="http://www.blogjava.net/snowolf/aggbug/52537.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/snowolf/" target="_blank">snowolf</a> 2006-06-13 17:48 <a href="http://www.blogjava.net/snowolf/archive/2006/06/13/52537.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>精确截取字符串（转载） </title><link>http://www.blogjava.net/snowolf/archive/2006/06/13/52369.html</link><dc:creator>snowolf</dc:creator><author>snowolf</author><pubDate>Tue, 13 Jun 2006 02:46:00 GMT</pubDate><guid>http://www.blogjava.net/snowolf/archive/2006/06/13/52369.html</guid><wfw:comment>http://www.blogjava.net/snowolf/comments/52369.html</wfw:comment><comments>http://www.blogjava.net/snowolf/archive/2006/06/13/52369.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/snowolf/comments/commentRss/52369.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/snowolf/services/trackbacks/52369.html</trackback:ping><description><![CDATA[开发中经常遇到，字符串过长，无法完全显示的问题<br /><br />这时候就需要截取我们所需要的长度，后面显示省略号或其他字符。<br /><br />由于中文字符占两个字节，而英文字符占用一个字节，所以，单纯地判断字符数，效果往往不尽如人意<br /><br />下面的方法通过判断字符的类型来进行截取，效果还算可以：）<br /><br /><br />如果大家有其他的解决方法欢迎贴出来，共同学习：）<br />**********************************************************************<br />private String str;<br />private int counterOfDoubleByte;<br />private byte b[];<br />/**<br />* 设置需要被限制长度的字符串<br />* @param str 需要被限制长度的字符串<br />*/<br />public void setLimitLengthString(String str){<br />  this.str = str;<br />}<br />/**<br />* @param len 需要显示的长度(&lt;font color="red"&gt;注意：长度是以byte为单位的，一个汉字是2个byte&lt;/font&gt;)<br />* @param symbol 用于表示省略的信息的字符，如“...”,“&gt;&gt;&gt;”等。<br />* @return 返回处理后的字符串<br />*/<br />public String getLimitLengthString(int len, String symbol) throws UnsupportedEncodingException {<br />  counterOfDoubleByte = 0;<br />  b = str.getBytes("GBK");<br />  if(b.length &lt;= len)<br />    return str;<br />  for(int i = 0; i &lt; len; i++){<br />    if(b[i] &lt; 0)<br />      counterOfDoubleByte++;<br />  }<br /><br />  if(counterOfDoubleByte % 2 == 0)<br />    return new String(b, 0, len, "GBK") + symbol;<br />  else<br />    return new String(b, 0, len - 1, "GBK") + symbol;<br />}<br /><br /><br /><font color="#ff0000" size="2"><strong>本文转贴自网友：focus2004 的文章<br /><br /><a title="permalink: re: 精确截取字符串（转载）" href="/rosen/archive/2005/08/12/9949.html#29339"><font color="#000080">#</font></a><font color="#000000"> </font><a name="29339"></a><font color="#000000">re: 精确截取字符串（转载） <span>2006-01-28 18:24 </span></font><a id="Comments1_CommentList_ctl02_NameLink" href="http://fstdg2003@21cn.com/" target="_blank"><font color="#000080">tdg</font></a><br /></strong><font color="#000000">大作拜读，有一点愚见，特抛砖引玉： <br />1。字符串除了可以基于byte[]操作外，还可以基于char[]操作。看老大你的意图是想截取字符串的前几个字符然后加上省略符号最后输出而已，完全不必考虑用byte[]数组操作啊 。而且好像开发中更注重语义上的第几个字符而不是你说的这种情况哦。 <br />2。以下是拙作，请斧正： <br />/** <br />* 字符串截取函数 <br />* @param str String 要处理的字符串 <br />* @param length int 需要显示的长度 <br />* @param symbol String 用于表示省略的信息的字符，如“...”,“&gt;&gt;&gt;”等 <br />* @return String 返回处理后的字符串 <br />* @throws UnsupportedEncodingException <br />*/ <br />public String getLimitLengthString(String str, int length, String symbol) throws <br />UnsupportedEncodingException { <br />assert str != null; <br />assert length &gt; 0; <br />assert symbol != null; <br />//如果字符串的位数小于等于要截取的位数，附加上表示省略的信息的字符串后返回 <br />if (str.length() &lt;= length) { <br />return str + symbol; <br />//从零开始，截取length个字符，附加上表示省略的信息的字符串后返回 <br />} else { <br />str = new String(str.getBytes("GBK")); <br />char[] charArray = str.toCharArray(); <br />char[] charArrayDesc = new char[length]; <br />System.arraycopy(charArray, 0, charArrayDesc, 0, length); <br />return new String(charArrayDesc) + symbol; <br />} <br />}  <br /><br />呵呵 tdg 兄很认真喔，谈不上斧正。主要是这个问题，用 char 处理，如果是字母或者数字，实际上截取出来的会比汉字少占用一半的空间，所以截取出来后，还是不能对齐。而实际上 char 数组中，不管是字母、数字还是汉字，它们都只代表一个单元。但是 byte 则不同，字母、数字只占用一个字节，而汉字占用两个字节（都是GBK编码）。  <br /><br />您好！ <br />你的文章让我受益不少，有个问题想向您确认一下： <br />在代码中 <br />b = str.getBytes("GBK"); <br />if(b.length &lt;= len) <br />return str; <br />for(int i = 0; i &lt; len; i++){ <br />if(b[i] &lt; 0) <br />counterOfDoubleByte++; <br />} <br />是不是如果只要是中文汉字，在b[i]对应的值都是小于0的， <br />也就是说，在汉字代表的两个字节中，这两个汉字分别转化为整数值时，是不是一定小于0，但值范围不能小于-127的。做过测试，不能肯定。：） <br /><br />istarliu，这里要强调一下，GBK、GB2312 双字节编码字节才是负的。UTF-8 三字节编码未去核实。<br /><br /><a class="" title="转贴" href="/rosen/archive/2005/08/12/9949.html" target="_blank">来源</a></font></font><img src ="http://www.blogjava.net/snowolf/aggbug/52369.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/snowolf/" target="_blank">snowolf</a> 2006-06-13 10:46 <a href="http://www.blogjava.net/snowolf/archive/2006/06/13/52369.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>将osworkflow集成到Spring环境中</title><link>http://www.blogjava.net/snowolf/archive/2006/06/06/50767.html</link><dc:creator>snowolf</dc:creator><author>snowolf</author><pubDate>Tue, 06 Jun 2006 06:40:00 GMT</pubDate><guid>http://www.blogjava.net/snowolf/archive/2006/06/06/50767.html</guid><wfw:comment>http://www.blogjava.net/snowolf/comments/50767.html</wfw:comment><comments>http://www.blogjava.net/snowolf/archive/2006/06/06/50767.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/snowolf/comments/commentRss/50767.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/snowolf/services/trackbacks/50767.html</trackback:ping><description><![CDATA[<p>osworkflow2.8提供了新的方式，将osworkflow集成到Spring环境中，并且使用Hibernate3持久化工作流状态。相关配置片断如下：</p>
<div class="code" style="border-top-style: solid; border-right-style: solid; border-left-style: solid; border-bottom-style: solid">
<div class="codeHeader" style="border-bottom-style: solid"><strong>applicationContext.xml</strong> </div>
<div class="codeContent">
<pre class="code-xml"><span class="code-tag">&lt;bean id=<span class="code-quote">"sessionFactory"</span> class=<span class="code-quote">"org.springframework.orm.hibernate3.LocalSessionFactoryBean"</span>&gt;</span>
<span class="code-tag">&lt;property name=<span class="code-quote">"dataSource"</span>&gt;</span>
<span class="code-tag">&lt;ref bean=<span class="code-quote">"dataSource"</span>/&gt;</span>
<span class="code-tag">&lt;/property&gt;</span>
<span class="code-tag">&lt;property name=<span class="code-quote">"hibernateProperties"</span>&gt;</span>
<span class="code-tag">&lt;ref bean=<span class="code-quote">"hibernateProperties"</span>/&gt;</span>
<span class="code-tag">&lt;/property&gt;</span>
<span class="code-tag">&lt;property name=<span class="code-quote">"mappingResources"</span>&gt;</span>
<span class="code-tag">&lt;list&gt;</span>
<span class="code-tag">
<span class="code-comment">&lt;!-- osworkflow mapping files --&gt;</span>
</span>
<span class="code-tag">&lt;value&gt;</span>com/opensymphony/workflow/spi/hibernate/HibernateCurrentStep.hbm.xml<span class="code-tag">&lt;/value&gt;<br />
</span><span class="code-tag">&lt;value&gt;</span>com/opensymphony/workflow/spi/hibernate/HibernateHistoryStep.hbm.xml<span class="code-tag">&lt;/value&gt;<br />
</span><span class="code-tag">&lt;value&gt;</span>com/opensymphony/workflow/spi/hibernate/HibernateWorkflowEntry.hbm.xml<span class="code-tag">&lt;/value&gt;<br />
</span><span class="code-tag">&lt;/list&gt;<br />
</span><span class="code-tag">&lt;/property&gt;<br />
<br />
</span><span class="code-tag">&lt;/bean&gt;<br />
<br />
<br />
</span><span class="code-tag">&lt;bean id=<span class="code-quote">"propertySetDelegate"</span> class=<span class="code-quote">"com.opensymphony.workflow.spi.hibernate.DefaultHibernatePropertySetDelegate"</span>&gt;<br />
</span><span class="code-tag">&lt;property name=<span class="code-quote">"sessionFactory"</span>&gt;<br />
</span><span class="code-tag">&lt;ref bean=<span class="code-quote">"sessionFactory"</span>/&gt;<br />
</span><span class="code-tag">&lt;/property&gt;<br />
</span><span class="code-tag">&lt;/bean&gt;<br />
</span><span class="code-tag">&lt;bean id=<span class="code-quote">"workflowStore"</span> class=<span class="code-quote">"com.opensymphony.workflow.spi.hibernate3.NewSpringHibernateWorkflowStore"</span>&gt;<br />
</span><span class="code-tag">&lt;property name=<span class="code-quote">"sessionFactory"</span>&gt;</span><span class="code-tag"><br />
&lt;ref bean=<span class="code-quote">"sessionFactory"</span>/&gt;<br />
</span><span class="code-tag">&lt;/property&gt;<br />
</span><span class="code-tag">&lt;property name=<span class="code-quote">"propertySetDelegate"</span>&gt;</span><span class="code-tag"><br />
&lt;ref bean=<span class="code-quote">"propertySetDelegate"</span>/&gt;</span><span class="code-tag"><br />
&lt;/property&gt;<br />
</span><span class="code-tag">&lt;/bean&gt;<br />
</span><span class="code-tag">&lt;bean id=<span class="code-quote">"workflowFactory"</span> class=<span class="code-quote">"com.opensymphony.workflow.loader.SpringWorkflowFactory"</span> init-method=<span class="code-quote">"init"</span>&gt;<br />
</span><span class="code-tag">&lt;property name=<span class="code-quote">"resource"</span>&gt;<br />
</span><span class="code-tag">&lt;value&gt;</span>workflows.xml<span class="code-tag">&lt;/value&gt;<br />
</span><span class="code-tag">&lt;/property&gt;<br />
</span><span class="code-tag">&lt;property name=<span class="code-quote">"reload"</span>&gt;</span><span class="code-tag"><br />
&lt;value&gt;</span>true<span class="code-tag">&lt;/value&gt;<br />
</span><span class="code-tag">&lt;/property&gt;</span><span class="code-tag">&lt;/bean&gt;<br />
</span><span class="code-tag">&lt;bean id=<span class="code-quote">"workflowConfiguration"</span> class=<span class="code-quote">"com.opensymphony.workflow.config.SpringConfiguration"</span>&gt;<br />
</span><span class="code-tag">&lt;property name=<span class="code-quote">"store"</span>&gt;<br />
</span><span class="code-tag">&lt;ref local=<span class="code-quote">"workflowStore"</span>/&gt;</span><span class="code-tag"><br />
&lt;/property&gt;<br />
</span><span class="code-tag">&lt;property name=<span class="code-quote">"factory"</span>&gt;</span><span class="code-tag"><br />
&lt;ref local=<span class="code-quote">"workflowFactory"</span>/&gt;</span><span class="code-tag"><br />
&lt;/property&gt;<br />
</span><span class="code-tag">&lt;/bean&gt;</span><span class="code-tag"><br />
&lt;bean id=<span class="code-quote">"workflowTypeResolver"</span> class=<span class="code-quote">"com.opensymphony.workflow.util.SpringTypeResolver"</span>&gt;<br />
</span><span class="code-tag">&lt;/bean&gt;</span></pre>
</div>
</div>
<p>在应用代码中初始化工作流示例片断：</p>
<div class="code">
<div class="codeContent">
<pre class="code-java">Workflow workflow = <span class="code-keyword">new</span> BasicWorkflow(<span class="code-object">String</span> caller);
workflow.setConfiguration(workflowConfiguration);
workflow.initialize(workflowName, 0, <span class="code-keyword">null</span>);</pre>
</div>
</div>
<img src ="http://www.blogjava.net/snowolf/aggbug/50767.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/snowolf/" target="_blank">snowolf</a> 2006-06-06 14:40 <a href="http://www.blogjava.net/snowolf/archive/2006/06/06/50767.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Session详解</title><link>http://www.blogjava.net/snowolf/archive/2006/03/22/36880.html</link><dc:creator>snowolf</dc:creator><author>snowolf</author><pubDate>Wed, 22 Mar 2006 08:19:00 GMT</pubDate><guid>http://www.blogjava.net/snowolf/archive/2006/03/22/36880.html</guid><wfw:comment>http://www.blogjava.net/snowolf/comments/36880.html</wfw:comment><comments>http://www.blogjava.net/snowolf/archive/2006/03/22/36880.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/snowolf/comments/commentRss/36880.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/snowolf/services/trackbacks/36880.html</trackback:ping><description><![CDATA[
		<strong> 一、术语session<br /><br />　</strong>在我的经验里，session这个词被滥用的程度大概仅次于transaction，更加有趣的是transaction与session在某些语境下的含义是相同的。
<p>    session，中文经常翻译为会话，其本来的含义是指有始有终的一系列动作/消息，比如打电话时从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个 session.有时候我们可以看到这样的话“在一个浏览器会话期间，……”，这里的会话一词用的就是其本义，是指从一个浏览器窗口打开到关闭这个期间 ①。最混乱的是“用户（客户端）在一次会话期间”这样一句话，它可能指用户的一系列动作（一般情况下是同某个具体目的相关的一系列动作，比如从登录到选购商品到结账登出这样一个网上购物的过程，有时候也被称为一个transaction），然而有时候也可能仅仅是指一次连接，也有可能是指含义①，其中的差别只能靠上下文来推断②。</p><p>    然而当session一词与网络协议相关联时，它又往往隐含了“面向连接”和/或“保持状态”这样两个含义， “面向连接”指的是在通信双方在通信之前要先建立一个通信的渠道，比如打电话，直到对方接了电话通信才能开始，与此相对的是写信，在你把信发出去的时候你并不能确认对方的地址是否正确，通信渠道不一定能建立，但对发信人来说，通信已经开始了。“保持状态”则是指通信的一方能够把一系列的消息关联起来，使得消息之间可以互相依赖，比如一个服务员能够认出再次光临的老顾客并且记得上次这个顾客还欠店里一块钱。这一类的例子有“一个TCP session”或者 “一个POP3 session”③。</p><p>    而到了web服务器蓬勃发展的时代，session在web开发语境下的语义又有了新的扩展，它的含义是指一类用来在客户端与服务器之间保持状态的解决方案④。有时候session也用来指这种解决方案的存储结构，如“把xxx保存在session 里”⑤。由于各种用于web开发的语言在一定程度上都提供了对这种解决方案的支持，所以在某种特定语言的语境下，session也被用来指代该语言的解决方案，比如经常把Java里提供的javax.servlet.http.HttpSession简称为session⑥。</p><p>    鉴于这种混乱已不可改变，本文中session一词的运用也会根据上下文有不同的含义，请大家注意分辨。</p><p>    在本文中，使用中文“浏览器会话期间”来表达含义①，使用“session机制”来表达含义④，使用“session”表达含义⑤，使用具体的“HttpSession”来表达含义⑥</p><p>    <strong>二、HTTP协议与状态<br /><br />　</strong>保持HTTP 协议本身是无状态的，这与HTTP协议本来的目的是相符的，客户端只需要简单的向服务器请求下载某些文件，无论是客户端还是服务器都没有必要纪录彼此过去的行为，每一次请求之间都是独立的，好比一个顾客和一个自动售货机或者一个普通的（非会员制）大卖场之间的关系一样。</p><p>    然而聪明（或者贪心？）的人们很快发现如果能够提供一些按需生成的动态信息会使web变得更加有用，就像给有线电视加上点播功能一样。这种需求一方面迫使HTML逐步添加了表单、脚本、DOM等客户端行为，另一方面在服务器端则出现了CGI规范以响应客户端的动态请求，作为传输载体的HTTP协议也添加了文件上载、 cookie这些特性。其中cookie的作用就是为了解决HTTP协议无状态的缺陷所作出的努力。至于后来出现的session机制则是又一种在客户端与服务器之间保持状态的解决方案。</p><p>    让我们用几个例子来描述一下cookie和session机制之间的区别与联系。笔者曾经常去的一家咖啡店有喝5杯咖啡免费赠一杯咖啡的优惠，然而一次性消费5杯咖啡的机会微乎其微，这时就需要某种方式来纪录某位顾客的消费数量。想象一下其实也无外乎下面的几种方案：1、该店的店员很厉害，能记住每位顾客的消费数量，只要顾客一走进咖啡店，店员就知道该怎么对待了。这种做法就是协议本身支持状态。</p><p>    2、发给顾客一张卡片，上面记录着消费的数量，一般还有个有效期限。每次消费时，如果顾客出示这张卡片，则此次消费就会与以前或以后的消费相联系起来。这种做法就是在客户端保持状态。</p><p>    3、发给顾客一张会员卡，除了卡号之外什么信息也不纪录，每次消费时，如果顾客出示该卡片，则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。</p><p>    由于HTTP协议是无状态的，而出于种种考虑也不希望使之成为有状态的，因此，后面两种方案就成为现实的选择。具体来说cookie机制采用的是在客户端保持状态的方案，而session机制采用的是在服务器端保持状态的方案。同时我们也看到，由于采用服务器端保持状态的方案在客户端也需要保存一个标识，所以session机制可能需要借助于cookie机制来达到保存标识的目的，但实际上它还有其他选择。</p><p>    <strong>三、理解cookie机制<br /><br />　</strong>cookie机制的基本原理就如上面的例子一样简单，但是还有几个问题需要解决：“会员卡”如何分发：“会员卡”的内容；以及客户如何使用“会员卡”。</p><p>    正统的cookie分发是通过扩展HTTP协议来实现的，服务器通过在HTTP的响应头中加上一行特殊的指示以提示浏览器按照指示生成相应的cookie.然而纯粹的客户端脚本如JavaScript或者VBScript也可以生成cookie.</p><p>    而cookie 的使用是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器检查所有存储的cookie，如果某个cookie所声明的作用范围大于等于将要请求的资源所在的位置，则把该cookie附在请求资源的HTTP请求头上发送给服务器。意思是麦当劳的会员卡只能在麦当劳的店里出示，如果某家分店还发行了自己的会员卡，那么进这家店的时候除了要出示麦当劳的会员卡，还要出示这家店的会员卡。</p><p>    cookie的内容主要包括：名字，值，过期时间，路径和域。</p><p>    其中域可以指定某一个域比如。google.com，相当于总店招牌，比如宝洁公司，也可以指定一个域下的具体某台机器比如<a href="http://www.google.com/">www.google.com</a>或者froogle.google.com，可以用飘柔来做比。</p><p>    路径就是跟在域名后面的URL路径，比如/或者/foo等等，可以用某飘柔专柜做比。</p><p>    路径与域合在一起就构成了cookie的作用范围。</p><p>    如果不设置过期时间，则表示这个cookie的生命期为浏览器会话期间，只要关闭浏览器窗口，cookie就消失了。这种生命期为浏览器会话期的 cookie被称为会话cookie.会话cookie一般不存储在硬盘上而是保存在内存里，当然这种行为并不是规范规定的。如果设置了过期时间，浏览器就会把cookie保存到硬盘上，关闭后再次打开浏览器，这些cookie仍然有效直到超过设定的过期时间。</p><p>    存储在硬盘上的cookie 可以在不同的浏览器进程间共享，比如两个IE窗口。而对于保存在内存里的cookie，不同的浏览器有不同的处理方式。对于IE，在一个打开的窗口上按 Ctrl-N（或者从文件菜单）打开的窗口可以与原窗口共享，而使用其他方式新开的IE进程则不能共享已经打开的窗口的内存cookie；对于 Mozilla Firefox0.8，所有的进程和标签页都可以共享同样的cookie.一般来说是用javascript的window.open打开的窗口会与原窗口共享内存cookie.浏览器对于会话cookie的这种只认cookie不认人的处理方式经常给采用session机制的web应用程序开发者造成很大的困扰。</p><p>    下面就是一个goolge设置cookie的响应头的例子HTTP/1.1 302 FoundLocation： <a href="http://www.google.com/intl/zh-CN/Set-Cookie">http://www.google.com/intl/zh-CN/Set-Cookie</a>： PREF=ID=0565f77e132de138：NW=1：TM=1098082649：LM=1098082649：S=KaeaCFPo49RiA_d8； expires=Sun， 17-Jan-2038 19：14：07 GMT； path=/； domain=.google.comContent-Type： text/html</p><p align="center"><img onmouseover="javascript:imgShowTip(this);" style="DISPLAY: inline" onclick="javascript:imgClick(this);" alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200603/20060314125320274.jpg" onload="javascript:imgLoad(this);" border="0" resized="0" /></p><p>    这是使用HTTPLook这个HTTP Sniffer软件来俘获的HTTP通讯纪录的一部分</p><p align="center"><img onmouseover="javascript:imgShowTip(this);" style="DISPLAY: inline" onclick="javascript:imgClick(this);" alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200603/20060314125320533.jpg" onload="javascript:imgLoad(this);" border="0" resized="0" /></p><p>    浏览器在再次访问goolge的资源时自动向外发送cookie</p><p align="center"><img onmouseover="javascript:imgShowTip(this);" style="DISPLAY: inline" onclick="javascript:imgClick(this);" alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200603/20060314125322468.jpg" onload="javascript:imgLoad(this);" border="0" resized="0" /></p><p>    用Firefox可以很容易的观察现有的cookie的值使用HTTPLook配合Firefox可以很容易的理解cookie的工作原理。</p><p align="center"><img onmouseover="javascript:imgShowTip(this);" style="DISPLAY: inline" onclick="javascript:imgClick(this);" alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200603/20060314125322207.jpg" onload="javascript:imgLoad(this);" border="0" resized="0" /></p><p>    IE也可以设置在接受cookie前询问</p><p>   <strong> 四、理解session机制</strong></p><p>    session机制是一种服务器端的机制，服务器使用一种类似于散列表的结构（也可能就是使用散列表）来保存信息。</p><p>    当程序需要为某个客户端的请求创建一个session的时候，服务器首先检查这个客户端的请求里是否已包含了一个session标识 - 称为 session id，如果已包含一个session id则说明以前已经为此客户端创建过session，服务器就按照session id把这个 session检索出来使用（如果检索不到，可能会新建一个），如果客户端请求不包含session id，则为此客户端创建一个session并且生成一个与此session相关联的session id，session id的值应该是一个既不会重复，又不容易被找到规律以仿造的字符串，这个 session id将被在本次响应中返回给客户端保存。</p><p>    保存这个session id的方式可以采用cookie，这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。一般这个cookie的名字都是类似于SEEESIONID，而。比如weblogic对于web应用程序生成的cookie，JSESSIONID= ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng！-145788764，它的名字就是 JSESSIONID.</p><p>    由于cookie可以被人为的禁止，必须有其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。经常被使用的一种技术叫做URL重写，就是把session id直接附加在URL路径的后面，附加方式也有两种，一种是作为URL路径的附加信息，表现形式为<a href="http://……/xxx">http://……/xxx</a>；jsessionid= ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng！-145788764另一种是作为查询字符串附加在URL后面，表现形式为<a href="http://……/xxx">http://……/xxx</a>？jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng！-145788764这两种方式对于用户来说是没有区别的，只是服务器在解析的时候处理的方式不同，采用第一种方式也有利于把session id的信息和正常程序参数区分开来。</p><p>    为了在整个交互过程中始终保持状态，就必须在每个客户端可能请求的路径后面都包含这个session id.</p><p>    另一种技术叫做表单隐藏字段。就是服务器会自动修改表单，添加一个隐藏字段，以便在表单提交时能够把session id传递回服务器。比如下面的表单&lt;form name="testform" action="/xxx"&gt;&lt;input type="text"&gt;&lt;/form&gt;</p><p>    在被传递给客户端之前将被改写成&lt;form name="testform" action="/xxx"&gt;&lt;input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng！-145788764"&gt;&lt;input type="text"&gt;&lt;/form&gt;</p><p>    这种技术现在已较少应用，笔者接触过的很古老的iPlanet6（SunONE应用服务器的前身）就使用了这种技术。</p><p>    实际上这种技术可以简单的用对action应用URL重写来代替。</p><p>    在谈论session机制的时候，常常听到这样一种误解“只要关闭浏览器，session就消失了”。其实可以想象一下会员卡的例子，除非顾客主动对店家提出销卡，否则店家绝对不会轻易删除顾客的资料。对session来说也是一样的，除非程序通知服务器删除一个session，否则服务器会一直保留，程序一般都是在用户做log off的时候发个指令去删除session.然而浏览器从来不会主动在关闭之前通知服务器它将要关闭，因此服务器根本不会有机会知道浏览器已经关闭，之所以会有这种错觉，是大部分session机制都使用会话cookie来保存session id，而关闭浏览器后这个 session id就消失了，再次连接服务器时也就无法找到原来的session.如果服务器设置的cookie被保存到硬盘上，或者使用某种手段改写浏览器发出的HTTP请求头，把原来的session id发送给服务器，则再次打开浏览器仍然能够找到原来的session.</p><p>    恰恰是由于关闭浏览器不会导致session被删除，迫使服务器为seesion设置了一个失效时间，当距离客户端上一次使用session的时间超过这个失效时间时，服务器就可以认为客户端已经停止了活动，才会把session删除以节省存储空间。</p><p>    <strong>五、理解javax.servlet.http.HttpSession<br /><br />　</strong> HttpSession是Java平台对session机制的实现规范，因为它仅仅是个接口，具体到每个web应用服务器的提供商，除了对规范支持之外，仍然会有一些规范里没有规定的细微差异。这里我们以BEA的Weblogic Server8.1作为例子来演示。</p><p>    首先，Weblogic Server提供了一系列的参数来控制它的HttpSession的实现，包括使用cookie的开关选项，使用URL重写的开关选项，session持久化的设置，session失效时间的设置，以及针对cookie的各种设置，比如设置cookie的名字、路径、域， cookie的生存时间等。</p><p>    一般情况下，session都是存储在内存里，当服务器进程被停止或者重启的时候，内存里的session也会被清空，如果设置了session的持久化特性，服务器就会把session保存到硬盘上，当服务器进程重新启动或这些信息将能够被再次使用， Weblogic Server支持的持久性方式包括文件、数据库、客户端cookie保存和复制。</p><p>    复制严格说来不算持久化保存，因为session实际上还是保存在内存里，不过同样的信息被复制到各个cluster内的服务器进程中，这样即使某个服务器进程停止工作也仍然可以从其他进程中取得session.</p><p>    cookie生存时间的设置则会影响浏览器生成的cookie是否是一个会话cookie.默认是使用会话cookie.有兴趣的可以用它来试验我们在第四节里提到的那个误解。</p><p>    cookie的路径对于web应用程序来说是一个非常重要的选项，Weblogic Server对这个选项的默认处理方式使得它与其他服务器有明显的区别。后面我们会专题讨论。</p><p>    关于session的设置参考[5] <a href="http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869">http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869</a></p><p>   <strong> 六、HttpSession常见问题</strong>（在本小节中session的含义为⑤和⑥的混合）</p><p>    1、session在何时被创建一个常见的误解是以为session在有客户端访问时就被创建，然而事实是直到某server端程序调用 HttpServletRequest.getSession（true）这样的语句时才被创建，注意如果JSP没有显示的使用 &lt;% @page session="false"%&gt; 关闭session，则JSP文件在编译成Servlet时将会自动加上这样一条语句 HttpSession session = HttpServletRequest.getSession（true）；这也是JSP中隐含的 session对象的来历。</p><p>    由于session会消耗内存资源，因此，如果不打算使用session，应该在所有的JSP中关闭它。</p><p>    2、session何时被删除综合前面的讨论，session在下列情况下被删除a.程序调用HttpSession.invalidate（）；或b.距离上一次收到客户端发送的session id时间间隔超过了session的超时设置；或c.服务器进程被停止（非持久session）</p><p>    3、如何做到在浏览器关闭时删除session严格的讲，做不到这一点。可以做一点努力的办法是在所有的客户端页面里使用javascript代码window.oncolose来监视浏览器的关闭动作，然后向服务器发送一个请求来删除session.但是对于浏览器崩溃或者强行杀死进程这些非常规手段仍然无能为力。</p><p>    4、有个HttpSessionListener是怎么回事你可以创建这样的listener去监控session的创建和销毁事件，使得在发生这样的事件时你可以做一些相应的工作。注意是session的创建和销毁动作触发listener，而不是相反。类似的与HttpSession有关的listener还有 HttpSessionBindingListener，HttpSessionActivationListener和 HttpSessionAttributeListener.</p><p>    5、存放在session中的对象必须是可序列化的吗不是必需的。要求对象可序列化只是为了session能够在集群中被复制或者能够持久保存或者在必要时server能够暂时把session交换出内存。在 Weblogic Server的session中放置一个不可序列化的对象在控制台上会收到一个警告。我所用过的某个iPlanet版本如果 session中有不可序列化的对象，在session销毁时会有一个Exception，很奇怪。</p><p>    6、如何才能正确的应付客户端禁止cookie的可能性对所有的URL使用URL重写，包括超链接，form的action，和重定向的URL，具体做法参见[6] <a href="http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770">http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770</a></p><p>    7、开两个浏览器窗口访问应用程序会使用同一个session还是不同的session参见第三小节对cookie的讨论，对session来说是只认id不认人，因此不同的浏览器，不同的窗口打开方式以及不同的cookie存储方式都会对这个问题的答案有影响。</p><p>    8、如何防止用户打开两个浏览器窗口操作导致的session混乱这个问题与防止表单多次提交是类似的，可以通过设置客户端的令牌来解决。就是在服务器每次生成一个不同的id返回给客户端，同时保存在session里，客户端提交表单时必须把这个id也返回服务器，程序首先比较返回的id与保存在session里的值是否一致，如果不一致则说明本次操作已经被提交过了。可以参看《J2EE核心模式》关于表示层模式的部分。需要注意的是对于使用javascript window.open打开的窗口，一般不设置这个id，或者使用单独的id，以防主窗口无法操作，建议不要再window.open打开的窗口里做修改操作，这样就可以不用设置。</p><p>    9、为什么在Weblogic Server中改变session的值后要重新调用一次session.setValue做这个动作主要是为了在集群环境中提示Weblogic Server session中的值发生了改变，需要向其他服务器进程复制新的session值。</p><p>    10、为什么session不见了排除session正常失效的因素之外，服务器本身的可能性应该是微乎其微的，虽然笔者在iPlanet6SP1加若干补丁的Solaris版本上倒也遇到过；浏览器插件的可能性次之，笔者也遇到过3721插件造成的问题；理论上防火墙或者代理服务器在cookie处理上也有可能会出现问题。</p><p>    出现这一问题的大部分原因都是程序的错误，最常见的就是在一个应用程序中去访问另外一个应用程序。我们在下一节讨论这个问题。</p><p> <strong>   七、跨应用程序的session共享</strong></p><p>    常常有这样的情况，一个大项目被分割成若干小项目开发，为了能够互不干扰，要求每个小项目作为一个单独的web应用程序开发，可是到了最后突然发现某几个小项目之间需要共享一些信息，或者想使用session来实现SSO（single sign on），在session中保存login的用户信息，最自然的要求是应用程序间能够访问彼此的session.</p><p>    然而按照Servlet规范，session的作用范围应该仅仅限于当前应用程序下，不同的应用程序之间是不能够互相访问对方的session的。各个应用服务器从实际效果上都遵守了这一规范，但是实现的细节却可能各有不同，因此解决跨应用程序session共享的方法也各不相同。</p><p>    首先来看一下Tomcat是如何实现web应用程序之间session的隔离的，从 Tomcat设置的cookie路径来看，它对不同的应用程序设置的cookie路径是不同的，这样不同的应用程序所用的session id是不同的，因此即使在同一个浏览器窗口里访问不同的应用程序，发送给服务器的session id也可以是不同的。</p><p align="center"><img onmouseover="javascript:imgShowTip(this);" style="DISPLAY: inline" onclick="javascript:imgClick(this);" alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200603/20060314125323841.jpg" onload="javascript:imgLoad(this);" border="0" resized="0" /></p><p align="center"><img onmouseover="javascript:imgShowTip(this);" style="DISPLAY: inline" onclick="javascript:imgClick(this);" alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200603/20060314125323233.jpg" onload="javascript:imgLoad(this);" border="0" resized="0" /></p><p>    根据这个特性，我们可以推测Tomcat中session的内存结构大致如下。</p><p align="center"><img onmouseover="javascript:imgShowTip(this);" style="DISPLAY: inline" onclick="javascript:imgClick(this);" alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200603/20060314125323802.jpg" onload="javascript:imgLoad(this);" border="0" resized="0" /></p><p>    笔者以前用过的iPlanet也采用的是同样的方式，估计SunONE与iPlanet之间不会有太大的差别。对于这种方式的服务器，解决的思路很简单，实际实行起来也不难。要么让所有的应用程序共享一个session id，要么让应用程序能够获得其他应用程序的session id.</p><p>    iPlanet中有一种很简单的方法来实现共享一个session id，那就是把各个应用程序的cookie路径都设为/（实际上应该是/NASApp，对于应用程序来讲它的作用相当于根）。</p><p>    &lt;session-info&gt;&lt;path&gt;/NASApp&lt;/path&gt;&lt;/session-info&gt;</p><p>    需要注意的是，操作共享的session应该遵循一些编程约定，比如在session attribute名字的前面加上应用程序的前缀，使得 setAttribute（"name"， "neo"）变成setAttribute（"app1.name"， "neo"），以防止命名空间冲突，导致互相覆盖。</p><p>    在Tomcat中则没有这么方便的选择。在Tomcat版本3上，我们还可以有一些手段来共享session.对于版本4以上的Tomcat，目前笔者尚未发现简单的办法。只能借助于第三方的力量，比如使用文件、数据库、JMS或者客户端cookie，URL参数或者隐藏字段等手段。</p><p>    我们再看一下Weblogic Server是如何处理session的。</p><p align="center"><img onmouseover="javascript:imgShowTip(this);" style="DISPLAY: inline" onclick="javascript:imgClick(this);" alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200603/20060314125323420.jpg" onload="javascript:imgLoad(this);" border="0" resized="0" /></p><p align="center"><img onmouseover="javascript:imgShowTip(this);" style="DISPLAY: inline" onclick="javascript:imgClick(this);" alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200603/20060314125324813.jpg" onload="javascript:imgLoad(this);" border="0" resized="0" /></p><p>    从截屏画面上可以看到Weblogic Server对所有的应用程序设置的cookie的路径都是/，这是不是意味着在Weblogic Server中默认的就可以共享session了呢？然而一个小实验即可证明即使不同的应用程序使用的是同一个session，各个应用程序仍然只能访问自己所设置的那些属性。这说明Weblogic Server中的session的内存结构可能如下</p><p align="center"><img onmouseover="javascript:imgShowTip(this);" style="DISPLAY: inline" onclick="javascript:imgClick(this);" alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200603/20060314125324805.jpg" onload="javascript:imgLoad(this);" border="0" resized="0" /></p><p>    对于这样一种结构，在 session机制本身上来解决session共享的问题应该是不可能的了。除了借助于第三方的力量，比如使用文件、数据库、JMS或者客户端 cookie，URL参数或者隐藏字段等手段，还有一种较为方便的做法，就是把一个应用程序的session放到ServletContext中，这样另外一个应用程序就可以从ServletContext中取得前一个应用程序的引用。示例代码如下，</p><p>    应用程序A context.setAttribute（"appA"， session）；</p><p>    应用程序B contextA = context.getContext（"/appA"）；HttpSession sessionA = （HttpSession）contextA.getAttribute（"appA"）；</p><p>    值得注意的是这种用法不可移植，因为根据ServletContext的JavaDoc，应用服务器可以处于安全的原因对于context.getContext（"/appA"）；返回空值，以上做法在Weblogic Server 8.1中通过。</p><p>    那么Weblogic Server为什么要把所有的应用程序的cookie路径都设为/呢？原来是为了SSO，凡是共享这个session的应用程序都可以共享认证的信息。一个简单的实验就可以证明这一点，修改首先登录的那个应用程序的描述符weblogic.xml，把cookie路径修改为/appA 访问另外一个应用程序会重新要求登录，即使是反过来，先访问cookie路径为/的应用程序，再访问修改过路径的这个，虽然不再提示登录，但是登录的用户信息也会丢失。注意做这个实验时认证方式应该使用FORM，因为浏览器和web服务器对basic认证方式有其他的处理方式，第二次请求的认证不是通过 session来实现的。具体请参看[7] secion 14.8 Authorization，你可以修改所附的示例程序来做这些试验。</p><p>    <strong>八、总结<br /><br />　</strong>session机制本身并不复杂，然而其实现和配置上的灵活性却使得具体情况复杂多变。这也要求我们不能把仅仅某一次的经验或者某一个浏览器，服务器的经验当作普遍适用的经验，而是始终需要具体情况具体分析。</p><p>    摘要：虽然session机制在web应用程序中被采用已经很长时间了，但是仍然有很多人不清楚session机制的本质，以至不能正确的应用这一技术。本文将详细讨论session的工作机制并且对在Java web application中应用session机制时常见的问题作出解答。</p><img src ="http://www.blogjava.net/snowolf/aggbug/36880.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/snowolf/" target="_blank">snowolf</a> 2006-03-22 16:19 <a href="http://www.blogjava.net/snowolf/archive/2006/03/22/36880.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用 Struts Validator</title><link>http://www.blogjava.net/snowolf/archive/2006/03/20/36248.html</link><dc:creator>snowolf</dc:creator><author>snowolf</author><pubDate>Mon, 20 Mar 2006 02:59:00 GMT</pubDate><guid>http://www.blogjava.net/snowolf/archive/2006/03/20/36248.html</guid><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 构建带有验证的 “防弹” 应用程序																																				验证的重要性																						伟大的篮球队经常因为他们有稳定的控球、精彩的传球、挡不住的投篮而受到赞扬。伟大的音乐家要反复地练习，而且会在一两个音阶或小节上花费数小时的时间。伟大的汽车有许多额外的特性，但是跑得更远，引擎...&nbsp;&nbsp;<a href='http://www.blogjava.net/snowolf/archive/2006/03/20/36248.html'>阅读全文</a><img src ="http://www.blogjava.net/snowolf/aggbug/36248.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/snowolf/" target="_blank">snowolf</a> 2006-03-20 10:59 <a href="http://www.blogjava.net/snowolf/archive/2006/03/20/36248.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一篇不错的讲解Java异常的文章</title><link>http://www.blogjava.net/snowolf/archive/2006/03/17/35813.html</link><dc:creator>snowolf</dc:creator><author>snowolf</author><pubDate>Fri, 17 Mar 2006 04:46:00 GMT</pubDate><guid>http://www.blogjava.net/snowolf/archive/2006/03/17/35813.html</guid><wfw:comment>http://www.blogjava.net/snowolf/comments/35813.html</wfw:comment><comments>http://www.blogjava.net/snowolf/archive/2006/03/17/35813.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/snowolf/comments/commentRss/35813.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/snowolf/services/trackbacks/35813.html</trackback:ping><description><![CDATA[
		<p>
				<font size="2">六种异常处理的陋习</font>
		</p>
		<p>
				<font size="2">你觉得自己是一个Java专家吗？是否肯定自己已经全面掌握了Java的异常处理机制？在下面这段代码中，你能够迅速找出异常处理的六个问题吗？ <br /><br /></font>
		</p>
		<table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1">
				<tbody>
						<tr>
								<td>
										<font size="2">1 OutputStreamWriter out = ... <br />2 java.sql.Connection conn = ... <br />3 try { // ⑸ <br />4 　Statement stat = conn.createStatement(); <br />5 　ResultSet rs = stat.executeQuery( <br />6 　　"select uid, name from user"); <br />7 　while (rs.next()) <br />8 　{ <br />9 　　out.println("ID：" + rs.getString("uid") // ⑹ <br />10 　　　"，姓名：" + rs.getString("name")); <br />11 　} <br />12 　conn.close(); // ⑶ <br />13 　out.close(); <br />14 } <br />15 catch(Exception ex) // ⑵ <br />16 { <br />17 　ex.printStackTrace(); //⑴，⑷ <br />18 }</font>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<br />
				<font size="2">　　作为一个Java程序员，你至少应该能够找出两个问题。但是，如果你不能找出全部六个问题，请继续阅读本文。 <br /><br />　　本文讨论的不是Java异常处理的一般性原则，因为这些原则已经被大多数人熟知。我们要做的是分析各种可称为“反例”（anti-pattern）的违背优秀编码规范的常见坏习惯，帮助读者熟悉这些典型的反面例子，从而能够在实际工作中敏锐地察觉和避免这些问题。 <br /><br />　　<b>反例之一：丢弃异常 </b><br /><br />　　代码：15行-18行。 <br /><br />　　这段代码捕获了异常却不作任何处理，可以算得上Java编程中的杀手。从问题出现的频繁程度和祸害程度来看，它也许可以和C/C++程序的一个恶名远播的问题相提并论??不检查缓冲区是否已满。如果你看到了这种丢弃（而不是抛出）异常的情况，可以百分之九十九地肯定代码存在问题（在极少数情况下，这段代码有存在的理由，但最好加上完整的注释，以免引起别人误解）。 <br /><br />　　这段代码的错误在于，异常（几乎）总是意味着某些事情不对劲了，或者说至少发生了某些不寻常的事情，我们不应该对程序发出的求救信号保持沉默和无动于衷。调用一下printStackTrace算不上“处理异常”。不错，调用printStackTrace对调试程序有帮助，但程序调试阶段结束之后，printStackTrace就不应再在异常处理模块中担负主要责任了。 <br /><br />　　丢弃异常的情形非常普遍。打开JDK的ThreadDeath类的文档，可以看到下面这段说明：“特别地，虽然出现ThreadDeath是一种‘正常的情形’，但ThreadDeath类是Error而不是Exception的子类，因为许多应用会捕获所有的Exception然后丢弃它不再理睬。”这段话的意思是，虽然ThreadDeath代表的是一种普通的问题，但鉴于许多应用会试图捕获所有异常然后不予以适当的处理，所以JDK把ThreadDeath定义成了Error的子类，因为Error类代表的是一般的应用不应该去捕获的严重问题。可见，丢弃异常这一坏习惯是如此常见，它甚至已经影响到了Java本身的设计。 <br /><br />　　那么，应该怎样改正呢？主要有四个选择： <br /><br />　　1、处理异常。针对该异常采取一些行动，例如修正问题、提醒某个人或进行其他一些处理，要根据具体的情形确定应该采取的动作。再次说明，调用printStackTrace算不上已经“处理好了异常”。 <br /><br />　　2、重新抛出异常。处理异常的代码在分析异常之后，认为自己不能处理它，重新抛出异常也不失为一种选择。 <br /><br />　　3、把该异常转换成另一种异常。大多数情况下，这是指把一个低级的异常转换成应用级的异常（其含义更容易被用户了解的异常）。 <br /><br />　　4、不要捕获异常。 <br /><br />　　结论一：既然捕获了异常，就要对它进行适当的处理。不要捕获异常之后又把它丢弃，不予理睬。 <br /><br />　　<b>反例之二：不指定具体的异常 </b><br /><br />　　代码：15行。 <br /><br />　　许多时候人们会被这样一种“美妙的”想法吸引：用一个catch语句捕获所有的异常。最常见的情形就是使用catch(Exception ex)语句。但实际上，在绝大多数情况下，这种做法不值得提倡。为什么呢？ <br /><br />　　要理解其原因，我们必须回顾一下catch语句的用途。catch语句表示我们预期会出现某种异常，而且希望能够处理该异常。异常类的作用就是告诉Java编译器我们想要处理的是哪一种异常。由于绝大多数异常都直接或间接从java.lang.Exception派生，catch(Exception ex)就相当于说我们想要处理几乎所有的异常。 <br /><br />　　再来看看前面的代码例子。我们真正想要捕获的异常是什么呢？最明显的一个是SQLException，这是JDBC操作中常见的异常。另一个可能的异常是IOException，因为它要操作OutputStreamWriter。显然，在同一个catch块中处理这两种截然不同的异常是不合适的。如果用两个catch块分别捕获SQLException和IOException就要好多了。这就是说，catch语句应当尽量指定具体的异常类型，而不应该指定涵盖范围太广的Exception类。 <br /><br />　　另一方面，除了这两个特定的异常，还有其他许多异常也可能出现。例如，如果由于某种原因，executeQuery返回了null，该怎么办？答案是让它们继续抛出，即不必捕获也不必处理。实际上，我们不能也不应该去捕获可能出现的所有异常，程序的其他地方还有捕获异常的机会??直至最后由JVM处理。 <br /><br />　　结论二：在catch语句中尽可能指定具体的异常类型，必要时使用多个catch。不要试图处理所有可能出现的异常。 <br /><br />　　<b>反例之三：占用资源不释放 </b><br /><br />　　代码：3行-14行。 <br /><br />　　异常改变了程序正常的执行流程。这个道理虽然简单，却常常被人们忽视。如果程序用到了文件、Socket、JDBC连接之类的资源，即使遇到了异常，也要正确释放占用的资源。为此，Java提供了一个简化这类操作的关键词finally。 <br /><br />　　finally是样好东西：不管是否出现了异常，Finally保证在try/catch/finally块结束之前，执行清理任务的代码总是有机会执行。遗憾的是有些人却不习惯使用finally。 <br /><br />　　当然，编写finally块应当多加小心，特别是要注意在finally块之内抛出的异常??这是执行清理任务的最后机会，尽量不要再有难以处理的错误。 <br /><br />　　结论三：保证所有资源都被正确释放。充分运用finally关键词。</font>
		</p>
		<p>
				<font size="2">
						<strong>反例之四：不说明异常的详细信息 <br /><br /></strong>　　代码：3行-18行。 <br /><br />　　仔细观察这段代码：如果循环内部出现了异常，会发生什么事情？我们可以得到足够的信息判断循环内部出错的原因吗？不能。我们只能知道当前正在处理的类发生了某种错误，但却不能获得任何信息判断导致当前错误的原因。 <br /><br />　　printStackTrace的堆栈跟踪功能显示出程序运行到当前类的执行流程，但只提供了一些最基本的信息，未能说明实际导致错误的原因，同时也不易解读。 <br /><br />　　因此，在出现异常时，最好能够提供一些文字信息，例如当前正在执行的类、方法和其他状态信息，包括以一种更适合阅读的方式整理和组织printStackTrace提供的信息。 <br /><br />　　结论四：在异常处理模块中提供适量的错误原因信息，组织错误信息使其易于理解和阅读。 <br /><br />　　<b>反例之五：过于庞大的try块 </b><br /><br />　　代码：3行-14行。 <br /><br />　　经常可以看到有人把大量的代码放入单个try块，实际上这不是好习惯。这种现象之所以常见，原因就在于有些人图省事，不愿花时间分析一大块代码中哪几行代码会抛出异常、异常的具体类型是什么。把大量的语句装入单个巨大的try块就象是出门旅游时把所有日常用品塞入一个大箱子，虽然东西是带上了，但要找出来可不容易。 <br /><br />　　一些新手常常把大量的代码放入单个try块，然后再在catch语句中声明Exception，而不是分离各个可能出现异常的段落并分别捕获其异常。这种做法为分析程序抛出异常的原因带来了困难，因为一大段代码中有太多的地方可能抛出Exception。 <br /><br />　　结论五：尽量减小try块的体积。 <br /><br />　　<b>反例之六：输出数据不完整</b><br /><br />　　代码：7行-11行。 <br /><br />　　不完整的数据是Java程序的隐形杀手。仔细观察这段代码，考虑一下如果循环的中间抛出了异常，会发生什么事情。循环的执行当然是要被打断的，其次，catch块会执行??就这些，再也没有其他动作了。已经输出的数据怎么办？使用这些数据的人或设备将收到一份不完整的（因而也是错误的）数据，却得不到任何有关这份数据是否完整的提示。对于有些系统来说，数据不完整可能比系统停止运行带来更大的损失。 <br /><br />　　较为理想的处置办法是向输出设备写一些信息，声明数据的不完整性；另一种可能有效的办法是，先缓冲要输出的数据，准备好全部数据之后再一次性输出。 <br /><br />　　结论六：全面考虑可能出现的异常以及这些异常对执行流程的影响。 <br /><br />　　<b>改写后的代码</b><br /><br />　　根据上面的讨论，下面给出改写后的代码。也许有人会说它稍微有点?嗦，但是它有了比较完备的异常处理机制。 <br /><br /></font>
		</p>
		<table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1">
				<tbody>
						<tr>
								<td>
										<font size="2">OutputStreamWriter out = ... <br />java.sql.Connection conn = ... <br />try { <br />　Statement stat = conn.createStatement(); <br />　ResultSet rs = stat.executeQuery( <br />　　"select uid, name from user"); <br />　while (rs.next()) <br />　{ <br />　　out.println("ID：" + rs.getString("uid") + "，姓名: " + rs.getString("name")); <br />　} <br />} <br />catch(SQLException sqlex) <br />{ <br />　out.println("警告：数据不完整"); <br />　throw new ApplicationException("读取数据时出现SQL错误", sqlex); <br />} <br />catch(IOException ioex) <br />{ <br />　throw new ApplicationException("写入数据时出现IO错误", ioex); <br />} <br />finally <br />{ <br />　if (conn != null) { <br />　　try { <br />　　　conn.close(); <br />　　} <br />　　catch(SQLException sqlex2) <br />　　{ <br />　　　System.err(this.getClass().getName() + ".mymethod - 不能关闭数据库连接: " + sqlex2.toString()); <br />　　} <br />　} <br /><br />　if (out != null) { <br />　　try { <br />　　　out.close(); <br />　　} <br />　　catch(IOException ioex2) <br />　　{ <br />　　　System.err(this.getClass().getName() + ".mymethod - 不能关闭输出文件" + ioex2.toString()); <br />　　} <br />　} <br />} </font>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<font size="2">　　本文的结论不是放之四海皆准的教条，有时常识和经验才是最好的老师。如果你对自己的做法没有百分之百的信心，务必加上详细、全面的注释。 <br /><br />　　另一方面，不要笑话这些错误，不妨问问你自己是否真地彻底摆脱了这些坏习惯。即使最有经验的程序员偶尔也会误入歧途，原因很简单，因为它们确确实实带来了“方便”。所有这些反例都可以看作Java编程世界的恶魔，它们美丽动人，无孔不入，时刻诱惑着你。也许有人会认为这些都属于鸡皮蒜毛的小事，不足挂齿，但请记住：勿以恶小而为之，勿以善小而不为。</font>
<img src ="http://www.blogjava.net/snowolf/aggbug/35813.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/snowolf/" target="_blank">snowolf</a> 2006-03-17 12:46 <a href="http://www.blogjava.net/snowolf/archive/2006/03/17/35813.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Eclipse中的快捷键- -</title><link>http://www.blogjava.net/snowolf/archive/2006/03/17/35809.html</link><dc:creator>snowolf</dc:creator><author>snowolf</author><pubDate>Fri, 17 Mar 2006 04:03:00 GMT</pubDate><guid>http://www.blogjava.net/snowolf/archive/2006/03/17/35809.html</guid><wfw:comment>http://www.blogjava.net/snowolf/comments/35809.html</wfw:comment><comments>http://www.blogjava.net/snowolf/archive/2006/03/17/35809.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/snowolf/comments/commentRss/35809.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/snowolf/services/trackbacks/35809.html</trackback:ping><description><![CDATA[
		<p>把eclipse中的快捷键列了出来。<br /><span><div><strong><div><strong>编辑</strong></div><table cellspacing="0" cellpadding="0" border="1"><tbody><tr><td valign="top" width="115"><div><font size="+0"><strong>作用域</strong></font></div></td><td valign="top" width="312"><div><font size="+0"><strong>功能</strong></font></div></td><td valign="top" width="132"><div><font size="+0"><strong>快捷键</strong></font></div></td></tr><tr><td valign="top" width="115"><div><font size="+0">全局</font></div></td><td valign="top" width="312"><div><font size="+0">查找并替换</font></div></td><td valign="top" width="132"><div><font size="+0">Ctrl+F</font></div></td></tr><tr><td valign="top" width="115"><div><font size="+0">文本编辑器</font></div></td><td valign="top" width="312"><div><font size="+0">查找上一个</font></div></td><td valign="top" width="132"><div><font size="+0">Ctrl+Shift+K</font></div></td></tr><tr><td valign="top" width="115"><div><font size="+0">文本编辑器</font></div></td><td valign="top" width="312"><div><font size="+0">查找下一个</font></div></td><td valign="top" width="132"><div><font size="+0">Ctrl+K</font></div></td></tr><tr><td valign="top" width="115"><div><font size="+0">全局</font></div></td><td valign="top" width="312"><div><font size="+0">撤销</font></div></td><td valign="top" width="132"><div><font size="+0">Ctrl+Z</font></div></td></tr><tr><td valign="top" width="115"><div><font size="+0">全局</font></div></td><td valign="top" width="312"><div><font size="+0">复制</font></div></td><td valign="top" width="132"><div><font size="+0">Ctrl+C</font></div></td></tr><tr><td valign="top" width="115"><div><font size="+0">全局</font></div></td><td valign="top" width="312"><div><font size="+0">恢复上一个选择</font></div></td><td valign="top" width="132"><div><font size="+0">Alt+Shift+↓</font></div></td></tr><tr><td valign="top" width="115"><div><font size="+0">全局</font></div></td><td valign="top" width="312"><div><font size="+0">剪切</font></div></td><td valign="top" width="132"><div><font size="+0">Ctrl+X</font></div></td></tr><tr><td valign="top" width="115"><div><font size="+0">全局</font></div></td><td valign="top" width="312"><div><font size="+0">快速修正</font></div></td><td valign="top" width="132"><div><font size="+0">Ctrl1+1</font></div></td></tr><tr><td valign="top" width="115"><div><font size="+0">全局</font></div></td><td valign="top" width="312"><div><font size="+0">内容辅助</font></div></td><td valign="top" width="132"><div><font size="+0">Alt+/</font></div></td></tr><tr><td valign="top" width="115"><div><font size="+0">全局</font></div></td><td valign="top" width="312"><div><font size="+0">全部选中</font></div></td><td valign="top" width="132"><div><font size="+0">Ctrl+A</font></div></td></tr><tr><td valign="top" width="115"><div><font size="+0">全局</font></div></td><td valign="top" width="312"><div><font size="+0">删除</font></div></td><td valign="top" width="132"><div><font size="+0">Delete</font></div></td></tr><tr><td valign="top" width="115"><div><font size="+0">全局</font></div></td><td valign="top" width="312"><div><font size="+0">上下文信息</font></div></td><td valign="top" width="132"><div><font size="+0">Alt+？</font></div><div><font size="+0">Alt+Shift+?</font></div><div><font size="+0">Ctrl+Shift+Space</font></div></td></tr><tr><td valign="top" width="115"><div><font size="+0">Java编辑器</font></div></td><td valign="top" width="312"><div><font size="+0">显示工具提示描述</font></div></td><td valign="top" width="132"><div><font size="+0">F2</font></div></td></tr><tr><td valign="top" width="115"><div><font size="+0">Java编辑器</font></div></td><td valign="top" width="312"><div><font size="+0">选择封装元素</font></div></td><td valign="top" width="132"><div><font size="+0">Alt+Shift+↑</font></div></td></tr><tr><td valign="top" width="115"><div><font size="+0">Java编辑器</font></div></td><td valign="top" width="312"><div><font size="+0">选择上一个元素</font></div></td><td valign="top" width="132"><div><font size="+0">Alt+Shift+←</font></div></td></tr><tr><td valign="top" width="115"><div><font size="+0">Java编辑器</font></div></td><td valign="top" width="312"><div><font size="+0">选择下一个元素</font></div></td><td valign="top" width="132"><div><font size="+0">Alt+Shift+→</font></div></td></tr><tr><td valign="top" width="115"><div><font size="+0">文本编辑器</font></div></td><td valign="top" width="312"><div><font size="+0">增量查找</font></div></td><td valign="top" width="132"><div><font size="+0">Ctrl+J</font></div></td></tr><tr><td valign="top" width="115"><div><font size="+0">文本编辑器</font></div></td><td valign="top" width="312"><div><font size="+0">增量逆向查找</font></div></td><td valign="top" width="132"><div><font size="+0">Ctrl+Shift+J</font></div></td></tr><tr><td valign="top" width="115"><div><font size="+0">全局</font></div></td><td valign="top" width="312"><div><font size="+0">粘贴</font></div></td><td valign="top" width="132"><div><font size="+0">Ctrl+V</font></div></td></tr><tr><td valign="top" width="115"><div><font size="+0">全局</font></div></td><td valign="top" width="312"><div><font size="+0">重做</font></div></td><td valign="top" width="132"><div><font size="+0">Ctrl+Y</font></div></td></tr></tbody></table><div><font size="+0"></font></div></strong></div><div><strong>查看</strong></div><p></p><table cellspacing="0" cellpadding="0" border="1"><tbody><tr><td valign="top" width="115"><div><font size="+0">作用域</font></div></td><td valign="top" width="312"><div><font size="+0">功能</font></div></td><td valign="top" width="132"><div><font size="+0">快捷键</font></div></td></tr><tr><td valign="top" width="115"><div><font size="+0">全局</font></div></td><td valign="top" width="312"><div><font size="+0">放大</font></div></td><td valign="top" width="132"><div><font size="+0">Ctrl+=</font></div></td></tr><tr><td valign="top" width="115"><div><font size="+0">全局</font></div></td><td valign="top" width="312"><div><font size="+0">缩小</font></div></td><td valign="top" width="132"><div><font size="+0">Ctrl+-</font></div></td></tr></tbody></table></span></p>
		<div>
				<font size="+0">
				</font>
		</div>
		<div>
				<strong>窗口</strong>
		</div>
		<p>
		</p>
		<table cellspacing="0" cellpadding="0" border="1">
				<tbody>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">作用域</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">功能</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">快捷键</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">激活编辑器</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">F12</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">切换编辑器</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+Shift+W</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">上一个编辑器</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+Shift+F6</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">上一个视图</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+Shift+F7</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">上一个透视图</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+Shift+F8</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">下一个编辑器</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+F6</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">下一个视图</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+F7</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">下一个透视图</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+F8</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">文本编辑器</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">显示标尺上下文菜单</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+W</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">显示视图菜单</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+F10</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">显示系统菜单</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Alt+-</font>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
		<div>
				<font size="+0">
				</font>
		</div>
		<div>
				<strong>导航</strong>
		</div>
		<p>
		</p>
		<table cellspacing="0" cellpadding="0" border="1">
				<tbody>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">作用域</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">功能</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">快捷键</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">Java编辑器</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">打开结构</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+F3</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">打开类型</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+Shift+T</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">打开类型层次结构</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">F4</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">打开声明</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">F3</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">打开外部javadoc</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Shift+F2</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">打开资源</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+Shift+R</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">后退历史记录</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Alt+←</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">前进历史记录</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Alt+→</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">上一个</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+,</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">下一个</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+.</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">Java编辑器</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">显示大纲</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+O</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">在层次结构中打开类型</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+Shift+H</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">转至匹配的括号</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+Shift+P</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">转至上一个编辑位置</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+Q</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">Java编辑器</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">转至上一个成员</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+Shift+↑</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">Java编辑器</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">转至下一个成员</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+Shift+↓</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">文本编辑器</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">转至行</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+L</font>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
		<div>
				<font size="+0">
				</font>
		</div>
		<div>
				<font size="+0">
						<strong>搜索</strong>
				</font>
		</div>
		<p>
		</p>
		<table cellspacing="0" cellpadding="0" border="1">
				<tbody>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">作用域</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">功能</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">快捷键</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">出现在文件中</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+Shift+U</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">打开搜索对话框</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+H</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">工作区中的声明</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+G</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">工作区中的引用</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+Shift+G</font>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
		<div>
				<font size="+0">
				</font>
		</div>
		<div>
				<font size="+0">
						<strong>文本编辑</strong>
				</font>
		</div>
		<p>
		</p>
		<table cellspacing="0" cellpadding="0" border="1">
				<tbody>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">作用域</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">功能</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">快捷键</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">文本编辑器</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">改写切换</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Insert</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">文本编辑器</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">上滚行</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+↑</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">文本编辑器</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">下滚行</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+↓</font>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
		<div>
				<font size="+0">
				</font>
		</div>
		<div>
				<font size="+0">
						<strong>文件</strong>
				</font>
		</div>
		<p>
		</p>
		<table cellspacing="0" cellpadding="0" border="1">
				<tbody>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">作用域</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">功能</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">快捷键</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">保存</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+X </font>
										</div>
										<div>
												<font size="+0">Ctrl+S</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">打印</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+P</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">关闭</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+F4</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">全部保存</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+Shift+S</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">全部关闭</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+Shift+F4</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">属性</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Alt+Enter</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">新建</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+N</font>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
		<div>
				<font size="+0">
				</font>
		</div>
		<div>
				<font size="+0">
						<strong>项目</strong>
				</font>
		</div>
		<p>
		</p>
		<table cellspacing="0" cellpadding="0" border="1">
				<tbody>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">作用域</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">功能</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">快捷键</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">全部构建</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+B</font>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
		<div>
				<font size="+0">
				</font>
		</div>
		<div>
				<font size="+0">
						<strong>源代码</strong>
				</font>
		</div>
		<p>
		</p>
		<table cellspacing="0" cellpadding="0" border="1">
				<tbody>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">作用域</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">功能</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">快捷键</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">Java编辑器</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">格式化</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+Shift+F</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">Java编辑器</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">取消注释</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+\</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">Java编辑器</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">注释</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+/</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">Java编辑器</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">添加导入</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+Shift+M</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">Java编辑器</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">组织导入</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+Shift+O</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">Java编辑器</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">使用try/catch块来包围</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">未设置，太常用了，所以在这里列出,建议自己设置。<br />也可以使用Ctrl+1自动修正。</font>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
		<div>
				<font size="+0">
				</font>
		</div>
		<div>
				<font size="+0">
						<strong>运行</strong>
				</font>
		</div>
		<p>
		</p>
		<table cellspacing="0" cellpadding="0" border="1">
				<tbody>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">作用域</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">功能</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">快捷键</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">单步返回</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">F7</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">单步跳过</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">F6</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">单步跳入</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">F5</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">单步跳入选择</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+F5</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">调试上次启动</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">F11</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">继续</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">F8</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">使用过滤器单步执行</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Shift+F5</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">添加/去除断点</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+Shift+B</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">显示</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+D</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">运行上次启动</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+F11</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">运行至行</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+R</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">执行</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Ctrl+U</font>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
		<div>
				<font size="+0">
				</font>
		</div>
		<div>
				<font size="+0">
						<strong>重构</strong>
				</font>
		</div>
		<p>
		</p>
		<table cellspacing="0" cellpadding="0" border="1">
				<tbody>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">作用域</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">功能</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">快捷键</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">撤销重构</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Alt+Shift+Z</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">抽取方法</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Alt+Shift+M</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">抽取局部变量</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Alt+Shift+L</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">内联</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Alt+Shift+I</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">移动</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Alt+Shift+V</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">重命名</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Alt+Shift+R</font>
										</div>
								</td>
						</tr>
						<tr>
								<td valign="top" width="115">
										<div>
												<font size="+0">全局</font>
										</div>
								</td>
								<td valign="top" width="312">
										<div>
												<font size="+0">重做</font>
										</div>
								</td>
								<td valign="top" width="132">
										<div>
												<font size="+0">Alt+Shift+Y</font>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
		<p> </p>
<img src ="http://www.blogjava.net/snowolf/aggbug/35809.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/snowolf/" target="_blank">snowolf</a> 2006-03-17 12:03 <a href="http://www.blogjava.net/snowolf/archive/2006/03/17/35809.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>