﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-心无痕的博客-随笔分类-JAVA</title><link>http://www.blogjava.net/xinwuhen/category/29825.html</link><description /><language>zh-cn</language><lastBuildDate>Wed, 07 Apr 2010 09:42:15 GMT</lastBuildDate><pubDate>Wed, 07 Apr 2010 09:42:15 GMT</pubDate><ttl>60</ttl><item><title>用连接池配置BIRT报表的数据库连接。。。。</title><link>http://www.blogjava.net/xinwuhen/archive/2009/04/07/264241.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Tue, 07 Apr 2009 05:32:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2009/04/07/264241.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/264241.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2009/04/07/264241.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/264241.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/264241.html</trackback:ping><description><![CDATA[<p>现阶段我们在开发报表的时候，是使用jdbc链接数据库的，为提高报表的运行效率和稳定性，使用连接池进行管理。比较简便和低耦合的解决办法，使用jndi连接池。</p>
<p>&nbsp;</p>
<p><font color="#ff0000"><strong>jdbc和jndi的区别</strong></font></p>
<p><font color="#ff0000">JDBC -最基本的连接数据库的方式， 每次对数据库打交道的时候 ，连接数据库是需要实例下你实现连接数据库的方法或者类。 <br />
JNDI DataSource 英文全称是:Java Naming and Directory Interface java 命明接口，当服务启动时 事先把连接数据库的已经连好多条，具体多少条你可以设置，存放在tomcat容器里，用的时候可以直接使用， 不用再实例化得到连接， 相对与jdbc效率要快点</font></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>在eclipse设计报表的时候，我们使用jdbc链接数据库做测试，当到了tomcat运行环境中切换到jndi连接池，这是比较方便的开发方法。</p>
<p>实现步骤：</p>
<p><strong>1.tomcat配置jndi连接池</strong></p>
<p>在 {tomcat目录}\webapps\{项目名}\META-INF 中新增context.xml文件，配置代码如下<br />
</p>
<p><strong></p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" /><span style="color: #0000ff">&lt;?</span><span style="color: #ff00ff">xml&nbsp;version="1.0"&nbsp;encoding="UTF-8"</span><span style="color: #0000ff">?&gt;</span><span style="color: #000000"><br />
<img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">Context</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
<img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">Resource<br />
<img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #ff0000">auth</span><span style="color: #0000ff">="Container"</span><span style="color: #ff0000"><br />
<img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name</span><span style="color: #0000ff">="jdbc/travel_agency"</span><span style="color: #ff0000"><br />
<img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;type</span><span style="color: #0000ff">="javax.sql.DataSource"</span><span style="color: #ff0000"><br />
<img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxIdle</span><span style="color: #0000ff">="5"</span><span style="color: #ff0000"><br />
<img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxWait</span><span style="color: #0000ff">="-1"</span><span style="color: #ff0000"><br />
<img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;driverClassName</span><span style="color: #0000ff">="com.mysql.jdbc.Driver"</span><span style="color: #ff0000"><br />
<img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;username</span><span style="color: #0000ff">="itravel"</span><span style="color: #ff0000"><br />
<img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;password</span><span style="color: #0000ff">="709394"</span><span style="color: #ff0000"><br />
<img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;url</span><span style="color: #0000ff">="jdbc:mysql://192.168.1.100/travel_agency?useUnicode=true&amp;amp;characterEncoding=UTF-8"</span><span style="color: #ff0000"><br />
<img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxActive</span><span style="color: #0000ff">="10"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
<img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">Context</span><span style="color: #0000ff">&gt;</span></div>
<p>2.在web.xml中加入配置<br />
</strong></p>
<p>&nbsp;</p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" /><span style="color: #0000ff">&lt;</span><span style="color: #800000">resource-ref</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
<img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">description</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">Database&nbsp;Source</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">description</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
<img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">res-ref-name</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">jdbc/travel_agency</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">res-ref-name</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
<img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">res-type</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">javax.sql.DataSource</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">res-type</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
<img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">res-auth</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">Container</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">res-auth</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
<img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">resource-ref</span><span style="color: #0000ff">&gt;</span></div>
<p><br />
<strong>3.实例报表中数据源代码</strong></p>
<p>&nbsp;</p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><span style="color: #008080">1</span><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" /><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">data-sources</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
</span><span style="color: #008080">2</span><span style="color: #000000"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">oda-data-source&nbsp;</span><span style="color: #ff0000">extensionID</span><span style="color: #0000ff">="org.eclipse.birt.report.data.oda.jdbc"</span><span style="color: #ff0000">&nbsp;name</span><span style="color: #0000ff">="数据源"</span><span style="color: #ff0000">&nbsp;id</span><span style="color: #0000ff">="227"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
</span><span style="color: #008080">3</span><span style="color: #000000"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">property&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="odaDriverClass"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">com.mysql.jdbc.Driver</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">property</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;<br />
</span><span style="color: #008080">4</span><span style="color: #000000"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">property&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="odaURL"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">jdbc:mysql://192.168.1.100/travel_agency</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">property</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;<br />
</span><span style="color: #008080">5</span><span style="color: #000000"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">property&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="odaUser"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">itravel</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">property</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
</span><span style="color: #008080">6</span><span style="color: #000000"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">encrypted-property&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="odaPassword"</span><span style="color: #ff0000">&nbsp;encryptionID</span><span style="color: #0000ff">="base64"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">NzA5Mzk0</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">encrypted-property</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
</span><span style="color: #008080">7</span><span style="color: #000000"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">property&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="odaJndiName"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">java:comp/env/jdbc/travel_agency</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">property</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
</span><span style="color: #008080">8</span><span style="color: #000000"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">oda-data-source</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
</span><span style="color: #008080">9</span><span style="color: #000000"><img alt="" align="top" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">data-sources</span><span style="color: #0000ff">&gt;</span></div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>除了第7行&nbsp;<span style="color: #0000ff">&lt;</span><span style="color: #800000">property&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="odaJndiName"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">java:comp/env/jdbc/travel_agency</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">property</span><span style="color: #0000ff">&gt;</span>，其余是我们的之前的配置。用了第7行的代码，表示该报表支持jndi数据源，birt在运行报表的时候，会先用jndi去连接，如果失败了再用jdbc链接，这样做的好处就是，我们在开发报表的时候，没有放到web环境中，可以使用jdbc，当放到tomcat中，因为有了第7行的配置。默认采用jdni连接。<br />
<br />
<strong>4.步骤3中第6行密码的生成程序（JAVA程序）</strong><br />
<span style="font-family: 'Courier New'; color: rgb(127,0,85); font-size: 10.5pt; font-weight: bold; mso-spacerun: 'yes'">package</span><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">&nbsp;com.hollycrm.birt.security;</span><span style="font-family: 'Courier New'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt" class="p0"><span style="font-family: 'Courier New'; color: rgb(127,0,85); font-size: 10.5pt; font-weight: bold; mso-spacerun: 'yes'">import</span><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">&nbsp;java.io.BufferedReader;</span><span style="font-family: 'Courier New'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt" class="p0"><span style="font-family: 'Courier New'; color: rgb(127,0,85); font-size: 10.5pt; font-weight: bold; mso-spacerun: 'yes'">import</span><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">&nbsp;java.io.IOException;</span><span style="font-family: 'Courier New'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt" class="p0"><span style="font-family: 'Courier New'; color: rgb(127,0,85); font-size: 10.5pt; font-weight: bold; mso-spacerun: 'yes'">import</span><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">&nbsp;java.io.InputStreamReader;</span><span style="font-family: 'Courier New'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt" class="p0"><span style="font-family: 'Courier New'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt" class="p0"><span style="font-family: 'Courier New'; color: rgb(127,0,85); font-size: 10.5pt; font-weight: bold; mso-spacerun: 'yes'">import</span><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">&nbsp;sun.misc.BASE64Encoder;</span><span style="font-family: 'Courier New'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt" class="p0"><span style="font-family: 'Courier New'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt" class="p0"><span style="font-family: 'Courier New'; color: rgb(127,0,85); font-size: 10.5pt; font-weight: bold; mso-spacerun: 'yes'">public</span><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">&nbsp;</span><span style="font-family: 'Courier New'; color: rgb(127,0,85); font-size: 10.5pt; font-weight: bold; mso-spacerun: 'yes'">class</span><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">&nbsp;CreateBirtBase64Password&nbsp;{</span><span style="font-family: 'Courier New'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt" class="p0"><span style="font-family: 'Courier New'; color: rgb(127,0,85); font-size: 10.5pt; font-weight: bold; mso-spacerun: 'yes'">public</span><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">&nbsp;</span><span style="font-family: 'Courier New'; color: rgb(127,0,85); font-size: 10.5pt; font-weight: bold; mso-spacerun: 'yes'">static</span><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">&nbsp;</span><span style="font-family: 'Courier New'; color: rgb(127,0,85); font-size: 10.5pt; font-weight: bold; mso-spacerun: 'yes'">void</span><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">&nbsp;main(String[]&nbsp;args)&nbsp;{</span><span style="font-family: 'Courier New'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt" class="p0"><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">InputStreamReader&nbsp;inStreamReader&nbsp;=&nbsp;</span><span style="font-family: 'Courier New'; color: rgb(127,0,85); font-size: 10.5pt; font-weight: bold; mso-spacerun: 'yes'">new</span><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">&nbsp;InputStreamReader(System.</span><span style="font-style: italic; font-family: 'Courier New'; color: rgb(0,0,192); font-size: 10.5pt; mso-spacerun: 'yes'">in</span><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">);</span><span style="font-family: 'Courier New'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt" class="p0"><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">BufferedReader&nbsp;buffReader&nbsp;=&nbsp;</span><span style="font-family: 'Courier New'; color: rgb(127,0,85); font-size: 10.5pt; font-weight: bold; mso-spacerun: 'yes'">new</span><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">&nbsp;BufferedReader(inStreamReader);</span><span style="font-family: 'Courier New'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt" class="p0"><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">System.</span><span style="font-style: italic; font-family: 'Courier New'; color: rgb(0,0,192); font-size: 10.5pt; mso-spacerun: 'yes'">out</span><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">.println(</span><span style="font-family: 'Courier New'; color: rgb(42,0,255); font-size: 10.5pt; mso-spacerun: 'yes'">"请输入需要通过Base64加密的字符串："</span><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">);</span><span style="font-family: 'Courier New'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt" class="p0"><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">String&nbsp;strSrcPassword&nbsp;=&nbsp;</span><span style="font-family: 'Courier New'; color: rgb(127,0,85); font-size: 10.5pt; font-weight: bold; mso-spacerun: 'yes'">null</span><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">;</span><span style="font-family: 'Courier New'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt" class="p0"><span style="font-family: 'Courier New'; color: rgb(127,0,85); font-size: 10.5pt; font-weight: bold; mso-spacerun: 'yes'">try</span><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">&nbsp;{</span><span style="font-family: 'Courier New'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt" class="p0"><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">strSrcPassword&nbsp;=&nbsp;buffReader.readLine();</span><span style="font-family: 'Courier New'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt" class="p0"><span style="font-family: 'Courier New'; color: rgb(127,0,85); font-size: 10.5pt; font-weight: bold; mso-spacerun: 'yes'">if</span><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">&nbsp;(strSrcPassword&nbsp;!=&nbsp;</span><span style="font-family: 'Courier New'; color: rgb(127,0,85); font-size: 10.5pt; font-weight: bold; mso-spacerun: 'yes'">null</span><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">)&nbsp;{</span><span style="font-family: 'Courier New'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt" class="p0"><span style="font-family: 'Courier New'; color: rgb(63,127,95); font-size: 10.5pt; mso-spacerun: 'yes'">//&nbsp;通过用户输入的密码信息生成Base64的加密密码</span><span style="font-family: 'Courier New'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt" class="p0"><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">String&nbsp;strBase64Password&nbsp;=&nbsp;</span><span style="font-family: 'Courier New'; color: rgb(127,0,85); font-size: 10.5pt; font-weight: bold; mso-spacerun: 'yes'">new</span><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">&nbsp;BASE64Encoder().encode(strSrcPassword.trim().getBytes());</span><span style="font-family: 'Courier New'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt" class="p0"><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">System.</span><span style="font-style: italic; font-family: 'Courier New'; color: rgb(0,0,192); font-size: 10.5pt; mso-spacerun: 'yes'">out</span><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">.println(</span><span style="font-family: 'Courier New'; color: rgb(42,0,255); font-size: 10.5pt; mso-spacerun: 'yes'">"您输入的原始密码为："</span><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">&nbsp;+&nbsp;strSrcPassword&nbsp;+&nbsp;</span><span style="font-family: 'Courier New'; color: rgb(42,0,255); font-size: 10.5pt; mso-spacerun: 'yes'">"\r对应生成的Base64密码值为："</span><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">&nbsp;+&nbsp;strBase64Password);</span><span style="font-family: 'Courier New'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt" class="p0"><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">}</span><span style="font-family: 'Courier New'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt" class="p0"><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">}&nbsp;</span><span style="font-family: 'Courier New'; color: rgb(127,0,85); font-size: 10.5pt; font-weight: bold; mso-spacerun: 'yes'">catch</span><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">&nbsp;(IOException&nbsp;e)&nbsp;{</span><span style="font-family: 'Courier New'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt" class="p0"><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">e.printStackTrace();</span><span style="font-family: 'Courier New'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt" class="p0"><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">}</span><span style="font-family: 'Courier New'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt" class="p0"><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">}</span><span style="font-family: 'Courier New'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p style="margin-top: 0pt; text-indent: 21pt; margin-bottom: 0pt; margin-left: 63pt" class="p0"><span style="font-family: 'Courier New'; color: rgb(0,0,0); font-size: 10.5pt; mso-spacerun: 'yes'">}</span><span style="font-family: '宋体'; font-size: 10.5pt; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p><!--endfragment--></p>
 <img src ="http://www.blogjava.net/xinwuhen/aggbug/264241.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2009-04-07 13:32 <a href="http://www.blogjava.net/xinwuhen/archive/2009/04/07/264241.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于用javascript动态生成表格的注意点...</title><link>http://www.blogjava.net/xinwuhen/archive/2009/03/18/260606.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Wed, 18 Mar 2009 15:11:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2009/03/18/260606.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/260606.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2009/03/18/260606.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/260606.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/260606.html</trackback:ping><description><![CDATA[<p>有时为了动态生成页面内容, 我们会用到javascript来这么处理, 但有时用javascript动态生成页面信息时,会有错误却查不到信息,现以用javascript动态生成表格为例, 说明如下(以下代码可以直接拷贝下来,存为html格式的文件执行):<br />
<br />
&lt;html&gt;<br />
&lt;head&gt;<br />
&nbsp;&lt;script language='javascript'&gt;<br />
&nbsp;&nbsp;function addNode() {<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;// 第一部分代码<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;var vDiv = document.getElementById('1');&nbsp;// 注意:此处是取的不包含在&lt;table&gt;内的&lt;div&gt;标签<br />
&nbsp;&nbsp;&nbsp;var vTable = document.createElement('table');<br />
&nbsp;&nbsp;&nbsp;var tbody = document.createElement("tbody");<br />
&nbsp;&nbsp;&nbsp;var vTr = document.createElement('tr');<br />
&nbsp;&nbsp;&nbsp;var vTd = document.createElement('td');<br />
&nbsp;&nbsp;&nbsp;var vText = document.createTextNode('这是第一部分代码');<br />
&nbsp;&nbsp;&nbsp;vTd.appendChild(vText);&nbsp;// 或: vTd.innerText='这是第一部分代码';<br />
&nbsp;&nbsp;&nbsp;vTr.appendChild(vTd);<br />
&nbsp;&nbsp;&nbsp;tbody.appendChild(vTr);<br />
&nbsp;&nbsp;&nbsp;vTable.appendChild(tbody);<br />
&nbsp;&nbsp;&nbsp;vDiv.appendChild(vTable);<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;// 第二部分代码<br />
&nbsp;&nbsp;&nbsp;/*<br />
&nbsp;&nbsp;&nbsp;var vDiv = document.getElementById('2');&nbsp;// 注意:此处是取的&lt;table&gt;标签<br />
&nbsp;&nbsp;&nbsp;//var obj = document.createElement("table");<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;var tbody = document.createElement("tbody");<br />
&nbsp;&nbsp;&nbsp;var tr = document.createElement("tr");<br />
&nbsp;&nbsp;&nbsp;var td = document.createElement("td");<br />
&nbsp;&nbsp;&nbsp;td.innerText = "这是第二部分代码";<br />
&nbsp;&nbsp;&nbsp;tr.appendChild(td);<br />
&nbsp;&nbsp;&nbsp;tbody.appendChild(tr);<br />
&nbsp;&nbsp;&nbsp;//obj.appendChild(tbody);<br />
&nbsp;&nbsp;&nbsp;vDiv.appendChild(tbody);&nbsp;// 注意: 此处vDiv即为&lt;table&gt;标签, 故只需要在这个标签上添加&lt;tbody&gt;标签<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp; 同样，如果本段代码取&lt;tbody&gt;标签，<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 即：var vDiv = document.getElementById('4'); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 那么，我们只需用vDiv.appendChild(tr);即可实现同样的效果。<br />
&nbsp;&nbsp;&nbsp;*/<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;/*<br />
&nbsp;&nbsp;&nbsp;// 第三部分代码<br />
&nbsp;&nbsp;&nbsp;var vDiv = document.getElementById('8');&nbsp;// 注意:此处是取的包含在&lt;tbody&gt;标签(id为6)内的&lt;div&gt;标签<br />
&nbsp;&nbsp;&nbsp;//var obj = document.createElement("table");<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;//var tbody = document.createElement("tbody");<br />
&nbsp;&nbsp;&nbsp;var tr = document.createElement("tr");<br />
&nbsp;&nbsp;&nbsp;var td = document.createElement("td");<br />
&nbsp;&nbsp;&nbsp;td.innerText="这是第三部分代码";<br />
&nbsp;&nbsp;&nbsp;tr.appendChild(td);<br />
&nbsp;&nbsp;&nbsp;//tbody.appendChild(tr);<br />
&nbsp;&nbsp;&nbsp;//obj.appendChild(tbody);<br />
&nbsp;&nbsp;&nbsp;vDiv.appendChild(tr);&nbsp;// 通过此处，向id为8的&lt;div&gt;添加标签&lt;tr&gt;是错误的；因为，&lt;div&gt;与&lt;tr&gt;不是父子关系<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;// 这是错误的代码： vDiv.innerHtml="&lt;table&gt;&lt;tr&gt;&lt;td&gt;test&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;";<br />
&nbsp;&nbsp;&nbsp;*/</p>
<p>&nbsp;&nbsp;}<br />
&nbsp;&lt;/script&gt;<br />
&lt;/head&gt;<br />
&lt;body&gt;</p>
<p>&nbsp;&lt;!-- 总结: 动态生成页面表格 --&gt; <br />
&nbsp;&lt;!--&nbsp;&nbsp;&nbsp; 1: 在页面中本身就没有&lt;table&gt;标签时, 必须创建&lt;table&gt;、&lt;tbody&gt;、&lt;tr&gt;、&lt;td&gt;这四个标签,并且缺一不可;&nbsp;--&gt;<br />
&nbsp;&lt;!--&nbsp;&nbsp;&nbsp;参见：&#8220;第一部分代码&#8221; --&gt;<br />
&nbsp;&lt;!--&nbsp;&nbsp;&nbsp; 2: 在页面中本身存在&lt;table&gt;标签时, 依据上边四个标签必须有的原则：在页面中有的标签我们直接取 --&gt;<br />
&nbsp;&lt;!--&nbsp;&nbsp;&nbsp;最内层的标签, 然后把缺的标签补上即可;参见：&#8220;第二部分代码&#8221; --&gt;<br />
&nbsp;&lt;!--&nbsp;&nbsp;&nbsp; 3: 对于没有父子关系的标签，如ID为8的标签（即：div标签）与tr标签就没有父子关系。--&gt;<br />
&nbsp;&lt;!--&nbsp;&nbsp;&nbsp;此时，就不能直接添加tbody标签到div标签内部. 参见：&#8220;第三部分代码&#8221;。--&gt;</p>
<p>&nbsp;&lt;!-- 此处仅有div标签 --&gt;<br />
&nbsp;&lt;div id='1'&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&lt;/div&gt;</p>
<p>&nbsp;&lt;!-- 此处仅有table标签 --&gt;<br />
&nbsp;&lt;table id='2'&gt;<br />
&nbsp;&nbsp;<br />
&nbsp;&lt;/table&gt;</p>
<p>&nbsp;&lt;!-- 此处有table、tbody二种标签 --&gt;<br />
&nbsp;&lt;table id='3'&gt;<br />
&nbsp;&nbsp;&lt;tbody id='4'&gt;</p>
<p>&nbsp;&nbsp;&lt;/tbody&gt;<br />
&nbsp;&lt;/table&gt;</p>
<p>&nbsp;&lt;table id='5'&gt;<br />
&nbsp;&nbsp;&lt;tbody id='6'&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;tr id=7&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&lt;/tr&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;div id='8'&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&lt;/div&gt;<br />
&nbsp;&nbsp;&lt;/tbody&gt;<br />
&nbsp;&lt;/table&gt;<br />
&lt;/body&gt;<br />
&lt;html&gt;</p>
<p>&lt;script language='javascript'&gt;<br />
&nbsp;addNode();<br />
&lt;/script&gt;</p>
<img src ="http://www.blogjava.net/xinwuhen/aggbug/260606.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2009-03-18 23:11 <a href="http://www.blogjava.net/xinwuhen/archive/2009/03/18/260606.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入Struts 1.1----转自IBM DeveloperWorks</title><link>http://www.blogjava.net/xinwuhen/archive/2008/07/01/212013.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Tue, 01 Jul 2008 14:10:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2008/07/01/212013.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/212013.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2008/07/01/212013.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/212013.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/212013.html</trackback:ping><description><![CDATA[<p>2003 年 8 月 02 日</p>
<blockquote>作为基于MVC模式的Web应用最经典框架，Struts已经正式推出了1.1版本，该版本在以往版本的基础上，提供了许多激动人心的新功能。本文就将带你走进Struts 1.1去深入地了解这些功能。</blockquote>
<p><!--start RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--end RESERVED FOR FUTURE USE INCLUDE FILES-->
<table cellspacing="0" cellpadding="0" width="150" border="0">
    <tbody>
        <tr>
            <td class="left-nav-highlight" colspan="2"><a class="left-nav" href="http://www.ibm.com/developerworks/cn/java/l-struts1-1/#" cmimpressionsent="1">本文内容包括：</a></td>
        </tr>
        <tr class="left-nav-child-highlight">
            <td><img height="8" alt="" src="http://www.ibm.com/i/v14/t/cl-bullet.gif" width="2" /></td>
            <td><a class="left-nav-child" href="http://www.ibm.com/developerworks/cn/java/l-struts1-1/#1" cmimpressionsent="1">Model 2</a></td>
        </tr>
        <tr class="left-nav-child-highlight">
            <td><img height="8" alt="" src="http://www.ibm.com/i/v14/t/cl-bullet.gif" width="2" /></td>
            <td><a class="left-nav-child" href="http://www.ibm.com/developerworks/cn/java/l-struts1-1/#2" cmimpressionsent="1">Struts 1.1 和Model 2</a></td>
        </tr>
        <tr class="left-nav-child-highlight">
            <td><img height="8" alt="" src="http://www.ibm.com/i/v14/t/cl-bullet.gif" width="2" /></td>
            <td><a class="left-nav-child" href="http://www.ibm.com/developerworks/cn/java/l-struts1-1/#3" cmimpressionsent="1">模块</a></td>
        </tr>
        <tr class="left-nav-child-highlight">
            <td><img height="8" alt="" src="http://www.ibm.com/i/v14/t/cl-bullet.gif" width="2" /></td>
            <td><a class="left-nav-child" href="http://www.ibm.com/developerworks/cn/java/l-struts1-1/#4" cmimpressionsent="1">ActionServlet</a></td>
        </tr>
        <tr class="left-nav-child-highlight">
            <td><img height="8" alt="" src="http://www.ibm.com/i/v14/t/cl-bullet.gif" width="2" /></td>
            <td><a class="left-nav-child" href="http://www.ibm.com/developerworks/cn/java/l-struts1-1/#5" cmimpressionsent="1">ActionForm</a></td>
        </tr>
        <tr class="left-nav-child-highlight">
            <td><img height="8" alt="" src="http://www.ibm.com/i/v14/t/cl-bullet.gif" width="2" /></td>
            <td><a class="left-nav-child" href="http://www.ibm.com/developerworks/cn/java/l-struts1-1/#6" cmimpressionsent="1">Action</a></td>
        </tr>
        <tr class="left-nav-child-highlight">
            <td><img height="8" alt="" src="http://www.ibm.com/i/v14/t/cl-bullet.gif" width="2" /></td>
            <td><a class="left-nav-child" href="http://www.ibm.com/developerworks/cn/java/l-struts1-1/#7" cmimpressionsent="1">宣称式异常处理</a></td>
        </tr>
        <tr class="left-nav-child-highlight">
            <td><img height="8" alt="" src="http://www.ibm.com/i/v14/t/cl-bullet.gif" width="2" /></td>
            <td><a class="left-nav-child" href="http://www.ibm.com/developerworks/cn/java/l-struts1-1/#8" cmimpressionsent="1">taglib</a></td>
        </tr>
        <tr class="left-nav-child-highlight">
            <td><img height="8" alt="" src="http://www.ibm.com/i/v14/t/cl-bullet.gif" width="2" /></td>
            <td><a class="left-nav-child" href="http://www.ibm.com/developerworks/cn/java/l-struts1-1/#9" cmimpressionsent="1">Commons Logging 接口</a></td>
        </tr>
        <tr class="left-nav-child-highlight">
            <td><img height="8" alt="" src="http://www.ibm.com/i/v14/t/cl-bullet.gif" width="2" /></td>
            <td><a class="left-nav-child" href="http://www.ibm.com/developerworks/cn/java/l-struts1-1/#author" cmimpressionsent="1">关于作者</a></td>
        </tr>
        <tr class="left-nav-child-highlight">
            <td><img height="8" alt="" src="http://www.ibm.com/i/v14/t/cl-bullet.gif" width="2" /></td>
            <td><a class="left-nav-child" href="http://www.ibm.com/developerworks/cn/java/l-struts1-1/#rate" cmimpressionsent="1">对本文的评价</a></td>
        </tr>
    </tbody>
</table>
<br />
</p>
<p><strong>说明：</strong>希望本文的读者能有一定的Struts使用基础。 </p>
<p><a name="1"><span class="atitle">Model 2</span></a></p>
<p>
<p>Struts是基于Model 2之上的，而Model 2是经典的MVC（模型－视图－控制器）模型的Web应用变体，这个改变主要是由于网络应用的特性--HTTP协议的无状态性引起的。Model 2的目的和MVC一样，也是利用控制器来分离模型和视图，达到一种层间松散耦合的效果，提高系统灵活性、复用性和可维护性。在多数情况下，你可以将Model 2与MVC等同起来。</p>
<p>下图表示一个基于Java技术的典型网络应用，从中可以看出Model 2中的各个部分是如何对应于Java中各种现有技术的。</p>
<p><br />
<img alt="" src="http://www.ibm.com/developerworks/cn/java/l-struts1-1/image001.gif" /> <br />
</p>
<p>在利用Model 2之前，我们是把所有的表示逻辑和业务逻辑都集中在一起（比如大杂烩似的JSP），有时也称这种应用模式为Model 1，Model 1的主要缺点就是紧耦合，复用性差以及维护成本高。</p>
<p><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/l-struts1-1/#main" cmimpressionsent="1"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
</p>
<p><a name="2"><span class="atitle">Struts 1.1 和Model 2</span></a></p>
<p>
<p>既然Struts 1.1是基于Model 2之上，那它的底层机制也就是MVC，下面是Struts 1.1中的MVC实现示意图：</p>
<p><br />
<img alt="" src="http://www.ibm.com/developerworks/cn/java/l-struts1-1/image002.jpg" /> <br />
<em>图解说明：其中不同颜色代表MVC的不同部分：红色（控制器）、紫色（模型）和绿色（视图） </em></p>
<p>首先，控制器（ActionServlet）进行初始化工作，读取配置文件（struts-config.xml），为不同的Struts模块初始化相应的ModuleConfig对象。比如配置文件中的Action映射定义都保存在ActionConfig集合中。相应地有ControlConfig集合、FormBeanConfig集合、ForwardConfig集合和MessageResourcesConfig集合等。</p>
<p><em><strong>提示：</strong>模块是在Struts 1.1中新提出的概念，在稍后的内容中我们将详细介绍，你现在可以简单地把模块看作是一个子系统，它们共同组成整个应用，同时又各自独立。Struts 1.1中所有的处理都是在特定模块环境中进行的。模块的提出主要是为了解决Struts 1.0中单配置文件的问题。 </em></p>
<p>控制器接收HTTP请求，并从ActionConfig中找出对应于该请求的Action子类，如果没有对应的Action，控制器直接将请求转发给JSP或者静态页面。否则控制器将请求分发至具体Action类进行处理。</p>
<p>在控制器调用具体Action的execute方法之前，ActionForm对象将利用HTTP请求中的参数来填充自己（可选步骤，需要在配置文件中指定）。具体的ActionForm对象应该是ActionForm的子类对象，它其实就是一个JavaBean。此外，还可以在ActionForm类中调用validate方法来检查请求参数的合法性，并且可以返回一个包含所有错误信息的ActionErrors对象。如果执行成功，ActionForm自动将这些参数信息以JavaBean（一般称之为form bean）的方式保存在Servlet Context中，这样它们就可以被其它Action对象或者JSP调用。</p>
<p>Struts将这些ActionForm的配置信息都放在FormBeanConfig集合中，通过它们Struts能够知道针对某个客户请求是否需要创建相应的ActionForm实例。</p>
<p>Action很简单，一般只包含一个execute方法，它负责执行相应的业务逻辑，如果需要，它也进行相应的数据检查。执行完成之后，返回一个ActionForward对象，控制器通过该ActionForward对象来进行转发工作。我们主张将获取数据和执行业务逻辑的功能放到具体的JavaBean当中，而Action只负责完成与控制有关的功能。遵循该原则，所以在上图中我将Action对象归为控制器部分。</p>
<p><em><strong>提示：</strong>其实在Struts 1.1中，ActionMapping的作用完全可以由ActionConfig来替代，只不过由于它是公共API的一部分以及兼容性的问题得以保留。ActionMapping通过继承ActionConfig来获得与其一致的功能，你可以等同地看待它们。同理，其它例如ActionForward与ForwardConfig的关系也是如此。 </em></p>
<p>下图给出了客户端从发出请求到获得响应整个过程的图解说明。</p>
<p><br />
<img alt="" src="http://www.ibm.com/developerworks/cn/java/l-struts1-1/image003.jpg" /> <br />
</p>
<p>下面我们就来详细地讨论一下其中的每个部分，在这之前，先来了解一下模块的概念。</p>
<p><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/l-struts1-1/#main" cmimpressionsent="1"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
</p>
<p><a name="3"><span class="atitle">模块</span></a></p>
<p>
<p>我们知道，在Struts 1.0中，我们只能在web.xml中为ActionServlet指定一个配置文件，这对于我们这些网上的教学例子来说当然没什么问题，但是在实际的应用开发过程中，可能会有些麻烦。因为许多开发人员都可能同时需要修改配置文件，但是配置文件只能同时被一个人修改，这样肯定会造成一定程度上的资源争夺，势必会影响开发效率和引起开发人员的抱怨。</p>
<p>在Struts 1.1中，为了解决这个并行开发的问题，提出了两种解决方案：
<ol>
    <li>多个配置文件的支持
    <li>模块的支持 </li>
</ol>
<p>&nbsp;</p>
<p>支持多个配置文件，是指你能够为ActionServlet同时指定多个xml配置文件，文件之间以逗号分隔，比如Struts提供的MailReader演示例子中就采用该种方法。</p>
<p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">  &lt;!-- Action Servlet Configuration --&gt;
            &lt;servlet&gt;
            &lt;servlet-name&gt;action&lt;/servlet-name&gt;
            &lt;servlet-class&gt;org.apache.struts.action.ActionServlet&lt;/servlet-class&gt;
            &lt;init-param&gt;
            &lt;param-name&gt;config&lt;/param-name&gt;
            &lt;param-value&gt;/WEB-INF/struts-config.xml, /WEB-INF/struts-config-registration.xml&lt;/param-value&gt;
            &lt;/init-param&gt;
            &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
            &lt;/servlet&gt;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
</p>
<p>这种方法可以很好地解决修改冲突的问题，不同的开发人员可以在不同的配置文件中设置自己的Action、ActionForm等等（当然不是说每个开发人员都需要自己的配置文件，可以按照系统的功能模块进行划分）。但是，这里还是存在一个潜在的问题，就是可能不同的配置文件之间会产生冲突，因为在ActionServlet初始化的时候这几个文件最终还是需要合并到一起的。比如，在struts-config.xml中配置了一个名为success的&lt;forward&gt;，而在struts-config-registration.xml中也配置了一个同样的&lt;forward&gt;，那么执行起来就会产生冲突。</p>
<p>为了彻底解决这种冲突，Struts 1.1中引进了模块（Module）的概念。一个模块就是一个独立的子系统，你可以在其中进行任意所需的配置，同时又不必担心和其它的配置文件产生冲突。因为前面我们讲过，ActionServlet是将不同的模块信息保存在不同的ModuleConfig对象中的。要使用模块的功能，需要进行以下的准备工作：</p>
<p>1、为每个模块准备一个配置文件</p>
<p>2、配置web.xml文件，通知控制器</p>
<p>决定采用多个模块以后，你需要将这些信息告诉控制器，这需要在web.xml文件进行配置。下面是一个典型的多模块配置：</p>
<p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">&lt;init-param&gt;
            &lt;param-name&gt;config&lt;/param-name&gt;
            &lt;param-value&gt;/WEB-INF/struts-config.xml&lt;/param-value&gt;
            &lt;/init-param&gt;
            &lt;init-param&gt;
            &lt;param-name&gt;config/customer&lt;/param-name&gt;
            &lt;param-value&gt;/WEB-INF/struts-config-customer.xml&lt;/param-value&gt;
            &lt;/init-param&gt;
            &lt;init-param&gt;
            &lt;param-name&gt;config/order&lt;/param-name&gt;
            &lt;param-value&gt;/WEB-INF/struts-config-order.xml&lt;/param-value&gt;
            &lt;/init-param&gt;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
</p>
<p>要配置多个模块，你需要在原有的一个&lt;init-param&gt;（在Struts 1.1中将其对应的模块称为缺省模块）的基础之上，增加模块对应的&lt;init-param&gt;。其中&lt;param-name&gt;表示为config/XXX的形式，其中XXX为对应的模块名，&lt;param-value&gt;中还是指定模块对应的配置文件。上面这个例子说明该应用有三个模块，分别是缺省模块、customer和order，它们分别对应不同的配置文件。</p>
<p>3、准备各个模块所需的ActionForm、Action和JSP等资源</p>
<p>但是要注意的是，模块的出现也同时带来了一个问题，即如何在不同模块间进行转发？有两种方法可以实现模块间的转发，一种就是在&lt;forward&gt;（全局或者本地）中定义，另外一种就是利用org.apache.struts.actions.SwitchAction。</p>
<p>下面就是一个全局的例子：</p>
<p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">    ...
            &lt;struts-config&gt;
            ...
            &lt;global-forwards&gt;
            &lt;forward name="toModuleB"
            contextRelative="true"
            path="/moduleB/index.do"
            redirect="true"/&gt;
            ...
            &lt;/global-forwards&gt;
            ...
            &lt;/struts-config&gt;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
</p>
<p>可以看出，只需要在原有的path属性前加上模块名，同时将contextRelative属性置为true即可。此外，你也可以在&lt;action&gt;中定义一个类似的本地&lt;forward&gt;。</p>
<p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">  &lt;action-mappings&gt;
            &lt;!-- Action mapping for profile form --&gt;
            &lt;action path="/login"
            type="com.ncu.test.LoginAction"
            name="loginForm"
            scope="request"
            input="tile.userLogin"
            validate="true"&gt;
            &lt;forward name="success" contextRelative="true" path="/moduleA/login.do"/&gt;
            &lt;/action&gt;
            &lt;/action-mappings&gt;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
</p>
<p>如果你已经处在其他模块，需要转回到缺省模块，那应该类似下面这样定义，即模块名为空。</p>
<p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">&lt;forward name="success" contextRelative="true" path="/login.do"/&gt;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
</p>
<p>此外，你也可以使用org.apache.struts.actions.SwitchAction，例如：</p>
<p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">    ...
            &lt;action-mappings&gt;
            &lt;action path="/toModule"
            type="org.apache.struts.actions.SwitchAction"/&gt;
            ...
            &lt;/action-mappings&gt;
            ...
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/l-struts1-1/#main" cmimpressionsent="1"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
</p>
<p><a name="4"><span class="atitle">ActionServlet</span></a></p>
<p>
<p>我们首先来了解MVC中的控制器。在Struts 1.1中缺省采用ActionServlet类来充当控制器。当然如果ActionServlet不能满足你的需求，你也可以通过继承它来实现自己的类。这可以在/WEB-INF/web.xml中来具体指定。</p>
<p>要掌握ActionServlet，就必须了解它所扮演的角色。首先，ActionServlet表示MVC结构中的控制器部分，它需要完成控制器所需的前端控制及转发请求等职责。其次，ActionServlet被实现为一个专门处理HTTP请求的Servlet，它同时具有servlet的特点。在Struts 1.1中它主要完成以下功能：
<ul>
    <li>接收客户端请求
    <li>根据客户端的URI将请求映射到一个相应的Action类
    <li>从请求中获取数据填充Form Bean（如果需要）
    <li>调用Action类的execute()方法获取数据或者执行业务逻辑
    <li>选择正确的视图响应客户 </li>
</ul>
<p>&nbsp;</p>
<p>此外，ActionServlet还负责初始化和清除应用配置信息的任务。ActionServlet的初始化工作在init方法中完成，它可以分为两个部分：初始化ActionServlet自身的一些信息以及每个模块的配置信息。前者主要通过initInternal、initOther和initServlet三个方法来完成。</p>
<p>我们可以在/WEB-INF/web.xml中指定具体的控制器以及初始参数，由于版本的变化以及Struts 1.1中模块概念的引进，一些初始参数被废弃或者移入到/WEB-INF/struts-config.xml中定义。下面列出所有被废弃的参数，相应地在web.xml文件中也不鼓励再使用。</p>
<ul>
    <li>application
    <li>bufferSize
    <li>content
    <li>debug
    <li>factory
    <li>formBean
    <li>forward
    <li>locale
    <li>mapping
    <li>maxFileSize
    <li>multipartClass
    <li>nocache
    <li>null
    <li>tempDir </li>
</ul>
<p>ActionServlet根据不同的模块来初始化ModuleConfig类，并在其中以XXXconfig集合的方式保存该模块的各种配置信息，比如ActionConfig，FormBeanConfig等。</p>
<p>初始化工作完成之后，ActionServlet准备接收客户请求。针对每个请求，方法process(HttpServletRequest request, HttpServletResponse response)将被调用。该方法指定具体的模块，然后调用该模块的RequestProcessor的process方法。</p>
<p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">protected void process(HttpServletRequest request,
            HttpServletResponse response)
            throws IOException, ServletException {
            RequestUtils.selectModule(request, getServletContext());
            getRequestProcessor(getModuleConfig(request)).process(request, response);
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
</p>
<p>RequestProcessor包含了Struts控制器的所有处理逻辑，它调用不同的processXXX方法来完成不同的处理。下表列出其中几个主要的方法：</p>
<p>
<table border="1">
    <tbody>
        <tr>
            <td>方法</td>
            <td>功能</td>
        </tr>
        <tr>
            <td>processPath</td>
            <td>获取客户端的请求路径</td>
        </tr>
        <tr>
            <td>processMapping</td>
            <td>利用路径来获得相应的ActionMapping</td>
        </tr>
        <tr>
            <td>processActionForm</td>
            <td>初始化ActionForm（如果需要）并存入正确的scope中</td>
        </tr>
        <tr>
            <td>processActionCreate</td>
            <td>初始化Action</td>
        </tr>
        <tr>
            <td>processActionPerform</td>
            <td>调用Action的execute方法</td>
        </tr>
        <tr>
            <td>processForwardConfig</td>
            <td>处理Action返回的ActionForward</td>
        </tr>
    </tbody>
</table>
</p>
<p><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/l-struts1-1/#main" cmimpressionsent="1"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
</p>
<p><a name="5"><span class="atitle">ActionForm</span></a></p>
<p>
<p>对于ActionForm你可以从以下几个方面来理解它：
<ol>
    <li>ActionForm表示HTTP窗体中的数据，可以将其看作是模型和视图的中介，它负责保存视图中的数据供模型或者视图使用。Struts 1.1文档中把它比作HTTP和Action之间的防火墙，这体现了ActionForm具有的过滤保护的作用，只有通过ActionForm验证的数据才能够发送到Action处理。
    <li>ActionForm是与一个或多个ActionConfig关联的JavaBean，在相应的action的execute方法被调用之前，ActionForm会自动利用请求参数来填充自己（初始化属性）。
    <li>ActionForm是一个抽象类，你必须通过继承来实现自己的类。 </li>
</ol>
<p>&nbsp;</p>
<p>ActionForm首先利用属性的getter和setter方法来实现初始化，初始化完毕后，ActionForm的validate方法被调用，你可以在其中来检查请求参数的正确性和有效性，并且可以将错误信息以ActionErrors的形式返回到输入窗体。否则，ActionForm将被作为参数传给action的execute方法以供使用。</p>
<p>ActionForm bean的生命周期可以设置为session（缺省）和request，当设置为session时，记得在reset方法中将所有的属性重新设置为初始值。</p>
<p>由于ActionForm对应于HTTP窗体，所以随着页面的增多，你的ActionForm将会急速增加。而且可能同一类型页面字段将会在不同的ActionForm中出现，并且在每个ActionForm中都存在相同的验证代码。为了解决这个问题，你可以为整个应用实现一个ActionForm或者至少一个模块对应于一个ActionForm。</p>
<p>但是，聚合的代价就是复用性很差，而且难维护。针对这个问题，在Struts 1.1中提出了DynaActionForm的概念。</p>
<p><strong>DynaActionForm类</strong> </p>
<p>DynaActionForm的目的就是减少ActionForm的数目，利用它你不必创建一个个具体的ActionForm类，而是在配置文件中配置出所需的虚拟ActionForm。例如，在下表中通过指定&lt;form-bean&gt;的type为"org.apache.struts.action.DynaActionForm"来创建一个动态的ActionForm--loginForm。</p>
<p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">&lt;form-beans&gt;
            &lt;form-bean name="loginForm" type="org.apache.struts.action.DynaActionForm"&gt;
            &lt;form-property name="actionClass" type="java.lang.String"/&gt;
            &lt;form-property name="username" type="java.lang.String"/&gt;
            &lt;form-property name="password" type="java.lang.String"/&gt;
            &lt;/form-bean&gt;
            &lt;/form-beans&gt;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
</p>
<p>动态的ActionForm的使用方法跟普通的ActionForm相同，但是要注意一点。普通的ActionForm对象需要为每个属性提供getter和setter方法，以上面的例子而言，我们需要提供getUsername() 和 setUsername()方法取得和设置username属性，同样地有一对方法用于取得和设置password属性和actionClass属性。</p>
<p>如果使用DynaActionForm，它将属性保存在一个HashMap类对象中，同时提供相应的get(name) 和 set(name)方法，其中参数name是要访问的属性名。例如要访问DynaActionForm中username的值，可以采用类似的代码：</p>
<p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">String username = (String)form.get("username")；
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
</p>
<p>由于值存放于一个HashMap对象，所以要记得对get()方法返回的Object对象做强制性类型转换。正是由于这点区别，如果你在Action中非常频繁地使用ActionForm对象，建议还是使用普通的ActionForm对象。</p>
<p>在Struts 1.1中，除了DynaActionForm以外，还提供了表单输入自动验证的功能，在包org.apache.struts.validator中提供了许多有用的类，其中最常见的就是DynaValidatorForm类。</p>
<p><strong>DynaValidatorForm类</strong> </p>
<p>DynaValidatorForm是DynaActionForm的子类，它能够提供动态ActionForm和自动表单输入验证的功能。和使用DynaActionForm类似，你必须首先在配置文件中进行配置：</p>
<p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">&lt;form-beans&gt;
            &lt;form-bean name="loginForm" type="org.apache.struts.validator.DynaValidatorForm"&gt;
            &lt;form-property name="actionClass" type="java.lang.String"/&gt;
            &lt;form-property name="username" type="java.lang.String"/&gt;
            &lt;form-property name="password" type="java.lang.String"/&gt;
            &lt;/form-bean&gt;
            &lt;/form-beans&gt;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
</p>
<p>同时要定义验证的插件：</p>
<p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">  &lt;plug-in className="org.apache.struts.validator.ValidatorPlugIn"&gt;
            &lt;set-property property="pathnames"
            value="/WEB-INF/validator-rules.xml,
            /WEB-INF/validation.xml"/&gt;
            &lt;/plug-in&gt;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
</p>
<p>其中的validator.xml和validator-rules.xml分别表示验证定义和验证规则的内容（可以合并在一起），比如针对上例中的DynaValidatorForm，我们有如下验证定义（validator.xml）：</p>
<p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">&lt;?xml version="1.0" encoding="ISO-8859-1" ?&gt;
            &lt;!DOCTYPE form-validation PUBLIC
            "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.0//EN"
            "http://jakarta.apache.org/commons/dtds/validator_1_0.dtd"&gt;
            &lt;!--    Validation Rules    $Id: validation.xml--&gt;
            &lt;form-validation&gt;
            &lt;!-- ========== Default Language Form Definitions ===================== --&gt;
            &lt;formset&gt;
            &lt;form name="loginForm"&gt;
            &lt;field property="username" depends="required, minlength,maxlength"&gt;
            &lt;arg0   key="prompt.username"/&gt;
            &lt;arg1   key="${var:minlength}" name="minlength" resource="false"/&gt;
            &lt;arg2   key="${var:maxlength}" name="maxlength" resource="false"/&gt;
            &lt;var&gt;
            &lt;var-name&gt;maxlength&lt;/var-name&gt;
            &lt;var-value&gt;16&lt;/var-value&gt;
            &lt;/var&gt;
            &lt;var&gt;
            &lt;var-name&gt;minlength&lt;/var-name&gt;
            &lt;var-value&gt;3&lt;/var-value&gt;
            &lt;/var&gt;
            &lt;/field&gt;
            &lt;field property="password" depends="required, minlength,maxlength" bundle="alternate"&gt;
            &lt;arg0   key="prompt.password"/&gt;
            &lt;arg1   key="${var:minlength}" name="minlength" resource="false"/&gt;
            &lt;arg2   key="${var:maxlength}" name="maxlength" resource="false"/&gt;
            &lt;var&gt;
            &lt;var-name&gt;maxlength&lt;/var-name&gt;
            &lt;var-value&gt;16&lt;/var-value&gt;
            &lt;/var&gt;
            &lt;var&gt;
            &lt;var-name&gt;minlength&lt;/var-name&gt;
            &lt;var-value&gt;3&lt;/var-value&gt;
            &lt;/var&gt;
            &lt;/field&gt;
            &lt;/form&gt;
            &lt;/formset&gt;
            &lt;/form-validation&gt;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
</p>
<p>从上述定义中，我们可以看到对于字段username有三项验证：required, minlength, maxlength，意思是该字段不能为空，而且长度在3和16之间。而validator-rules.xml文件则可以采用Struts提供的缺省文件。注意在&lt;form-bean&gt;中定义的form是如何与validation.xml中的form关联起来的。最后，要启动自动验证功能，还需要将Action配置的validate属性设置为true。</p>
<p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">&lt;action path="/login"
            type="com.ncu.test.LoginAction"
            name="loginForm"
            scope="request"
            input="tile.userLogin"validate="true"&gt;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
</p>
<p>此时，Struts将根据xml配置文件中的定义来检验表单输入，并将不符合要求的错误信息输出到页面。但是你可能会想：这个功能虽然好，可是什么检验都跑到服务器端执行，效率方面和用户易用性方面是不是有些问题？你可能会怀念起那简单的JavaScript客户端验证。</p>
<p>不用担心，在Struts 1.1中也支持JavaScript客户端验证。如果你选择了客户端验证，当某个表单被提交以后，Struts 1.1启动客户端验证，如果浏览器不支持JavaScript验证，则服务器端验证被启动，这种双重验证机制能够最大限度地满足各种开发者的需要。JavaScript验证代码也是在validator-rules.xml文件中定义的。要启动客户端验证，你必须在相应的JSP文件中做如下设置：
<ol>
    <li>为&lt;html:form&gt;增加onsubmit属性
    <li>设置Javascript支持 </li>
</ol>
<p>&nbsp;</p>
<p>下表中列出了一JSP文件的示例代码，红字部分为Javascript验证所需代码。</p>
<p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">&lt;%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %&gt;
            &lt;table bgcolor="#9AFF9A" cellspacing="0" cellpadding="10" border="1" width="100%"&gt;
            &lt;tr&gt;
            &lt;td&gt;
            &lt;table cellspacing="0" cellpadding="0" border="0" width="100%"&gt;
            &lt;tr bgcolor="#696969"&gt;
            &lt;td align="center"&gt;
            &lt;font color="#FFFFFF"&gt;Panel 3: Profile&lt;/font&gt;
            &lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
            &lt;td&gt;&lt;br&gt;
            &lt;html:errors/&gt;
            &lt;html:form action="/login.do" focus="username"  onsubmit="return validateLoginForm(this);"&gt;
            &lt;html:hidden property="actionClass"/&gt;
            &lt;center&gt;
            &lt;table&gt;
            &lt;tr&gt;
            &lt;td&gt;UserName:&lt;/td&gt;
            &lt;td&gt;&lt;html:text property="username" size="20"/&gt;&lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
            &lt;td&gt;Password:&lt;/td&gt;
            &lt;td&gt;&lt;html:password property="password" size="20"/&gt;&lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
            &lt;td colspan=2&gt;&lt;html:submit property="submitProperty" value="Submit"/&gt;&lt;/td&gt;
            &lt;/table&gt;
            &lt;/center&gt;
            &lt;/html:form&gt;
            &lt;html:javascript formName="loginForm" dynamicJavascript="true" staticJavascript="false"/&gt;
            &lt;script language="Javascript1.1" src="staticJavascript.jsp"&gt;&lt;/script&gt;
            &lt;/td&gt;
            &lt;/tr&gt;
            &lt;/table&gt;
            &lt;/td&gt;
            &lt;/tr&gt;
            &lt;/table&gt;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
</p>
<p>其中onsubmit的值为"return validateLoginForm(this);"，它的语法为：</p>
<p>return validate + struts-config.xml中定义的form-bean名称 + (this);</p>
<p>staticJavascript.jsp的内容为：</p>
<p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">&lt;%@ page language="java" %&gt;
            &lt;%-- set document type to Javascript (addresses a bug in Netscape according to a web resource --%&gt;
            &lt;%@ page contentType="application/x-javascript" %&gt;
            &lt;%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %&gt;
            &lt;html:javascript dynamicJavascript="false" staticJavascript="true"/&gt;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
</p>
<p>如果validator-rules.xml中定义的基本验证功能不能满足你的需求，你可以自己添加所需的验证类型。</p>
<p><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/l-struts1-1/#main" cmimpressionsent="1"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
</p>
<p><a name="6"><span class="atitle">Action</span></a></p>
<p>
<p>我们通过继承Action类来实现具体的执行类。具体Action类的功能一般都在execute（以前是perform方法）方法中完成，其中主要涉及到以下几个方面：
<ol>
    <li>辅助ActionForm进行一些表单数据的检查。
    <li>执行必要的业务逻辑，比如存取数据库，调用实体bean等。
    <li>更新服务器端的bean数据，后续对象中可能会用到这些数据，比如在JSP中利用bean:write来获得这些数据。
    <li>根据处理结果决定程序的去处，并以ActionForward对象的形式返回给ActionServlet。 </li>
</ol>
<p>&nbsp;</p>
<p><em><strong>提示：</strong>由于在Action和ActionForm中都可以实现验证方法，那么如何来安排它们之间的分工呢？一般来说，我们秉着MVC分离的原则，也就是视图级的验证工作放在ActionForm来完成，比如输入不能为空，email格式是否正确，利用ValidatorForm可以很轻松地完成这些工作。而与具体业务相关的验证则放入Action中，这样就可以获得最大ActionForm重用性的可能。 </em></p>
<p>前面我们提到过，我们主张将业务逻辑执行分离到单独的JavaBean中，而Action只负责错误处理和流程控制。而且考虑到重用性的原因，在执行业务逻辑的JavaBean中不要引用任何与Web应用相关的对象，比如HttpServletRequest，HttpServletResponse等对象，而应该将其转化为普通的Java对象。关于这一点，可以参考Petstore中WAF框架的实现思路。</p>
<p>此外，你可能还注意到execute与perform的一个区别：execute方法简单地掷出Exception异常，而perform方法则掷出ServletException和IOException异常。这不是说Struts 1.1在异常处理功能方面弱化了，而是为了配合Struts 1.1中一个很好的功能--宣称式异常处理机制。</p>
<p><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/l-struts1-1/#main" cmimpressionsent="1"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
</p>
<p><a name="7"><span class="atitle">宣称式异常处理</span></a></p>
<p>
<p>和EJB中的宣称式事务处理概念类似，宣称式异常处理其实就是可配置的异常处理，你可以在配置文件中指定由谁来处理Action类中掷出的某种异常。你可以按照以下步骤来完成该功能：
<ol>
    <li>实现org.apache.struts.action.ExceptionHandler的子类，覆盖execute方法，在该方法中处理异常并且返回一个ActionForward对象
    <li>在配置文件中配置异常处理对象，你可以配置一个全局的处理类或者单独为每个Action配置处理类 </li>
</ol>
<p>&nbsp;</p>
<p>下表就定义了一个全局的处理类CustomizedExceptionHandler，它被用来处理所有的异常。</p>
<p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">&lt;global-exceptions&gt;
            &lt;exception
            handler="com.yourcorp.CustomizedExceptionHandler"
            key="global.error.message"
            path="/error.jsp"
            scope="request"
            type="java.lang.Exception"/&gt;
            &lt;/global-exceptions&gt;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
</p>
<p>其中具体的参数含义，可以参考ExceptionHandler.java源文件。</p>
<p><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/l-struts1-1/#main" cmimpressionsent="1"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
</p>
<p><a name="8"><span class="atitle">taglib</span></a></p>
<p>
<p>讲完了模型和控制器，接下来我们要涉及的是视图。视图的角色主要是由JSP来完成，从JSP的规范中可以看出，在视图层可以"折腾"的技术不是很多，主要的就是自定义标记库的应用。Struts 1.1在原有的四个标记库的基础上新增了两个标记库--Tiles和Nested。</p>
<p>其中Tiles除了替代Template的基本模板功能外，还增加了布局定义、虚拟页面定义和动态页面生成等功能。Tiles强大的模板功能能够使页面获得最大的重用性和灵活性，此外可以结合Tiles配置文件中的页面定义和Action的转发逻辑，即你可以将一个Action转发到一个在Tiles配置文件中定义的虚拟页面，从而减少页面的数量。比如，下表中的Action定义了一个转发路径，它的终点是tile.userMain，而后者是你在Tiles配置文件中定义的一个页面。</p>
<p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">&lt;!-- ========== Action Mapping Definitions ============================== --&gt;
            &lt;action-mappings&gt;
            &lt;!-- Action mapping for profile form --&gt;
            &lt;action path="/login"
            type="com.ncu.test.LoginAction"
            name="loginForm"
            scope="request"
            input="tile.userLogin"
            validate="true"&gt;
            &lt;forward name="success" path="tile.userMain"/&gt;
            &lt;/action&gt;
            &lt;/action-mappings&gt;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
</p>
<p>Tiles配置文件：tiles-defs.xml</p>
<p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">&lt;!DOCTYPE tiles-definitions PUBLIC
            "-//Apache Software Foundation//DTD Tiles Configuration//EN"       "http://jakarta.apache.org/struts/dtds/tiles-config.dtd"&gt;
            &lt;tiles-definitions&gt;
            &lt;!-- =======================================================  --&gt;
            &lt;!-- Master definitions                                       --&gt;
            &lt;!-- =======================================================  --&gt;
            &lt;!-- Page layout used as root for all pages. --&gt;
            &lt;definition name="rootLayout" path="/tiles-layouts/rootLayout.jsp"&gt;
            &lt;put name="titleString" value="CHANGE-ME"/&gt;
            &lt;put name="topMenu" value="/tiles-components/topMenu.jsp"/&gt;
            &lt;put name="leftMenu" value="/tiles-components/panel1.jsp"/&gt;
            &lt;put name="body" value="CHANGE-ME"/&gt;
            &lt;put name="footer" value="/tiles-components/footer.jsp"/&gt;
            &lt;/definition&gt;
            &lt;!-- =======================================================  --&gt;
            &lt;!-- Page definitions 					--&gt;
            &lt;!-- =======================================================  --&gt;
            &lt;!-- User Login page --&gt;
            &lt;definition name="tile.userLogin" extends="rootLayout"&gt;
            &lt;put name="titleString" value="User Login"/&gt;
            &lt;put name="body" value="/src/userLogin.jsp"/&gt;
            &lt;/definition&gt;
            &lt;!-- User Main page --&gt;
            &lt;definition name="tile.userMain" extends="rootLayout"&gt;
            &lt;put name="titleString" value="User Main"/&gt;
            &lt;put name="body" value="/src/userMain.jsp"/&gt;
            &lt;/definition&gt;
            &lt;/tiles-definitions&gt;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
</p>
<p>而Nested标记库的作用是让以上这些基本标记库能够嵌套使用，发挥更大的作用。</p>
<p><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/l-struts1-1/#main" cmimpressionsent="1"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
</p>
<p><a name="9"><span class="atitle">Commons Logging 接口</span></a></p>
<p>
<p>所谓的Commons Logging接口，是指将日志功能的使用与日志具体实现分开，通过配置文件来指定具体使用的日志实现。这样你就可以在Struts 1.1中通过统一的接口来使用日志功能，而不去管具体是利用的哪种日志实现，有点于类似JDBC的功能。Struts 1.1中支持的日志实现包括：Log4J，JDK Logging API， LogKit，NoOpLog和SimpleLog。</p>
<p>你可以按照如下的方式来使用Commons Logging接口（可以参照Struts源文中的许多类实现）：</p>
<p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">package com.foo;
            // ...
            import org.apache.commons.logging.Log;
            import org.apache.commons.logging.LogFactory;
            //...
            public class Foo {
            // ...
            private static Log log = LogFactory.getLog(Foo.class);
            // ...
            public void setBar(Bar bar) {
            if (log.isTraceEnabled()) {
            log.trace("Setting bar to " + bar);
            }
            this.bar = bar;
            }
            // ...
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
</p>
<p>而开启日志功能最简单的办法就是在WEB-INF/classes目录下添加以下两个文件：</p>
<p>commons-logging.properties文件：</p>
<p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode"># Note: The Tiles framework now uses the commons-logging package to output different information or debug statements.
            Please refer to this package documentation to enable it. The simplest way to enable logging is to create two files in
            WEB-INF/classes:
            # commons-logging.properties
            # org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
            # simplelog.properties
            # # Logging detail level,
            # # Must be one of ("trace", "debug", "info", "warn", "error", or "fatal").
            #org.apache.commons.logging.simplelog.defaultlog=trace
            org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
</p>
<p>simplelog.properties文件：</p>
<p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode"># Logging detail level,
            # Must be one of ("trace", "debug", "info", "warn", "error", or "fatal").
            org.apache.commons.logging.simplelog.defaultlog=fatal
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
</p>
<p>这里我们采用的日志实现是SimpleLog，你可以在simplelog.properties文件指定日志明细的级别：trace，debug，info，warn，error和fatal，从trace到fatal错误级别越来越高，同时输出的日志信息也越来越少。而这些级别是和org.apache.commons.logging.log接口中的方法一一对应的。这些级别是向后包含的，也就是前面的级别包含后面级别的信息。</p>
<img src ="http://www.blogjava.net/xinwuhen/aggbug/212013.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2008-07-01 22:10 <a href="http://www.blogjava.net/xinwuhen/archive/2008/07/01/212013.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts配置文件详解----转载</title><link>http://www.blogjava.net/xinwuhen/archive/2008/07/01/211910.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Tue, 01 Jul 2008 07:16:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2008/07/01/211910.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/211910.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2008/07/01/211910.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/211910.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/211910.html</trackback:ping><description><![CDATA[<div id="related_topics" style="position: relative" _eventid="3" _madepositioned="true">相关文章: <span class="close"><a title="关闭" onclick="$('related_topics').hide();return false;" href="http://www.javaeye.com/topic/146902#">&nbsp;</a></span>
<ul>
    <li><a href="http://www.javaeye.com/topic/83869" target="_blank">配置Struts应用--解读Struts应用的两大配置文件</a>
    <li><a href="http://www.javaeye.com/topic/136575" target="_blank">struts配置</a> </li>
</ul>
<br />
<span>推荐圈子: <a href="http://ibm-websphere.group.javaeye.com/" target="_blank">IBM WebSphere专区</a></span> <br />
<a href="http://www.javaeye.com/wiki/topic/146902" target="_blank">更多相关推荐</a> </div>
<script type="text/javascript">
            new Draggable("related_topics");
          </script><span style="color: green">Struts应用采用两个基于XML的配置文件来配置,分别是web.xml和struts-cofig.xml文件.web.xml文件是配置所有 web应用的而struts-config.xml文件是struts专用的配置文件,事实上也是可以根据需要给这个配置文件起其他名称的. <br />
Web应用的发布描述文件:web应用发布描述文件可以在应用开着者,发布者和组装者之间传递配置信息,Web容器在启动的时候从该文件中读取配置信息, 根据它来装载和配置web应用.文档类型定义DTD对XML文档的格式做了定义,DTD吧XML文档划分为元素,属性,实体每一种XML文档都有独自的 DTD文件.可以从网上下载.&lt;web-app&gt;元素是web.xml的根元素,其他元素必须嵌入在&lt;web-app&gt;元素之内.要注意的是子元素也是有顺序的比如必须是首先&lt;servlet&gt;,然后&lt;servlet-mapping&gt;最后&lt; taglib&gt;. <br />
<br />
为Struts应用配置Web.xml文件:首先最重要的一步是配置ActionServlet,这个用&lt;servlet&gt;标签的 servlet-name属性起一个名字叫action,然后用servlet-class属性指定ActionServlet的类.然后用&lt; servlet-mapping&gt;标签的servlet-name属性指定action,在用url-pattern指定接收范围是*.do的请求.不管应用中包含了多少子应用,都只需要配置一个ActionServlet,类来出来应用中的不同的功能,其实者就是不必要的,因为Servlet本身就是多线程的,而且目前Struts只允许配置一个ActionServlet.声明ActionServlet的初始化参数:&lt; servlet&gt;的&lt;init-param&gt;子元素用来配置Servlet的初始化参数.param-name设置config参数名.param-value设置struts-config.xml的路径参数值. <br />
<br />
配置欢迎使用清单:如果客户访问Web的时候值是访问了WEB应用的根目录URL.没有具体的指定文件,Web会自动调用Web的欢迎文件.&lt; welcome-file-list&gt;元素来配置的.通过其中的&lt;welcome-file&gt;欢迎页面&lt;/welcome- file&gt;来配置. <br />
<br />
配置错误处理:尽管Struts框架功能强大的错误处理机制,但是不能保证处理所有的错误或者异常.当错误发生时,如果框架不能处理这种错误,把错误抛弃给Web容器,在默认的情况下web容器会想客户端返回错误信息.如果想避免让客户看到原始的错误信息,可以在Web应用发布描述文件中配置&lt; error-page&gt;元素.通过&lt;error-code&gt;404来定义错误的类型.然后通过&lt;location&gt;要处理错误的JSP页面来对错误进行处理.还可以用&lt;exception-type&gt;来设置异常,然后通过&lt;location&gt;来处理异常的JSP页面来处理异常. <br />
<br />
配置Struts标签库:这个就和以前学到的JSP自定义标签类似,配置元素为&lt;taglib&gt;来配置.&lt;taglib- uri&gt;这个指定标签库的uri,类似起一个名称.&lt;taglib-location&gt;这个是标签库的位置也就是实际所在的路径.通过这样的方法引入一个标签库,然后在前台JSP页面就可以通过自己定义的URI来调用标签. <br />
<br />
Struts配置文件:struts-config.xml文件.首先研讨一下org.apache.struts.config包,在struts应用启动的时候会把Struts配置文件信息读取到内存中,并把它们存放在config包中相关的JavaBean类的实例中.包中的每一个类都和 struts配置文件中特定的配置元素对应,ModuleConfig在Struts框架中扮演了十分重要的角色,它是整个config包的核心,在 Struts运行时来存放整个应用的配置信息.如果有多个子应用都会有一个ModuleConfig对象,它和Struts文件根元素的&lt; struts-config&gt;对应.根元素中包含&lt;form-bean&gt;&lt;action&gt;&lt;forward&gt; 等元素. <br />
<br />
&lt;struts-config&gt;元素:时Struts配置文件的根元素,和它对应的配置类ModuleConfig类,&lt;struts -config&gt;元素有8个子元素.他们的DTD定义是data-sources?form-bean? global-exception?global-forwards?action-mapping?controller?message-resources? plug-in*在Struts配置文件中,必须按照DTD指定的先手顺序来配置&lt;struts-config&gt;元素的各个子元素,如果颠倒了这些子元素的顺序,会产生错误. <br />
<br />
&lt;data-sources&gt;元素:用来配置应用所需要的数据源,数据源负责创建和特定的数据库的连接.许多数据源采用连接池的机制实现.以便提高数据库访问的性能.JAVA语言提供了javax.sql.DataSource接口,所有的数据源都必须实现这个接口.许多应用服务器和Web服务器都提供了数据源组件.很多数据库厂商也提供了数据源的实现.&lt;data-sources&gt;元素包含多个&lt;data- source&gt;子元素永远配置特定的数据源.他们可以包含多个&lt;set-property&gt;子元素用于设置数据源的各种属性.配置了数据源以后,就可以在Action类中访问数据源,在Action中定义了getDataSource(HttpRequest)方法,用于获取数据源对象的引用.然后可以利用DataSource对象调用getConnection获取一个连接对象对数据库进行操作.在配置文件中声明多个数据源的时候需要为每一个数据源分配唯一的Key值,通过这个来表示特定的数据源.获取特定的数据源的时候可以用dataSource = getDataSource(reqeust,&#8221;A&#8221;); <br />
<br />
&lt;form-beans&gt;元素:用来配置多个ActionForm,包含一个或者N个&lt;form-bean&gt;子元素.每个 &lt;form-bean&gt;元素都包含多个属性.className指定和&lt;form-bean&gt;匹配的类.name指定该 ActionForm的唯一标识符,这个属性是必须的以后作为引用使用.type指定ActionForm类的完整类名,这个属性也是必须的.注意包名也要加上.&lt;form-property&gt;是指定动态的Form的元素,以后会深入了解. <br />
<br />
&lt;global-exception&gt;元素:用于配置异常处理,元素可以包含一个或者多个&lt;exception&gt;元素,用来设置 JAVA异常和异常处理类ExceptionHandler之间的映射.className指定和元素对应的配置类,默认的不用动.handler指定异常处理类默认是ExceptionHandler.key指定在本地资源文件中异常的消息Key,path指定当前异常发生的时候转发的路径.scope 指定ActionMessages实例存放的范围.type指定需要处理异常类的名字,必须的.bundle指定Resource Bundle. <br />
<br />
&lt;global-forwards&gt;元素:用来声明全局转发,元素可以有一个或者N个&lt;forward&gt;元素组成,用于把一个逻辑名映射到特定的URL,通过这种方法Action类或者JSP页面无需指定URL,只要指定逻辑名称就可以实现请求转发或者重定向.这样可以减少控制组件和视图的聚合.易于维护.className对应的配置类.contextRelative如果为true表示当path属性以/开头的时候,给出的是对应的上下文URL默认是false.name转发路径的逻辑名,必须写.path转发或者重定向的URL,必须写必须是以/开头.redirect设置为true的时候表示执行重定向操作,此项为false的时候,表示执行请求转发操作.重定向与请求转发的区别以后就是重定向是把请求生成应答给客户端然后在重新发送给定向的URL,浏览器地址栏会有显示.而转发就是直接把请求转发给本应用的另一个文件,不生成应答所以客户端IE没显示. <br />
<br />
&lt;action-mapping&gt;元素:包含一个或者N个&lt;action&gt;元素,描述了从特定的请求路径到响应的Action的映射.在&lt;action&gt;元素中可以包含多个&lt;exception&gt;和&lt;forward&gt;子元素,他们分别配置局部异常处理和局部转发.attribute设置Action关联的ActionForm在request或者session范围内的key.就是在 request或者session共享内的名称.className对应配置元素的类.默认的是ActionMapping.forward指定转发 URL路径include指定包含URL路径.input指定包含表单的URL,当表单验证失败的时候发送的URL.name,指定和该Action关联的Form名字.该名字必须是在form-bean中定义过的,可写可不写.path必须/开头的方位Action的路径.parameter指定 Action配置参数.在Action的execute()方法中可以调用ActionMapping的getParameter()方法来读取匹配的参数.roles指定允许调用该Action的安全角色,多个角色之间逗号格开.scope指定Form的存在范围.默认是session.tyep指定 Action的完整类名.unknown如果是true表示可以处理用户发出的所有的无效的ActionURL默认是false.validate指定是否调用ActionForm的validate方法. <br />
<br />
&lt;controller&gt;元素:用于配置ActionServlet.buffreSize指定上载文件的输入缓冲大小.该属性为可选默认 4096.className指定元素对应的配置类,ControllerConfig.然后是contentType指定响应结果内容类型和字符编码, 该属性为可选,默认是text/html如果在Action或者JSP网页也设置了类型内容,会覆盖这个.locale指定是否把Locale对象保存到当前用户的session中默认false.tempDir指定处理文件上载的临时工作目录.nochache如果是true在响应结果中加入特定的头参数. <br />
<br />
&lt;message-resources&gt;元素:用来配置Resource Bundle.用于存放本地文本消息文件.className元素对应的配置类.MessageResourcesConfig.factory指定消息的工厂类.key指定文件存放的Servlet对象中采用的属性Key.null指定如何处理未知消息.parameter指定消息的文件名. <br />
<br />
&lt;plug-in&gt;元素:用于配置Struts插件. <br />
<br />
配置多应用模块:所有的子应用都可以共享同一个ActionServlet实例,但是每个子应用都有单独的配置文件.把应用划分为多个子应用模块. 首先为每个应用创建单独的Struts配置文件,在web.xml的ActionServlet配置代码中添加几个子应用信息.采用&lt; forward&gt;元素来实现应用之间的切换. <br />
<br />
Digester组件:是一个Apache的另一个开源代码项目.当Struts被初始化的时候,首先会读取并解析配置文件,框架采用Digester组件来且西配置文件.然后创建config包中的对象.者对象用于存放配置信息. <br />
<br />
其实配置文件不难,只要都理其中的原理就OK了.真正实际的项目开发中,采用的工具例如Eclipse系列,提供了相应的插件,在创建一个Struts工程的时候配置文件的标签都是自动生成的,而我们只需要往里面填写属性就OK了. <br />
</span>
<img src ="http://www.blogjava.net/xinwuhen/aggbug/211910.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2008-07-01 15:16 <a href="http://www.blogjava.net/xinwuhen/archive/2008/07/01/211910.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>搭建MyEclipse+Tomcat开发环境</title><link>http://www.blogjava.net/xinwuhen/archive/2008/06/30/211769.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Mon, 30 Jun 2008 14:26:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2008/06/30/211769.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/211769.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2008/06/30/211769.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/211769.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/211769.html</trackback:ping><description><![CDATA[<p align="left">本文转自:http://esoft.bokee.com/5081515.html</p>
<p>一、安装JDK<br />
首先下载JDK 5.0 Update7（JDK 5.0 Update7的下载页面为：<br />
<a href="http://java.sun.com/javase/downloads/index.jsp">http://java.sun.com/javase/downloads/index.jsp</a>）；<br />
然后运行JDK 5.0安装程序jdk-1_5_0_07-windows-i586-p.exe，安装过程中所有选项保持默认；<br />
最后配置JDK的环境变量：在&#8220;我的电脑&#8221;上点右键—&gt;&#8220;属性&#8221;—&gt;&#8220;高级&#8221;—&gt; &#8220;环境变量(N)&#8221;。<br />
<img alt=" " src="http://esoft.bokee.com/inc/J2EE_01.jpg" onload="function anonymous()&#13;&#10;{&#13;&#10;function anonymous()&#13;&#10;{&#13;&#10;function onload(event) {&#13;&#10;&#13;&#10;    function anonymous() {&#13;&#10;&#13;&#10;        function anonymous() {&#13;&#10;&#13;&#10;            function anonymous() {&#13;&#10;&#13;&#10;                function anonymous() {&#13;&#10;&#13;&#10;                    function anonymous() {&#13;&#10;&#13;&#10;                        function anonymous() {&#13;&#10;&#13;&#10;                            function anonymous() {&#13;&#10;&#13;&#10;                                function anonymous() {&#13;&#10;&#13;&#10;                                    function anonymous() {&#13;&#10;&#13;&#10;                                        function anonymous() {&#13;&#10;&#13;&#10;                                            function anonymous() {&#13;&#10;                                                img_auto_size(this, 450, true);&#13;&#10;                                            }&#13;&#10;&#13;&#10;                                        }&#13;&#10;&#13;&#10;                                    }&#13;&#10;&#13;&#10;                                }&#13;&#10;&#13;&#10;                            }&#13;&#10;&#13;&#10;                        }&#13;&#10;&#13;&#10;                    }&#13;&#10;&#13;&#10;                }&#13;&#10;&#13;&#10;            }&#13;&#10;&#13;&#10;        }&#13;&#10;&#13;&#10;    }&#13;&#10;&#13;&#10;}&#13;&#10;}&#13;&#10;}" align="bottom" twffan="done" /></p>
<p>新建系统变量JAVA_HOME：C:\Program Files\Java\jdk1.5.0_06<br />
新建系统变量CLASSPATH：.;%JAVA_HOME%\lib;（注意：点号表示当前目录，不能省略）<br />
在系统变量Path的值的<strong>前面</strong>加入以下内容：%JAVA_HOME%\bin;(注意:这里的分号不能省略)<br />
到这里，JDK安装完毕。<br />
下面我们测试一下JDK是否安装成功：<br />
将以下内容复制到记事本中：<br />
public class HelloJAVA<br />
{<br />
public static void main(String srg[])<br />
{<br />
System.out.println("Hello JAVA!");<br />
}<br />
}<br />
另存为&#8220;HelloJAVA.java&#8221;（不含引号，下同），并保存到D盘根目录下。<br />
在命令行依次输入下图中红线所标注的命令：<br />
<img alt=" " src="http://esoft.bokee.com/inc/J2EE_02.jpg" onload="function anonymous()&#13;&#10;{&#13;&#10;function anonymous()&#13;&#10;{&#13;&#10;function onload(event) {&#13;&#10;&#13;&#10;    function anonymous() {&#13;&#10;&#13;&#10;        function anonymous() {&#13;&#10;&#13;&#10;            function anonymous() {&#13;&#10;&#13;&#10;                function anonymous() {&#13;&#10;&#13;&#10;                    function anonymous() {&#13;&#10;&#13;&#10;                        function anonymous() {&#13;&#10;&#13;&#10;                            function anonymous() {&#13;&#10;&#13;&#10;                                function anonymous() {&#13;&#10;&#13;&#10;                                    function anonymous() {&#13;&#10;&#13;&#10;                                        function anonymous() {&#13;&#10;&#13;&#10;                                            function anonymous() {&#13;&#10;                                                img_auto_size(this, 450, true);&#13;&#10;                                            }&#13;&#10;&#13;&#10;                                        }&#13;&#10;&#13;&#10;                                    }&#13;&#10;&#13;&#10;                                }&#13;&#10;&#13;&#10;                            }&#13;&#10;&#13;&#10;                        }&#13;&#10;&#13;&#10;                    }&#13;&#10;&#13;&#10;                }&#13;&#10;&#13;&#10;            }&#13;&#10;&#13;&#10;        }&#13;&#10;&#13;&#10;    }&#13;&#10;&#13;&#10;}&#13;&#10;}&#13;&#10;}" align="bottom" twffan="done" /></p>
<p>如果出现上图红框中所标注的内容，则说明JDK安装成功！</p>
<p>注意:如果以后要安装诸如Eclipse、Borland JBuilder、JCreator、IntelliJ IDEA等集成开发环境(IDE,Integrated Development Environment),应该在IDE中编译运行一个简单的HelloWorld程序，以保证IDE可以识别出JDK的位置。</p>
<p>二、安装Tomcat<br />
首先下载jakarta-tomcat-5.0.30.zip，之所以下载免安装版的好处是可以使用多个Tomcat（jakarta-tomcat-5.0.30.zip的下载页面为：<br />
<a href="http://apache.linuxforum.net/tomcat/tomcat-5/v5.0.30/bin/">http://apache.linuxforum.net/tomcat/tomcat-5/v5.0.30/bin/</a>）；<br />
然后将jakarta-tomcat-5.0.30.zip直接解压到D盘根目录：</p>
<p><img alt=" " src="http://esoft.bokee.com/inc/J2EE_03.jpg" onload="function anonymous()&#13;&#10;{&#13;&#10;function anonymous()&#13;&#10;{&#13;&#10;function onload(event) {&#13;&#10;&#13;&#10;    function anonymous() {&#13;&#10;&#13;&#10;        function anonymous() {&#13;&#10;&#13;&#10;            function anonymous() {&#13;&#10;&#13;&#10;                function anonymous() {&#13;&#10;&#13;&#10;                    function anonymous() {&#13;&#10;&#13;&#10;                        function anonymous() {&#13;&#10;&#13;&#10;                            function anonymous() {&#13;&#10;&#13;&#10;                                function anonymous() {&#13;&#10;&#13;&#10;                                    function anonymous() {&#13;&#10;&#13;&#10;                                        function anonymous() {&#13;&#10;&#13;&#10;                                            function anonymous() {&#13;&#10;                                                img_auto_size(this, 450, true);&#13;&#10;                                            }&#13;&#10;&#13;&#10;                                        }&#13;&#10;&#13;&#10;                                    }&#13;&#10;&#13;&#10;                                }&#13;&#10;&#13;&#10;                            }&#13;&#10;&#13;&#10;                        }&#13;&#10;&#13;&#10;                    }&#13;&#10;&#13;&#10;                }&#13;&#10;&#13;&#10;            }&#13;&#10;&#13;&#10;        }&#13;&#10;&#13;&#10;    }&#13;&#10;&#13;&#10;}&#13;&#10;}&#13;&#10;}" align="bottom" twffan="done" /></p>
<p>最后配置Tomcat的环境变量：在&#8220;我的电脑&#8221;上点右键—&gt;&#8220;属性&#8221;—&gt;&#8220;高级&#8221;—&gt; &#8220;环境变量(N)&#8221;。<br />
新建系统变量CATALINA_HOME：D:\jakarta-tomcat-5.0.30<br />
在系统变量CLASSPATH的值的<strong>后面</strong>加入：%CATALINA_HOME%\common\lib;<br />
在系统变量Path的值中"%JAVA_HOME%\bin;"的<strong>后面</strong>加入以下内容：%CATALINA_HOME%\bin;</p>
<p>到这里，Tomcat安装完毕。</p>
<p>相关链接：<br />
<a href="http://www.coreservlets.com/Apache-Tomcat-Tutorial/Tomcat-5.0and-4.0.html"><font color="#3300ff">Tomcat 4和Tomcat 5安装配置指南<br />
</font></a><a href="http://www.coreservlets.com/Apache-Tomcat-Tutorial/"><font color="#0000ff">Tomcat 5.5安装配置指南</font></a> </p>
<p>进行完一、二两步的设置以后，各系统变量的值如下：</p>
<p>JAVA_HOME:C:\Program Files\Java\jdk1.5.0_06<br />
CATALINA_HOME:D:\jakarta-tomcat-5.0.30<br />
CLASSPATH:.;%JAVA_HOME%\lib;%CATALINA_HOME%\common\lib;<br />
Path:%JAVA_HOME%\bin;%CATALINA_HOME%\bin;%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem</p>
<p>三、安装Eclipse<br />
首先下载eclipse-SDK-3.1.2-win32.zip（eclipse-SDK-3.1.2-win32.zip下载地址为：<br />
<a href="http://www.eclipse.org/downloads/">http://www.eclipse.org/downloads/</a>）；<br />
然后将eclipse-SDK-3.1.2-win32.zip直接解压到D盘根目录：<br />
<img alt=" " src="http://esoft.bokee.com/inc/J2EE_04.jpg" onload="function anonymous()&#13;&#10;{&#13;&#10;function anonymous()&#13;&#10;{&#13;&#10;function onload(event) {&#13;&#10;&#13;&#10;    function anonymous() {&#13;&#10;&#13;&#10;        function anonymous() {&#13;&#10;&#13;&#10;            function anonymous() {&#13;&#10;&#13;&#10;                function anonymous() {&#13;&#10;&#13;&#10;                    function anonymous() {&#13;&#10;&#13;&#10;                        function anonymous() {&#13;&#10;&#13;&#10;                            function anonymous() {&#13;&#10;&#13;&#10;                                function anonymous() {&#13;&#10;&#13;&#10;                                    function anonymous() {&#13;&#10;&#13;&#10;                                        function anonymous() {&#13;&#10;&#13;&#10;                                            function anonymous() {&#13;&#10;                                                img_auto_size(this, 450, true);&#13;&#10;                                            }&#13;&#10;&#13;&#10;                                        }&#13;&#10;&#13;&#10;                                    }&#13;&#10;&#13;&#10;                                }&#13;&#10;&#13;&#10;                            }&#13;&#10;&#13;&#10;                        }&#13;&#10;&#13;&#10;                    }&#13;&#10;&#13;&#10;                }&#13;&#10;&#13;&#10;            }&#13;&#10;&#13;&#10;        }&#13;&#10;&#13;&#10;    }&#13;&#10;&#13;&#10;}&#13;&#10;}&#13;&#10;}" align="bottom" twffan="done" /> </p>
<p>到这里， Eclipse安装完毕。</p>
<p>四、安装MyEclipse<br />
首先下载EnterpriseWorkbenchInstaller_4.1.1GA_E3.1.exe（EnterpriseWorkbenchInstaller_4.1.1GA_E3.1.exe 的下载地址为：<br />
<a href="http://www.myeclipseide.com/ContentExpress-display-ceid-10.html"><span style="text-decoration: underline" twffan="done">http://www.myeclipseide.com/ContentExpress-display-ceid-10.html</span></a>）；<br />
然后安装EnterpriseWorkbenchInstaller_4.1.1GA_E3.1.exe。注意：当安装到下图所示的步骤的时候要选择Eclipse的安装路径（如图），其他选项保持默认。<br />
<img alt=" " src="http://esoft.bokee.com/inc/J2EE_05.jpg" onload="function anonymous()&#13;&#10;{&#13;&#10;function anonymous()&#13;&#10;{&#13;&#10;function onload(event) {&#13;&#10;&#13;&#10;    function anonymous() {&#13;&#10;&#13;&#10;        function anonymous() {&#13;&#10;&#13;&#10;            function anonymous() {&#13;&#10;&#13;&#10;                function anonymous() {&#13;&#10;&#13;&#10;                    function anonymous() {&#13;&#10;&#13;&#10;                        function anonymous() {&#13;&#10;&#13;&#10;                            function anonymous() {&#13;&#10;&#13;&#10;                                function anonymous() {&#13;&#10;&#13;&#10;                                    function anonymous() {&#13;&#10;&#13;&#10;                                        function anonymous() {&#13;&#10;&#13;&#10;                                            function anonymous() {&#13;&#10;                                                img_auto_size(this, 450, true);&#13;&#10;                                            }&#13;&#10;&#13;&#10;                                        }&#13;&#10;&#13;&#10;                                    }&#13;&#10;&#13;&#10;                                }&#13;&#10;&#13;&#10;                            }&#13;&#10;&#13;&#10;                        }&#13;&#10;&#13;&#10;                    }&#13;&#10;&#13;&#10;                }&#13;&#10;&#13;&#10;            }&#13;&#10;&#13;&#10;        }&#13;&#10;&#13;&#10;    }&#13;&#10;&#13;&#10;}&#13;&#10;}&#13;&#10;}" align="bottom" twffan="done" /></p>
<p>安装完毕之后，将MyEclipse安装目录下的features和plugins这2个目录覆盖到Eclipse的安装目录下。<br />
最后将刚才安装的 MyEclipse 卸载。<br />
解释一下上面这样做的原因： 因为MyEclipse是Eclipse的插件，所以只要把features和plugins这2个目录覆盖到Eclipse的安装目录，Eclipse就会自动认出这些插件。 <br />
到这里，MyEclipse安装完毕。</p>
<p>五、破解MyEclipse<br />
运行MyEclipse4.1.1注册机MyEclipseKeyGen.exe，选择MyEclipse的版本号，输入注册名，生成序列号。（MyEclipse4.x注册机的下载地址为：<br />
<a href="http://esoft.g8.com.cn/UploadFiles/2006-5/520753587.rar">http://esoft.g8.com.cn/UploadFiles/2006-5/520753587.rar</a>）<br />
运行eclipse.exe（首次运行要求指定Workspace），依次点击Window ----&gt; Preferences ----&gt;MyEclipse----&gt;Subscription ----&gt; Enter Subscription，输入注册名以及注册机生成的注册码。<br />
到这里，MyEclipse破解完毕。</p>
<p>六、指定Eclipse+MyEclipse的JRE 和Tomcat 服务器<br />
1.设定Eclipse+MyEclipse的JRE<br />
一般情况下，Eclipse可以自动找到JRE，我们不用进行过多的设置。<br />
2.设定Eclipse+MyEclipse的Tomcat 服务器<br />
只需设置图中所标注的两处即可，图中其余部分是自动生成的。<br />
<img alt=" " src="http://esoft.bokee.com/inc/J2EE_06.jpg" onload="function anonymous()&#13;&#10;{&#13;&#10;function anonymous()&#13;&#10;{&#13;&#10;function onload(event) {&#13;&#10;&#13;&#10;    function anonymous() {&#13;&#10;&#13;&#10;        function anonymous() {&#13;&#10;&#13;&#10;            function anonymous() {&#13;&#10;&#13;&#10;                function anonymous() {&#13;&#10;&#13;&#10;                    function anonymous() {&#13;&#10;&#13;&#10;                        function anonymous() {&#13;&#10;&#13;&#10;                            function anonymous() {&#13;&#10;&#13;&#10;                                function anonymous() {&#13;&#10;&#13;&#10;                                    function anonymous() {&#13;&#10;&#13;&#10;                                        function anonymous() {&#13;&#10;&#13;&#10;                                            function anonymous() {&#13;&#10;                                                img_auto_size(this, 450, true);&#13;&#10;                                            }&#13;&#10;&#13;&#10;                                        }&#13;&#10;&#13;&#10;                                    }&#13;&#10;&#13;&#10;                                }&#13;&#10;&#13;&#10;                            }&#13;&#10;&#13;&#10;                        }&#13;&#10;&#13;&#10;                    }&#13;&#10;&#13;&#10;                }&#13;&#10;&#13;&#10;            }&#13;&#10;&#13;&#10;        }&#13;&#10;&#13;&#10;    }&#13;&#10;&#13;&#10;}&#13;&#10;}&#13;&#10;}" align="bottom" twffan="done" /></p>
<p>到这里，我们的Eclipse+MyEclipse开发环境就搭建完毕了！</p>
<p>七、新建一个项目来测试一下Eclipse+MyEclipse开发环境是否搭建成功<br />
1.在Eclipse中依次点击&#8220; File ----&gt; New ----&gt; Project&#8221; , 在弹出的&#8220;New Project&#8221;对话框中依次点击&#8220;Web Project ----&gt;MyEclipse----&gt;J2EE Projects----&gt;Web Project&#8221;， 再点&#8220;Next&#8221;，在&#8220;Project Name&#8221;中输入项目的名字&#8220;test&#8221;,最后点&#8220;Finish&#8221;。<br />
2.在Eclipse左边Package Explorer列表中点击&#8220;test&#8221;，将项目test展开。右键点击 WebRoot ----&gt; New ----&gt; JSP , 新建一个名为hello.jsp的 JSP 页面 。 代码如下图（图中标注部分需要我们手动添加，其余部分是系统自动生成的）：</p>
<p><img alt=" " src="http://esoft.bokee.com/inc/J2EE_07.png" onload="function anonymous()&#13;&#10;{&#13;&#10;function anonymous()&#13;&#10;{&#13;&#10;function onload(event) {&#13;&#10;&#13;&#10;    function anonymous() {&#13;&#10;&#13;&#10;        function anonymous() {&#13;&#10;&#13;&#10;            function anonymous() {&#13;&#10;&#13;&#10;                function anonymous() {&#13;&#10;&#13;&#10;                    function anonymous() {&#13;&#10;&#13;&#10;                        function anonymous() {&#13;&#10;&#13;&#10;                            function anonymous() {&#13;&#10;&#13;&#10;                                function anonymous() {&#13;&#10;&#13;&#10;                                    function anonymous() {&#13;&#10;&#13;&#10;                                        function anonymous() {&#13;&#10;&#13;&#10;                                            function anonymous() {&#13;&#10;                                                img_auto_size(this, 450, true);&#13;&#10;                                            }&#13;&#10;&#13;&#10;                                        }&#13;&#10;&#13;&#10;                                    }&#13;&#10;&#13;&#10;                                }&#13;&#10;&#13;&#10;                            }&#13;&#10;&#13;&#10;                        }&#13;&#10;&#13;&#10;                    }&#13;&#10;&#13;&#10;                }&#13;&#10;&#13;&#10;            }&#13;&#10;&#13;&#10;        }&#13;&#10;&#13;&#10;    }&#13;&#10;&#13;&#10;}&#13;&#10;}&#13;&#10;}" align="bottom" twffan="done" /><br />
<br />
3. 再用同样的方法， 新建一个叫 hello_result.jsp 的JSP文件， 代码如下图：<br />
<img alt=" " src="http://esoft.bokee.com/inc/J2EE_08.png" onload="function anonymous()&#13;&#10;{&#13;&#10;function anonymous()&#13;&#10;{&#13;&#10;function onload(event) {&#13;&#10;&#13;&#10;    function anonymous() {&#13;&#10;&#13;&#10;        function anonymous() {&#13;&#10;&#13;&#10;            function anonymous() {&#13;&#10;&#13;&#10;                function anonymous() {&#13;&#10;&#13;&#10;                    function anonymous() {&#13;&#10;&#13;&#10;                        function anonymous() {&#13;&#10;&#13;&#10;                            function anonymous() {&#13;&#10;&#13;&#10;                                function anonymous() {&#13;&#10;&#13;&#10;                                   function anonymous() {&#13;&#10;&#13;&#10;                                        function anonymous() {&#13;&#10;&#13;&#10;                                            function anonymous() {&#13;&#10;                                                img_auto_size(this, 450, true);&#13;&#10;                                            }&#13;&#10;&#13;&#10;                                        }&#13;&#10;&#13;&#10;                                    }&#13;&#10;&#13;&#10;                                }&#13;&#10;&#13;&#10;                            }&#13;&#10;&#13;&#10;                        }&#13;&#10;&#13;&#10;                    }&#13;&#10;&#13;&#10;                }&#13;&#10;&#13;&#10;            }&#13;&#10;&#13;&#10;        }&#13;&#10;&#13;&#10;    }&#13;&#10;&#13;&#10;}&#13;&#10;}&#13;&#10;}" align="bottom" twffan="done" /></p>
<p>4. deploy（部署）项目。 <br />
点击 deploy 按钮（用红线画了的按钮就是 deploy 按钮）， 在弹出的窗口中点击Add， 部署test项目（如图所示）。<br />
<img alt=" " src="http://esoft.bokee.com/inc/J2EE_09.jpg" onload="function anonymous()&#13;&#10;{&#13;&#10;function anonymous()&#13;&#10;{&#13;&#10;function onload(event) {&#13;&#10;&#13;&#10;    function anonymous() {&#13;&#10;&#13;&#10;        function anonymous() {&#13;&#10;&#13;&#10;            function anonymous() {&#13;&#10;&#13;&#10;                function anonymous() {&#13;&#10;&#13;&#10;                    function anonymous() {&#13;&#10;&#13;&#10;                        function anonymous() {&#13;&#10;&#13;&#10;                            function anonymous() {&#13;&#10;&#13;&#10;                                function anonymous() {&#13;&#10;&#13;&#10;                                    function anonymous() {&#13;&#10;&#13;&#10;                                        function anonymous() {&#13;&#10;&#13;&#10;                                            function anonymous() {&#13;&#10;                                                img_auto_size(this, 450, true);&#13;&#10;                                            }&#13;&#10;&#13;&#10;                                        }&#13;&#10;&#13;&#10;                                    }&#13;&#10;&#13;&#10;                                }&#13;&#10;&#13;&#10;                            }&#13;&#10;&#13;&#10;                        }&#13;&#10;&#13;&#10;                    }&#13;&#10;&#13;&#10;                }&#13;&#10;&#13;&#10;            }&#13;&#10;&#13;&#10;        }&#13;&#10;&#13;&#10;    }&#13;&#10;&#13;&#10;}&#13;&#10;}&#13;&#10;}" align="bottom" twffan="done" /></p>
<p>5. 启动Tomcat服务器。<br />
如下图所示（用红线画了的按钮就是 启动Tomcat 的按钮）：</p>
<p><img alt=" " src="http://esoft.bokee.com/inc/J2EE_10.jpg" onload="function anonymous()&#13;&#10;{&#13;&#10;function anonymous()&#13;&#10;{&#13;&#10;function onload(event) {&#13;&#10;&#13;&#10;    function anonymous() {&#13;&#10;&#13;&#10;        function anonymous() {&#13;&#10;&#13;&#10;            function anonymous() {&#13;&#10;&#13;&#10;                function anonymous() {&#13;&#10;&#13;&#10;                    function anonymous() {&#13;&#10;&#13;&#10;                        function anonymous() {&#13;&#10;&#13;&#10;                            function anonymous() {&#13;&#10;&#13;&#10;                                function anonymous() {&#13;&#10;&#13;&#10;                                    function anonymous() {&#13;&#10;&#13;&#10;                                        function anonymous() {&#13;&#10;&#13;&#10;                                            function anonymous() {&#13;&#10;                                                img_auto_size(this, 450, true);&#13;&#10;                                            }&#13;&#10;&#13;&#10;                                        }&#13;&#10;&#13;&#10;                                    }&#13;&#10;&#13;&#10;                                }&#13;&#10;&#13;&#10;                            }&#13;&#10;&#13;&#10;                        }&#13;&#10;&#13;&#10;                    }&#13;&#10;&#13;&#10;                }&#13;&#10;&#13;&#10;            }&#13;&#10;&#13;&#10;        }&#13;&#10;&#13;&#10;    }&#13;&#10;&#13;&#10;}&#13;&#10;}&#13;&#10;}" align="bottom" twffan="done" /></p>
<p>Tomcat 启动输出信息如下图：<br />
<img alt=" " src="http://esoft.bokee.com/inc/J2EE_11.jpg" onload="function anonymous()&#13;&#10;{&#13;&#10;function anonymous()&#13;&#10;{&#13;&#10;function onload(event) {&#13;&#10;&#13;&#10;    function anonymous() {&#13;&#10;&#13;&#10;        function anonymous() {&#13;&#10;&#13;&#10;            function anonymous() {&#13;&#10;&#13;&#10;                function anonymous() {&#13;&#10;&#13;&#10;                    function anonymous() {&#13;&#10;&#13;&#10;                        function anonymous() {&#13;&#10;&#13;&#10;                            function anonymous() {&#13;&#10;&#13;&#10;                                function anonymous() {&#13;&#10;&#13;&#10;                                    function anonymous() {&#13;&#10;&#13;&#10;                                        function anonymous() {&#13;&#10;&#13;&#10;                                            function anonymous() {&#13;&#10;                                                img_auto_size(this, 450, true);&#13;&#10;                                            }&#13;&#10;&#13;&#10;                                        }&#13;&#10;&#13;&#10;                                    }&#13;&#10;&#13;&#10;                                }&#13;&#10;&#13;&#10;                            }&#13;&#10;&#13;&#10;                        }&#13;&#10;&#13;&#10;                    }&#13;&#10;&#13;&#10;                }&#13;&#10;&#13;&#10;            }&#13;&#10;&#13;&#10;        }&#13;&#10;&#13;&#10;    }&#13;&#10;&#13;&#10;}&#13;&#10;}&#13;&#10;}" align="bottom" twffan="done" /></p>
<p>6.项目test的运行结果：<br />
<img alt=" " src="http://esoft.bokee.com/inc/J2EE_12.jpg" onload="function anonymous()&#13;&#10;{&#13;&#10;function anonymous()&#13;&#10;{&#13;&#10;function onload(event) {&#13;&#10;&#13;&#10;    function anonymous() {&#13;&#10;&#13;&#10;        function anonymous() {&#13;&#10;&#13;&#10;            function anonymous() {&#13;&#10;&#13;&#10;                function anonymous() {&#13;&#10;&#13;&#10;                    function anonymous() {&#13;&#10;&#13;&#10;                        function anonymous() {&#13;&#10;&#13;&#10;                            function anonymous() {&#13;&#10;&#13;&#10;                                function anonymous() {&#13;&#10;&#13;&#10;                                    function anonymous() {&#13;&#10;&#13;&#10;                                        function anonymous() {&#13;&#10;&#13;&#10;                                            function anonymous() {&#13;&#10;                                                img_auto_size(this, 450, true);&#13;&#10;                                            }&#13;&#10;&#13;&#10;                                        }&#13;&#10;&#13;&#10;                                    }&#13;&#10;&#13;&#10;                                }&#13;&#10;&#13;&#10;                            }&#13;&#10;&#13;&#10;                        }&#13;&#10;&#13;&#10;                    }&#13;&#10;&#13;&#10;                }&#13;&#10;&#13;&#10;            }&#13;&#10;&#13;&#10;        }&#13;&#10;&#13;&#10;    }&#13;&#10;&#13;&#10;}&#13;&#10;}&#13;&#10;}" align="bottom" twffan="done" /> </p>
<p>我们可以去Eclipse的Workspace目录下看看test项目的代码，也可以去Tomcat的webapps目录下，看看部署之后的 test项目的结构。<br />
</p>
<img src ="http://www.blogjava.net/xinwuhen/aggbug/211769.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2008-06-30 22:26 <a href="http://www.blogjava.net/xinwuhen/archive/2008/06/30/211769.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用DTree实现树型结构数据展现</title><link>http://www.blogjava.net/xinwuhen/archive/2008/06/03/205483.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Tue, 03 Jun 2008 01:48:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2008/06/03/205483.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/205483.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2008/06/03/205483.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/205483.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/205483.html</trackback:ping><description><![CDATA[<div class="postbody clearfix">这两天发现了dtree,做的很不错,想和大家交流一下 <br />
下载地址：<a href="http://www.destroydrop.com/javascripts/tree/dtree.zip" target="_blank">http://www.destroydrop.com/javascripts/tree/dtree.zip</a> <br />
或从附件里下载 <br />
看看里面的example01.html例子。 <br />
在这个基础上我做了一个动态的树型结构数据的展现（其实就是动态生成js代码而已）。 <br />
java类代码 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" href="http://www.javaeye.com/topic/32245#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span class="keyword">import</span><span>&nbsp;java.io.Serializable; &nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;TreeNode&nbsp;</span><span class="keyword">implements</span><span>&nbsp;Serializable{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;String&nbsp;id&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//节点编号 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;String&nbsp;pid&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//父节点编号 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;String&nbsp;name&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//节点名称 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;String&nbsp;url&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//链接地址 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;String&nbsp;title&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//节点描述 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;String&nbsp;target&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//Target </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;String&nbsp;icon&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//图标路径 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;String&nbsp;iconOpen&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//展开状态下的图标路径 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;String&nbsp;open&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//是否展开 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//构造函数 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;TreeNode(){ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;id&nbsp;=&nbsp;</span><span class="string">""</span><span>&nbsp;; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pid&nbsp;=&nbsp;</span><span class="string">""</span><span>&nbsp;; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name&nbsp;=&nbsp;</span><span class="string">""</span><span>&nbsp;; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;url&nbsp;=&nbsp;</span><span class="string">""</span><span>&nbsp;; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;title&nbsp;=&nbsp;</span><span class="string">""</span><span>&nbsp;; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;target&nbsp;=&nbsp;</span><span class="string">""</span><span>&nbsp;; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;icon&nbsp;=&nbsp;</span><span class="string">""</span><span>&nbsp;; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iconOpen&nbsp;=&nbsp;</span><span class="string">""</span><span>&nbsp;; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;open&nbsp;=&nbsp;</span><span class="string">""</span><span>&nbsp;; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//------get&nbsp;set&nbsp;functions</span><span>&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">import java.io.Serializable;
public class TreeNode implements Serializable{
private String id ;          //节点编号
private String pid ;         //父节点编号
private String name ;        //节点名称
private String url ;         //链接地址
private String title ;       //节点描述
private String target ;      //Target
private String icon ;        //图标路径
private String iconOpen ;    //展开状态下的图标路径
private String open ;        //是否展开
//构造函数
public TreeNode(){
id = "" ;
pid = "" ;
name = "" ;
url = "" ;
title = "" ;
target = "" ;
icon = "" ;
iconOpen = "" ;
open = "" ;
}
//------get set functions
</pre>
<br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" href="http://www.javaeye.com/topic/32245#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;TreeNodeUtil&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//返回js代码 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;String&nbsp;createJsArray(TreeNode[]&nbsp;tn&nbsp;,&nbsp;String&nbsp;dtree)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>(tn&nbsp;==&nbsp;</span><span class="keyword">null</span><span>&nbsp;||&nbsp;tn.length&nbsp;==&nbsp;</span><span class="number">0</span><span>&nbsp;){ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span class="string">"TreeNode&nbsp;is&nbsp;empty"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;</span><span class="string">""</span><span>; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StringBuffer&nbsp;contents&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;StringBuffer(</span><span class="number">100</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents.append(</span><span class="string">"new&nbsp;dTree('"</span><span>+dtree+</span><span class="string">"');"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">for</span><span>&nbsp;(</span><span class="keyword">int</span><span>&nbsp;i&nbsp;=&nbsp;</span><span class="number">0</span><span>;&nbsp;i&nbsp;&lt;&nbsp;tn.length;&nbsp;i++)&nbsp;{&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents.append(</span><span class="string">"\n"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents.append(dtree+</span><span class="string">".add('"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents.append(tn[i].getId()); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents.append(</span><span class="string">"','"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents.append(tn[i].getPid()); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents.append(</span><span class="string">"','"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents.append(tn[i].getName()); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents.append(</span><span class="string">"','"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents.append(tn[i].getUrl()); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents.append(</span><span class="string">"','"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents.append(tn[i].getTitle()); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents.append(</span><span class="string">"','"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents.append(tn[i].getTarget()); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents.append(</span><span class="string">"','"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents.append(tn[i].getIcon()); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents.append(</span><span class="string">"','"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents.append(tn[i].getIconOpen()); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents.append(</span><span class="string">"','"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents.append(tn[i].getOpen()); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contents.append(</span><span class="string">"');"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;contents.toString(); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">public class TreeNodeUtil {
//返回js代码
public static String createJsArray(TreeNode[] tn , String dtree) {
if(tn == null || tn.length == 0 ){
System.out.println("TreeNode is empty");
return "";
}
StringBuffer contents = new StringBuffer(100);
contents.append("new dTree('"+dtree+"');");
for (int i = 0; i &lt; tn.length; i++) {
contents.append("\n");
contents.append(dtree+".add('");
contents.append(tn[i].getId());
contents.append("','");
contents.append(tn[i].getPid());
contents.append("','");
contents.append(tn[i].getName());
contents.append("','");
contents.append(tn[i].getUrl());
contents.append("','");
contents.append(tn[i].getTitle());
contents.append("','");
contents.append(tn[i].getTarget());
contents.append("','");
contents.append(tn[i].getIcon());
contents.append("','");
contents.append(tn[i].getIconOpen());
contents.append("','");
contents.append(tn[i].getOpen());
contents.append("');");
}
return contents.toString();
}
}
</pre>
<br />
根据实际情况生成TreeNode对象 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" href="http://www.javaeye.com/topic/32245#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;execute()&nbsp;</span><span class="keyword">throws</span><span>&nbsp;EpochalException&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;TODO&nbsp;Auto-generated&nbsp;method&nbsp;stub </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;sql&nbsp;=&nbsp;</span><span class="string">""</span><span>; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;url&nbsp;=&nbsp;</span><span class="string">""</span><span>&nbsp;; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;sql&nbsp;=&nbsp;</span><span class="string">"SELECT&nbsp;id,parentId,name,seq&nbsp;,remark&nbsp;FROM&nbsp;t_testtree&nbsp;ORDER&nbsp;BY&nbsp;&nbsp;seq&nbsp;DESC"</span><span>&nbsp;; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;TableData&nbsp;tableData&nbsp;=&nbsp;</span><span class="keyword">null</span><span>; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;TreeNode[]&nbsp;treeNodes&nbsp;=&nbsp;</span><span class="keyword">null</span><span>; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tableData&nbsp;=&nbsp;TableSelector.select(sql); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>(tableData!=</span><span class="keyword">null</span><span>){ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;treeNodes&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;TreeNode[tableData.getRowCount()]&nbsp;; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">for</span><span>(</span><span class="keyword">int</span><span>&nbsp;i&nbsp;=&nbsp;</span><span class="number">0</span><span>;&nbsp;i&lt;tableData.getRowCount();i++){ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;treeNodes[i]&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;TreeNode(); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;treeNodes[i].setId(tableData.getString(i,</span><span class="string">"id"</span><span>)); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;treeNodes[i].setName(tableData.getString(i,</span><span class="string">"name"</span><span>)); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;treeNodes[i].setPid(tableData.getString(i,</span><span class="string">"parentId"</span><span>)); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//根据实际情况生成连接地址 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;url&nbsp;=&nbsp;</span><span class="string">"programList.x?category="</span><span>+tableData.getString(i,</span><span class="string">"name"</span><span>)&nbsp;; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;treeNodes[i].setUrl(url); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;treeNodes[i].setTitle(tableData.getString(i,</span><span class="string">"remark"</span><span>)); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;treeNodes[i].setTarget(</span><span class="string">"_blank"</span><span>);</span><span class="comment">//打开新窗口 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dataBean.setParameter(</span><span class="string">"treeNodeArray"</span><span>,treeNodes)&nbsp;; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;}</span><span class="keyword">catch</span><span>(Exception&nbsp;e){ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(e.toString()); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">public void execute() throws EpochalException {
// TODO Auto-generated method stub
String sql = "";
String url = "" ;
sql = "SELECT id,parentId,name,seq ,remark FROM t_testtree ORDER BY  seq DESC" ;
TableData tableData = null;
TreeNode[] treeNodes = null;
try{
tableData = TableSelector.select(sql);
if(tableData!=null){
treeNodes = new TreeNode[tableData.getRowCount()] ;
for(int i = 0; i&lt;tableData.getRowCount();i++){
treeNodes[i] = new TreeNode();
treeNodes[i].setId(tableData.getString(i,"id"));
treeNodes[i].setName(tableData.getString(i,"name"));
treeNodes[i].setPid(tableData.getString(i,"parentId"));
//根据实际情况生成连接地址
url = "programList.x?category="+tableData.getString(i,"name") ;
treeNodes[i].setUrl(url);
treeNodes[i].setTitle(tableData.getString(i,"remark"));
treeNodes[i].setTarget("_blank");//打开新窗口
}
dataBean.setParameter("treeNodeArray",treeNodes) ;
}
}catch(Exception e){
System.out.println(e.toString());
}
}
</pre>
<br />
jsp这边取"treeNodeArray"后通过TreeNodeUtil类生成js代码 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" href="http://www.javaeye.com/topic/32245#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>&lt;% &nbsp;&nbsp;</span></span></li>
    <li><span>TreeNode[]&nbsp;treeNodes&nbsp;=&nbsp;(TreeNode[])dataBean.getParameterObject(</span><span class="string">"treeNodeArray"</span><span>)&nbsp;; &nbsp;&nbsp;</span></span></li>
    <li><span>%&gt; &nbsp;&nbsp;</span></li>
    <li><span>&lt;p&gt;&lt;a&nbsp;href=</span><span class="string">"javascript:&nbsp;d.openAll();"</span><span>&gt;全部展开&lt;/a&gt;&nbsp;|&nbsp;&lt;a&nbsp;href=</span><span class="string">"javascript:&nbsp;d.closeAll();"</span><span>&gt;全部关闭&lt;/a&gt;&lt;/p&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&lt;script&nbsp;language=</span><span class="string">"javascript"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>d&nbsp;=&nbsp;&lt;%=TreeNodeUtil.createJsArray(treeNodes,</span><span class="string">"d"</span><span>)%&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>document.write(d); &nbsp;&nbsp;</span></li>
    <li><span>&lt;/script&gt;&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">&lt;%
TreeNode[] treeNodes = (TreeNode[])dataBean.getParameterObject("treeNodeArray") ;
%&gt;
&lt;p&gt;&lt;a href="javascript: d.openAll();"&gt;全部展开&lt;/a&gt; | &lt;a href="javascript: d.closeAll();"&gt;全部关闭&lt;/a&gt;&lt;/p&gt;
&lt;script language="javascript"&gt;
d = &lt;%=TreeNodeUtil.createJsArray(treeNodes,"d")%&gt;
document.write(d);
&lt;/script&gt;
</pre>
<br />
客户端生成的js代码 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" href="http://www.javaeye.com/topic/32245#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>&lt;script&nbsp;language=</span><span class="string">"javascript"</span><span>&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>d&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;dTree(</span><span class="string">'d'</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>d.add(</span><span class="string">'1'</span><span>,</span><span class="string">'-1'</span><span>,</span><span class="string">'栏目'</span><span>,</span><span class="string">'programList.x?category=栏目'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">'_blank'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>d.add(</span><span class="string">'2'</span><span>,</span><span class="string">'1'</span><span>,</span><span class="string">'电影'</span><span>,</span><span class="string">'programList.x?category=电影'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">'_blank'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>d.add(</span><span class="string">'3'</span><span>,</span><span class="string">'1'</span><span>,</span><span class="string">'电视剧'</span><span>,</span><span class="string">'programList.x?category=电视剧'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">'_blank'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>d.add(</span><span class="string">'4'</span><span>,</span><span class="string">'1'</span><span>,</span><span class="string">'专题'</span><span>,</span><span class="string">'programList.x?category=专题'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">'_blank'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>d.add(</span><span class="string">'5'</span><span>,</span><span class="string">'1'</span><span>,</span><span class="string">'远程教育'</span><span>,</span><span class="string">'programList.x?category=远程教育'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">'_blank'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>d.add(</span><span class="string">'6'</span><span>,</span><span class="string">'1'</span><span>,</span><span class="string">'期刊'</span><span>,</span><span class="string">'programList.x?category=期刊'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">'_blank'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>d.add(</span><span class="string">'7'</span><span>,</span><span class="string">'2'</span><span>,</span><span class="string">'动作片'</span><span>,</span><span class="string">'programList.x?category=动作片'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">'_blank'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>d.add(</span><span class="string">'8'</span><span>,</span><span class="string">'2'</span><span>,</span><span class="string">'喜剧片'</span><span>,</span><span class="string">'programList.x?category=喜剧片'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">'_blank'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>d.add(</span><span class="string">'9'</span><span>,</span><span class="string">'2'</span><span>,</span><span class="string">'鬼片'</span><span>,</span><span class="string">'programList.x?category=鬼片'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">'_blank'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>d.add(</span><span class="string">'10'</span><span>,</span><span class="string">'3'</span><span>,</span><span class="string">'韩剧'</span><span>,</span><span class="string">'programList.x?category=韩剧'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">'_blank'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>d.add(</span><span class="string">'11'</span><span>,</span><span class="string">'3'</span><span>,</span><span class="string">'古装剧'</span><span>,</span><span class="string">'programList.x?category=古装剧'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">'_blank'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>d.add(</span><span class="string">'12'</span><span>,</span><span class="string">'5'</span><span>,</span><span class="string">'英语沙龙'</span><span>,</span><span class="string">'programList.x?category=英语沙龙'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">'_blank'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>d.add(</span><span class="string">'13'</span><span>,</span><span class="string">'4'</span><span>,</span><span class="string">'热门推荐'</span><span>,</span><span class="string">'programList.x?category=热门推荐'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">'_blank'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>d.add(</span><span class="string">'14'</span><span>,</span><span class="string">'7'</span><span>,</span><span class="string">'港台片'</span><span>,</span><span class="string">'programList.x?category=港台片'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">'_blank'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>d.add(</span><span class="string">'15'</span><span>,</span><span class="string">'7'</span><span>,</span><span class="string">'欧美片'</span><span>,</span><span class="string">'programList.x?category=欧美片'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">'_blank'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>d.add(</span><span class="string">'16'</span><span>,</span><span class="string">'14'</span><span>,</span><span class="string">'成龙全集'</span><span>,</span><span class="string">'programList.x?category=成龙全集'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">'_blank'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>d.add(</span><span class="string">'17'</span><span>,</span><span class="string">'14'</span><span>,</span><span class="string">'李连杰全集'</span><span>,</span><span class="string">'programList.x?category=李连杰全集'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">'_blank'</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>,</span><span class="string">''</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>document.write(d); &nbsp;&nbsp;</span></li>
    <li><span>&lt;/script&gt;&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">&lt;script language="javascript"&gt;
d = new dTree('d');
d.add('1','-1','栏目','programList.x?category=栏目','','_blank','','','');
d.add('2','1','电影','programList.x?category=电影','','_blank','','','');
d.add('3','1','电视剧','programList.x?category=电视剧','','_blank','','','');
d.add('4','1','专题','programList.x?category=专题','','_blank','','','');
d.add('5','1','远程教育','programList.x?category=远程教育','','_blank','','','');
d.add('6','1','期刊','programList.x?category=期刊','','_blank','','','');
d.add('7','2','动作片','programList.x?category=动作片','','_blank','','','');
d.add('8','2','喜剧片','programList.x?category=喜剧片','','_blank','','','');
d.add('9','2','鬼片','programList.x?category=鬼片','','_blank','','','');
d.add('10','3','韩剧','programList.x?category=韩剧','','_blank','','','');
d.add('11','3','古装剧','programList.x?category=古装剧','','_blank','','','');
d.add('12','5','英语沙龙','programList.x?category=英语沙龙','','_blank','','','');
d.add('13','4','热门推荐','programList.x?category=热门推荐','','_blank','','','');
d.add('14','7','港台片','programList.x?category=港台片','','_blank','','','');
d.add('15','7','欧美片','programList.x?category=欧美片','','_blank','','','');
d.add('16','14','成龙全集','programList.x?category=成龙全集','','_blank','','','');
d.add('17','14','李连杰全集','programList.x?category=李连杰全集','','_blank','','','');
document.write(d);
&lt;/script&gt;
</pre>
<br />
<br />
感觉使用很方便，数据量不是很大（一般的树型结构的数据量不会很大的，数据量大了就不直观了）的情况下能够满足大多数人的需要。 <br />
<strong><span style="color: red">注意的是root节点的pid必须为'-1'</span></strong> </div>
<div class="attachments">
<ul>
    <li><a href="http://www.javaeye.com/topics/download/147c9004-69f4-41f9-bcab-cd2f38fd6135">dtree.zip</a> (14.6 KB)
    <li>描述: dtree.zip
    <li>下载次数: 507 </li>
</ul>
</div>
<div id="topic_copyright">声明：JavaEye文章版权属于作者，受法律保护。没有作者书面许可不得转载。 </div>
 <img src ="http://www.blogjava.net/xinwuhen/aggbug/205483.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2008-06-03 09:48 <a href="http://www.blogjava.net/xinwuhen/archive/2008/06/03/205483.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JSP数据导出到EXCEL简便方法</title><link>http://www.blogjava.net/xinwuhen/archive/2008/05/19/201363.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Mon, 19 May 2008 04:55:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2008/05/19/201363.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/201363.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2008/05/19/201363.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/201363.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/201363.html</trackback:ping><description><![CDATA[<p>试试看从网页中把表格直接生成excel，虽然不是直接从sql到excel，不过反而更加方便而且人性化。。</p>
<p>网上倒是找到了不少的资料，发现一段javascript的功能实现代码，很不错：<br />
var elTable = document.getElementById("tb"); <br />
var oRangeRef = document.body.createTextRange(); <br />
oRangeRef.moveToElementText( elTable ); <br />
oRangeRef.execCommand( "Copy" ); <br />
<br />
var appExcel = new ActiveXObject( "Excel.Application" ); <br />
appExcel.Visible = true; <br />
appExcel.Workbooks.Add().Worksheets.Item(1).Paste(); <br />
appExcel = null;</p>
<p>实现功能就是把id为tb的表格内的数据都生成为excel，我试试了可行，但是放到服务器来运行就是script error的提示，然后网上到处求问，也找了百度空间的几位高手朋友问了下，可是还是不得其法。。不过还是很感谢他们的热心帮助</p>
<p>没办法，我只能用别的方法来实现了，其实满喜欢上面的这个javascript的功能的，比较人性化。。可惜我黔驴技穷，无法用上它，哎！~</p>
<p>既然我帮客户用jsp写的程序，那么我就还是用jsp来实现这个功能吧。。</p>
<p>于是找到了这么一个方法：<br />
<font color="#808080" size="2">原文出自：</font><a href="http://www.jsp.mlc.edu.tw/viewitem.jsp?itemid=0000000065"><font color="#808080" size="2">http://www.jsp.mlc.edu.tw/viewitem.jsp?itemid=0000000065</font></a><br />
</p>
<p><font size="2"><font color="#ff0000">***************************************************************************************************</font><br />
一、将网页资料以excel报表以线上浏览方式呈现 <br />
<font face="Courier New">xls651.jsp原始码如下 </font></font></p>
<font size="2"><font face="Courier New">
<p><br />
&lt;%@ page contentType="application/msexcel; <font style="background-color: #c7edcc">charset=gb2312</font>" %&gt;<br />
&lt;!-- 以上这行设定本网页为excel格式的网页 --&gt;<br />
&lt;%<br />
&nbsp;&nbsp; response.setHeader("Content-disposition","inline; filename=test1.xls");<br />
&nbsp;&nbsp; //以上这行设定传送到前端浏览器时的档名为test1.xls<br />
&nbsp;&nbsp; //就是靠这一行，让前端浏览器以为接收到一个excel档 <br />
%&gt;<br />
&lt;html&gt;<br />
&lt;head&gt;<br />
&lt;title&gt;Excel档案呈现方式&lt;/title&gt;<br />
&lt;/head&gt;<br />
&lt;body&gt;<br />
&nbsp; &lt;table border="1" width="100%"&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;姓名&lt;/td&gt;&lt;td&gt;身份证字号&lt;/td&gt;&lt;td&gt;生日&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/tr&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;李玟&lt;/td&gt;&lt;td&gt;N111111111&lt;/td&gt;&lt;td&gt;1900/11/12&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/tr&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;梁静如&lt;/td&gt;&lt;td&gt;N222222222&lt;/td&gt;&lt;td&gt;1923/10/1&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/tr&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;张惠妹&lt;/td&gt;&lt;td&gt;N333333333&lt;/td&gt;&lt;td&gt;1934/12/18&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/tr&gt;<br />
&nbsp; &lt;/table&gt;<br />
&lt;/body&gt;<br />
&lt;/html&gt;</p>
<p>二、将网页资料以excel报表以下载的方式呈现<br />
这个jsp档和上一个差不多，只有差别在这一行：<br />
线上浏览的方式： response.setHeader("Content-disposition","<font color="#ff0000">inline</font>; filename=test1.xls"); <br />
下载的方式： response.setHeader("Content-disposition","<font color="#ff0000">attachment</font>; filename=test2.xls"); <br />
附注： 1.以上纯以静态网页的方式呈现excel档，配合资料库，你便能以动态的报表方式做出excel报表了<br />
2.完全不用安装任何元件，或只能受限於win平台，一个简单的方式解决你的报表需求 <br />
3.聪明的你，应该能举一反三，知道如何将网页资料以word的doc格式展现了吧！<br />
(是不是只要把contentType改成"application/msword"以及filename的副档名改成.doc就可以了！)</p>
</font></font>
<img src ="http://www.blogjava.net/xinwuhen/aggbug/201363.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2008-05-19 12:55 <a href="http://www.blogjava.net/xinwuhen/archive/2008/05/19/201363.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于ANT构建应用时，根据判定条件执行不同任务的实例(以操作系统类型为判定条件举例)</title><link>http://www.blogjava.net/xinwuhen/archive/2008/05/14/200371.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Wed, 14 May 2008 03:36:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2008/05/14/200371.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/200371.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2008/05/14/200371.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/200371.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/200371.html</trackback:ping><description><![CDATA[最近在一个项目(湖北质检)，要求搭建一个专门的版本发布服务器，为了将源代码构建并在服务器上测试，而选用ANT来实现。但是，在执行起动Tomcat服务时会有二个起动脚本（startup.sh与startup.bat），这二个脚本分别用于Unix与Windows操作系统；因此，为了适应不同平台的构建，需要根据不同OS来执行不同的脚本。但是，ANT本身还没有条件判断的功能，所以，此处需要借助Ant-Contrib包来实现。具体如下：<br />
一：）下载<font style="background-color: #c7edcc">apache-ant-版本号-bin.zip</font>文件（此处是<font style="background-color: #c7edcc">apache-ant-1.7.0-bin.zip</font>）：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;下载<a title="apache-ant-1.7.0-bin.zip" href="http://ant.apache.org/bindownload.cgi" target="_blank">apache-ant-1.7.0-bin.zip<br />
</a>二：）下载<font style="background-color: #c7edcc">ant-contrib-</font>版本号.jar文件（此处是ant-contrib-1.0b3.jar）：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;下载<a title="ant-contrib-1.0b3.jar" href="http://sourceforge.net/project/showfiles.php?group_id=36177">ant-contrib-1.0b3.jar</a><br />
三：）解压ANT安装文件（<font style="background-color: #c7edcc">apache-ant-1.7.0-bin.zip）到某一目录，如：<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font style="background-color: #c7edcc">D:\Program Files\Apache_ANT_1.7.0<br />
<br />
四：）配置环境变量（path与classpath）：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font style="background-color: #c7edcc">ANT_HOME</font>=<font style="background-color: #c7edcc">D:\Program Files\Apache_ANT_1.7.0<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;path=%path%;%<font style="background-color: #c7edcc">ANT_HOME</font>%\bin;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;classpath=%<font style="background-color: #c7edcc">ANT_HOME</font>%\lib;<br />
五：）安装ant-contrib-1.0b3.jar，下面是ant-contrib-1.0b3.jar解压包中的指南对安装的说明，如下：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<h2><a name="install">Installation</a></h2>
<p>First you must install Apache Ant itself, most of the Ant-Contrib tasks require Ant 1.5 or higher to work properly, however, there are some tasks, specifically &lt;for&gt; which require Ant 1.6. You can download Ant <a href="http://ant.apache.org/bindownload.cgi">from Apache</a>.</p>
<p>Then you need the Ant-Contrib tasks themselves. As there is no release of these tasks yet, you have to build them from sources. Fortunately this is easy, check out the sources (grab the <code>ant-contrib</code> module from <a href="http://sourceforge.net/cvs/?group_id=36177">CVS</a>), change into the source directory of ant-contrib and type <code>ant</code>. After Ant has completed, you'll find <code>ant-contrib-version.jar</code> in the <code>lib</code> subdirectory.</p>
<p>You now have the choice:</p>
<ol>
    <li>Copy <code>ant-contrib-version.jar</code> to the <code>lib</code> directory of your Ant installation, or on your CLASSPATH environment variable. If you want to use one of the tasks in your project, add the line
    <pre>&lt;taskdef resource="net/sf/antcontrib/antlib.xml"/&gt;
    </pre>
    to your build file. <br />
    <br />
    <li>Keep <code>ant-contrib-version.jar</code> in a separate location. You now have to tell Ant explicitly where to find it (say in <code>/usr/share/java/lib</code>):
    <pre>&lt;taskdef resource="net/sf/antcontrib/antlib.xml"&gt;
    &lt;classpath&gt;
    &lt;pathelement location="/usr/share/java/lib/ant-contrib-version.jar"/&gt;
    &lt;/classpath&gt;
    &lt;/taskdef&gt;
    </pre>
    <li>If you would like to use run with Ant Version 1.5 you must use the the .properties file instead. Keep in mind that some tasks will not be available to you , such as the &lt;for&gt; task:
    <pre>&lt;taskdef resource="net/sf/antcontrib/antcontrib.properties"&gt;
    &lt;classpath&gt;
    &lt;pathelement location="/usr/share/java/lib/ant-contrib-version.jar"/&gt;
    &lt;/classpath&gt;
    &lt;/taskdef&gt;</pre>
    </li>
</ol>
<pre>六：）现在可以使用ant-contrib的功能来添加到ANT构建文件中，下面是本项目（湖北质检）的构建文件，如下<span style="color: red">(注意红色部分的条件定义与判断的执行)</span>:</pre>
<pre><font style="background-color: #c7edcc">&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
&lt;project name="QCSystem" default="startWebApplication" basedir="."&gt;<br />
&nbsp;&lt;description&gt;湖北质检ANT构建与Tomcat应用起动配置文件，起动应用时根据不同的操作系统调用不同的Tomcat起运脚本（startup.sh或startup.bat）!&lt;/description&gt;
&nbsp;
&nbsp;&lt;!-- ********** 构件文件相关属性 *********** --&gt;
&nbsp;&lt;!-- 系统环境变量 --&gt;
&nbsp;&lt;property environment="sys-env"/&gt;&nbsp;<br />
&nbsp;&lt;!-- 通用路径或文件夹名称 --&gt;
&nbsp;&lt;property name="srcDir" location="src"/&gt;
&nbsp;&lt;property name="webAppDir" location="webapp"/&gt;<br />
&nbsp;&lt;property name="webInfName" value="WEB-INF"/&gt;
&nbsp;&lt;property name="destDirName" value="classes"/&gt;<br />
&nbsp;&lt;property name="tomcatCommonName" value="common"/&gt;
&nbsp;<br />
&nbsp;<span style="color: red">&lt;!-- 添加"Ant-Contrib"对ANT构建文件的支持 --&gt; &nbsp;<br />
&nbsp;&lt;taskdef resource="net/sf/antcontrib/antcontrib.properties"&gt; &nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;classpath&gt; &nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;pathelement location="${sys-env.ANT_HOME}/Ant-Contrib/ant-contrib-1.0b3.jar"/&gt; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/classpath&gt; &nbsp;<br />
&nbsp;&lt;/taskdef&gt;</span><br />
<br />
&nbsp;<span style="color: red">&lt;!-- 初始化操作系统判断条件 --&gt; &nbsp;<br />
<font style="background-color: #c7edcc"> &lt;property name="winOS" value="win"/&gt;<br />
&nbsp;&lt;property name="unixOS" value="unix"/&gt;</font>
&nbsp;&lt;target name="init"&gt; &nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;echo message="初始化操作系统判断条件[开始]..." /&gt; &nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;condition property="OSType" value="${winOS}"&gt; &nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;os family="Windows"/&gt; &nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/condition&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;condition property="OSType" value="${unixOS}"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;os family="UNIX"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/condition&gt; &nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;echo message="初始化操作系统判断条件[结束]..." /&gt; &nbsp;<br />
&nbsp;&nbsp;&lt;/target&gt;</span></font></pre>
<pre>
<p><font style="background-color: #c7edcc">&nbsp;&lt;!-- 第三方类库--&gt;
&nbsp;&lt;path id="compileLibFiles"&gt;
&nbsp;&nbsp;&lt;fileset dir="${webAppDir}/${webInfName}/lib"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;include name="**/*.jar"/&gt;
&nbsp;&nbsp;&lt;/fileset&gt;<br />
&nbsp;&nbsp;&lt;fileset dir="${sys-env.CATALINA_HOME}/${tomcatCommonName}/lib"&gt;
&nbsp;&nbsp;&nbsp;&lt;include name="**/*.jar"/&gt;
&nbsp;&nbsp;&lt;/fileset&gt;
&nbsp;&lt;/path&gt;
&nbsp;<br />
&nbsp;&lt;!-- 编译工程 --&gt;
&nbsp;&lt;target name="compile"&gt;
&nbsp;&nbsp;&lt;echo message="湖北质检项目编译[开始] ..."/&gt;
&nbsp;&nbsp;&lt;javac srcdir="${srcDir}" debug="on" destdir="${webAppDir}/${webInfName}/${destDirName}" includes="**/*.java"&gt;
&nbsp;&nbsp;&nbsp;&lt;classpath refid="compileLibFiles"/&gt;
&nbsp;&nbsp;&lt;/javac&gt;<br />
&nbsp;&nbsp;&lt;!-- 拷贝配置文件到编译目录 --&gt;
&nbsp;&nbsp;&lt;copy todir="${webAppDir}/${webInfName}/${destDirName}"&gt;
&nbsp;&nbsp;&nbsp;&lt;fileset dir="${srcDir}" excludes="**/*.java"/&gt;
&nbsp;&nbsp;&lt;/copy&gt;
&nbsp;&nbsp;&lt;echo message="湖北质检项目编译[结束] ..."/&gt;
&nbsp;&lt;/target&gt;<br />
&nbsp;&lt;!-- 根据不同的操作系统调用不同的Tomcat起动程序(Windows操作系统:startup.bat&nbsp; Unix操作系统:startup.sh) --&gt;
&nbsp;&lt;target name="startWebApplication" depends="<span style="color: red">init</span>, compile"&gt;
&nbsp;&nbsp;&lt;echo message="起动湖北质检应用[开始] ..."/&gt;
&nbsp;&nbsp;<span style="color: red">&lt;if&gt; &nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;equals arg1="${OSType}" arg2="${winOS}"/&gt; &nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;!-- 下边这种方式直接判断操作系统也可以 --&gt; &nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;!--os family="WINDOWS"/--&gt; &nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;then&gt; &nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;exec dir="${sys-env.CATALINA_HOME}/bin" executable="${sys-env.CATALINA_HOME}/bin/startup.bat"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/then&gt; &nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;else&gt; &nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;exec dir="${sys-env.CATALINA_HOME}/bin" executable="${sys-env.CATALINA_HOME}/bin/startup.sh"/&gt; &nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/else&gt; &nbsp;&nbsp;<br />
&nbsp;&nbsp;&lt;/if&gt;</span>&nbsp;&nbsp;<br />
&nbsp;&nbsp;&lt;echo message="起动湖北质检应用[结束] ..."/&gt;
&nbsp;&lt;/target&gt;<br />
&lt;/project&gt;</font></p>
</pre>
<br />
</font><br />
</font></font>
<img src ="http://www.blogjava.net/xinwuhen/aggbug/200371.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2008-05-14 11:36 <a href="http://www.blogjava.net/xinwuhen/archive/2008/05/14/200371.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Subversion使用手记--转载</title><link>http://www.blogjava.net/xinwuhen/archive/2008/04/22/194676.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Tue, 22 Apr 2008 01:23:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2008/04/22/194676.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/194676.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2008/04/22/194676.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/194676.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/194676.html</trackback:ping><description><![CDATA[<p>一直以来对于自己的项目都是使用CVS进行管理，听说Subversion很久了，但是都没有时间去尝试。想想时间都是省出来的，于是决定，一天学一点，不多，积累成河嘛。<br />
&nbsp; Subversion和CVS相比，除了包含了CVS的全部特性之外，也加入了新的理念。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 新理念<br />
&nbsp; 1、路径、改名、以及文件meta-data也可进入版本控制范围。<br />
&nbsp; 缺少这些特性是CVS被抱怨最多的方面之一，subversion不止对文件内容和文件存放位置加入控制，也对目录，拷贝，重命名操作加入版本控制。它也允许文件/目录的相关元数据meta-data和文件/目录本身一起被版本控制起来，并提供一种机制对文件的执行权限进行控制。<br />
&nbsp; 2、Commit动作真正成为原子级的操作了。<br />
直到整个commit动作都成功前不会有任何部分的commit会生效。版本修订号只是预确认，而不是对文件预确认。(翻译不出来 -_-;)日志信息将绑定到修订信息，而不是象CVS那样冗余的存储下来。<br />
&nbsp;3、提供Apache网络服务器选项，支持WebDAV/DeltaV协议。<br />
Subversion可以使用基于http协议的WebDAV/DeltaV协议进行网络通讯，并由Apache服务器提供源码仓库方的网络浏览服务。这为Subversion提供了比CVS更好的协同工作能力，并提供了各式各样的自由的关键特性：授权，基于路径的授权，线性压缩，以及基本源码仓库浏览。<br />
4、独立服务器选项<br />
Subversion也能提供独立服务器选项，使用自定的协议（不是每个人都想运行Apache2.x）独立服务器可以作为系统的inetd服务运行，并提供基本的授权。它也能使用ssh进行加密。<br />
&nbsp;5、建立分支和标签操作成为不耗时的操作。<br />
这些动作没理由耗时，所以我们不再让它们耗时。<br />
6、分支与标签的实现都是基于底层的拷贝操作，一个拷贝占用一块固定大小的空间。任何拷贝都可以作为一份标签；假如你开始对某个版本的拷贝进行commit动作，那它也就成为一个分支。(这与CVS的"分支节点做标签"方式不同)<br />
7、天然的client/server结构，层次化库设计。<br />
Subversion从设计之初即采用client/server机构；因此避免了困扰CVS了许久的一些维护性难题。<br />
代码被构建为一组带有详细接口说明的模块，用以方便的由其他应用程序进行调用。<br />
8、Client/server协议向双方发送对比差异。<br />
网络协议利用宽带有效地发送对比差异给客户端和服务器端双方。( CVS只是 server-&gt;client,?没有client-&gt;server )<br />
&nbsp;9、资源消耗与数据改变的大小成正比，而不是与数据本身大小成正比一般来说，一项Subversion操作所需时间与操作最终变化的大小成正比。而不是与操作所触及的整个项目的大小成正比，这是Subversion源代码仓库模型的一个特性。<br />
&nbsp;10、有效的处理二进制文件<br />
Subversion对于二进制文件和文本文件的处理同样有效，因为subversion使用一种二进制差异比较算法来增量存储那些连续的修订本。<br />
&nbsp;11、易于语法分析的输出。<br />
所有Subversion命令行客户端的输出都是仔细设计的，可轻松为人所理解，也适于程序自动解析。可进行脚本语言处理将是下一步优先考虑的特性。<br />
&nbsp;好了，开始使用吧。<br />
Subversion到目前的安装已经非常简单了。到Subversion网站下载Windows下的安装文件，简单的步骤就可以完成安装，而且安装程序已经自动注册Path，直接在命令行模式就可以使用了。<br />
&nbsp; 首先初始化Repository，输入命令:<br />
&nbsp;svnadmin create D:"TestRepository"<br />
然后，把现有的项目的目录结构以及文件导入到Repository中：<br />
&nbsp;svn import D:"Projects"Project1 <a href="file:///D:/TestRepository/Project1"><font color="#000080">file:///D:"TestRepository"Project1</font></a> -m &#8220;初始化&#8220;<br />
&nbsp;用启动服务<br />
&nbsp;svnserve -d -r D:"TestRepository"<br />
&nbsp;客户端Checkout<br />
&nbsp;svn checkout svn://主机名/Project1?? (即获取Project1的项目)<br />
&nbsp;以上都是很简单的命令。而且上面只用到了一种服务模式，Apache的还在尝试中。<br />
&nbsp;目前只用到了Subversion的基本功能，就已经感觉不错了，觉得入门很轻松，帮助文档也比CVS要好的多。<br />
&nbsp;Subversion也有图形的客户端，可以在 TortoiseSVN 找到。<br />
&nbsp;Subversion也VS.Net的插件，可以在AnkhSVN 找到。<br />
&nbsp;TortoiseSVN相信不错，因为以前用过它的另一个For CVS的工具，可以和浏览器结合在一起，非常方便和美观。<br />
服务<br />
&nbsp;&nbsp;&nbsp; Subversion具有两种服务模式，一个是作为Apache的模块，另一个是自定义协议的Subserve服务。作为Apache的模块，客户端可以通过WebDAV/DeltaV协议访问Repository，而使用Subserve则使用<br />
Subversion的自定义协议。<br />
下表是两种服务模式的比较：</p>
<p>
<table style="width: 100%" cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.32%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">功能</span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.34%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">Apache + mod_dav_sub </span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.34%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">Svnserve </span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.32%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">验证方式</span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.34%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">基于HTTPS的X.509、LDAP、NTLM或其他Apache支持的验证</span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.34%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">CRAM-MD5</span><span style="font-size: 9pt; color: black; font-family: 宋体">或者SSH </span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.32%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">用户帐户管理</span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.34%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">私有的用户文件</span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.34%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">私有的用户文件或已有的系统帐户</span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.32%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">授权管理</span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.34%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">blanket read/write access</span><span style="font-size: 9pt; color: black; font-family: 宋体">或单一目录的访问控制</span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.34%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">blanket read/write access </span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.32%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">加密</span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.34%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">可选的SSL </span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.34%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">可选的SSH隧道</span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.32%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">交互性</span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.34%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">可通过支持WebDAV的客户端访问</span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.34%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">无交互性</span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.32%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">Web</span><span style="font-size: 9pt; color: black; font-family: 宋体">访问</span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.34%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">有限的内置支持，或通过第三方的工具，例如ViewCVS </span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.34%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">通过第三方的支持，如ViewCVS </span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.32%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">速度</span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.34%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">稍慢</span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.34%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">稍快</span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.32%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">初始安装</span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.34%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">稍复杂</span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
            <td style="border-right: #d4d0c8; padding-right: 7.5pt; border-top: #d4d0c8; padding-left: 7.5pt; padding-bottom: 7.5pt; border-left: #d4d0c8; width: 33.34%; padding-top: 7.5pt; border-bottom: #d4d0c8; background-color: transparent" width="33%">
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: 宋体">相当简单</span></p>
            <p>
            <p>
            <p>&nbsp;</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 启动svnserve服务<br />
svnserve 是一个轻量级的服务， 使用自定义的协议通过TCP/IP与客户端通讯。<br />
客户端通过由 svn:// 或者 svn+ssh:// 开始的URL访问svnserve服务器。<br />
启动服务器<br />
端口监控（inetd）模式<br />
如果你打算用端口监控来启动处理客户的访问请求的进程，你可以通过传入参数-i来启动：<br />
svnserve -i<br />
当使用-i参数启动服务的时候，svnserve通过stdin和stdout用自定义协议和客户端<br />
通讯。同时服务侦听3690端口。<br />
独立端口监控进程<br />
使用参数-d启动服务作为一个独立的端口监控进程。<br />
svnserve -d<br />
当运行svnserve在独立端口监控模式时，你可以使用--listen-port=和--listen-host=参数来自定义需要的端口和主机名称。当前模式默认的端口是3690。<br />
当然，也有第三种方法启动svnserve，也就是使用&#8220;隧道模式&#8221;，使用-t参数启动服务。这个模式要求远程服务程序，如RSH或SSH，已经成功验证用户，并且使用已经校验的用户启动一个属于该用户的svnserve进程。当使用该模式提供服务时，要确认启动的用户帐户具备对Repository的读/写权限。<br />
设置项目目录<br />
当svnserve开始运行时，它将会暴露所有的Repository到网络上。不过，当客户端需要获取一个Repository的内容时，需要指定Reopsitory的绝对路径。例如：一个Repository放在文件路径<br />
C:/Project Repository/Project1<br />
那么当客户端访问时，需要指定绝对路径：<br />
svn://host/C:/Project Repository/Project1<br />
所以，为了增加保密性，你可以使用参数-r指定需要暴露的Repository的路径，当用户访问时，只需指定Repository的名称即可。例如上面的Repository，当启动服务时，使用如下的方法：<br />
svn -d -r C:/Project Repository<br />
那么当客户端访问时，则使用<br />
svn://host/Project1<br />
就可以获取数据了。<br />
内置的验证和授权<br />
当客户端连接到一个svnserve进程时，下面的流程就会触发：<br />
1、客户选择一个指定的Repository；<br />
2、服务处理Repository的配置文件 conf/svnserve.conf文件，并且开始执行在其中定义的所有验证和授权策略；<br />
3、依赖与情形和授权策略：<br />
a)客户端也许允许匿名访问而不需要验证，或者<br />
b)客户但也许需要在任何时候被要求验证，或者<br />
c)假如处于"隧道模式"中，客户端将声明自己已经可以被外部验证。<br />
很显然，如上所说，用户文件是一个名为svnserve.conf的，放在conf目录下的文件。<br />
现在我们来看看如何配置这个文件：<br />
这个配置文件放置在Repository的目录中的conf目录下，它有两个节点：<br />
[general]<br />
[users]<br />
其中，[general]的配置信息有：<br />
anon-access = read<br />
auth-access = write<br />
其中表示对于验证有效的以及没通过验证的用户可以做什么事情。分别有read, write和none<br />
[users]的标签的配置内容有：<br />
USERNAME = PASSWORD<br />
password-db = passwd<br />
realm = My First Repository<br />
其中表示，用户名对应的密码是什么，或者指定一个存储用户名和密码的文件的相对或绝对路径以及指定了Repository的验证领域。如果两个Repository有相同的验证领域，那么它们应该有相同的密码数据库，反之亦然。默认的领域就是指向当前的Repository的路径，与服务器的Repository的根目录相关。<br />
<br />
几个版本控制工具的比较:<br />
</p>
<p>cvs是开源项目，其功能比vss强大很多，可以支持版本合并，多个分支。而vss是比较简单和易用的配置管理工具。在这两个工具的选择上还是要看是项目决定，一般10个人以下的团队vss可能更方便一些~~~</p>
<div class="fabiao">cvs是并行版本管理器，开源，可以多人同时修改一个文件，当出现冲突的时候自动合入或者提示； <br />
vss是微软visual studio中附带的版本管理器，只能在windows局域网环境下使用。使用一个文件同时只能由一个人来修改的方法来避免冲突。最大的优点是易学，并且跟visual studio可以无缝集成。</div>
<div class="fabiao">cvs,vss 都是版本控制的软件工具，可以把源代码或者其他文件的每一次修改的内容都保存起来，算是可以看以前版本的代码。 <br />
vss 基于文件共享的机制，易用性好，安全性不太好。vss 对于同时增加删除多个目录的支持很好。分支合并管理也很容易使用，打标签功能不太好用。vss 基于文件锁机制，同一时刻，只能有一个人修改同一个文件。 <br />
cvs 基于 c/s 结构，也有工具可以让它 b/s 运行，不过 b/s 速度慢，使用者不多。cvs 安全控制比较好，对于同时增加多个目录的支持不太好。cvs 中删除目录很难。cvs可以同一时刻多人修改统一文件然后合并，不过只支持文本文件；对于 office 或者其他格式的文档，多个人同时修改同一个文件很难合并，浪费大家时间。我在网上搜索让cvs支持锁机制，只有少数文章提到在 server 端用 script 控制，语焉不详。 <br />
总体来说，cvs 功能比vss强。</div>
<img src ="http://www.blogjava.net/xinwuhen/aggbug/194676.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2008-04-22 09:23 <a href="http://www.blogjava.net/xinwuhen/archive/2008/04/22/194676.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>log4j 配置</title><link>http://www.blogjava.net/xinwuhen/archive/2008/04/17/193689.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Thu, 17 Apr 2008 03:31:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2008/04/17/193689.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/193689.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2008/04/17/193689.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/193689.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/193689.html</trackback:ping><description><![CDATA[一、前言：<br />
&nbsp;&nbsp;&nbsp;&nbsp; log4j 是一个开放源码项目，是广泛使用的以Java编写的日志记录包。由于log4j出色的表现，&nbsp;&nbsp;&nbsp;&nbsp; 当时在log4j完成时，log4j开发组织曾建议sun在jdk1.4中用log4j取代jdk1.4 的日志工具类，但当时jdk1.4已接近完成，所以sun拒绝使用log4j，当在java开发中实际使用最多的还是log4j，&nbsp;&nbsp;&nbsp;&nbsp; 人们遗忘了sun的日志工具类。&nbsp;&nbsp;&nbsp;&nbsp; 它的一个独有特性包括在类别中继承的概念。通过使用类别层次结构，这样就减少了日志记录输出量，并将日志记录的开销降到最低。<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp; 它允许开发者控制以任意间隔输出哪些日志语句。通过使用外部配置文件，完全可以在运行时进行配置。几乎每个大的应用程序都包括其自己的日志记录或跟踪 API。经验表明日志记录是开发周期中的重要组成部分。同样，日志记录提供一些优点。首先，它可以提供运行应用程序的确切 上下文。一旦插入到代码中，生成日志记录输出就不需要人为干涉。其次，日志输出可以保存到永久媒体中以便以后研究。最后，除了在开发阶段中使用，十分丰富 的日志记录包还可以用作审计工具。
<p>&nbsp;&nbsp;&nbsp; 依照该规则，在 1996 年初，EU SEMPER（欧洲安全电子市场）项目就决定编写自己的跟踪 API。 在无数次改进、几次具体化和许多工作之后，该 API 已经演变成 log4j，一种流行的 Java 日志记录包。&nbsp; 这个包按 IBM 公共许可证分发，由开放源码权威机构认证。</p>
<p>&nbsp;&nbsp;&nbsp; 日志记录有其自己的缺点。它会降低应用程序的速度。如果太详细，它可能会使屏幕滚动变得看不见。&nbsp; 为了减低这些影响，log4j 被设计成快速且灵活的。由于应用程序很少将日志记录当作是主要功能，&nbsp; log4j API 力争易于了解和使用。<br />
&nbsp;&nbsp;&nbsp;&nbsp; log4j，它可以控制以任意间隔输出哪些日志语句。</p>
<p>二、主要组件</p>
<p>1、根类别（在类别层次结构的顶部，即全局性的日志级别）<br />
&nbsp;<br />
配置根Logger，其语法为：</p>
<p>log4j.rootLogger = [ level ] , appenderName, appenderName, ...</p>
<p>level 是日志记录的类别<br />
appenderName就是指定日志信息输出到哪个地方。您可以同时指定多个输出目的地。</p>
<p>类别level 为 OFF、FATAL、ERROR、WARN、INFO、DEBUG、log、ALL或自定义的优先级。<br />
og4j常用的优先级FATAL&gt;ERROR&gt;WARN&gt;INFO&gt;DEBUG<br />
配置根Logger，其语法为：<br />
log4j.rootLogger = [ level ] , appenderName, appenderName, &#8230;<br />
如果为log4j.rootLogger=WARN，则意味着只有WARN,ERROR,FATAL被输出，DEBUG,INFO将被屏蔽掉。</p>
<p>举例：log4j.rootCategory=INFO,stdout,Runlog,Errorlog<br />
根日志类别为INFO，DEBUG将被屏蔽，其他的将被输出。 stdout,Runlog,Errorlog分别为3个输出目的地。</p>
<p>&nbsp;2、常用输出格式</p>
<p>&nbsp;-X号:X信息输出时左对齐；<br />
&nbsp;%p:日志信息级别<br />
&nbsp;%d{}:日志信息产生时间<br />
&nbsp;%c:日志信息所在地（类名）<br />
&nbsp;%m:产生的日志具体信息<br />
&nbsp;%n:输出日志信息换行<br />
&nbsp;举例：<br />
log4j.appender.stdout.layout.ConversionPattern= %5p %d{yyyy-MM-dd HH:mm:ss} %c %m %n<br />
log4j.appender.Runlog.layout.ConversionPattern= %5p %d{yyyy-MM-dd HH:mm:ss} %c %m %n<br />
log4j.appender.Errorlog.layout.ConversionPattern= %5p %d{yyyy-MM-dd HH:mm:ss} %c %m %n</p>
<p>3、布局<br />
使用的输出布局，其中log4j提供4种布局：<br />
org.apache.log4j.HTMLLayout（以HTML表格形式布局）<br />
org.apache.log4j.PatternLayout（可以灵活地指定布局模式），<br />
org.apache.log4j.SimpleLayout（包含日志信息的级别和信息字符串），<br />
org.apache.log4j.TTCCLayout（包含日志产生的时间、线程、类别等等信息）</p>
<p>举例：<br />
输出格式为HTML表格<br />
log4j.appender.stdout.layout=org.apache.log4j.HTMLLayout</p>
<p>输出格式为可以灵活地指定布局模式<br />
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout</p>
<p>输出格式为包含日志信息的级别和信息字符串<br />
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout</p>
<p>输出格式为包含日志产生的时间、线程、类别等等信息<br />
log4j.appender.stdout.layout=org.apache.log4j.TTCCLayout</p>
<p><br />
4、目的地</p>
<p>配置日志信息输出目的地Appender，其语法为</p>
<p><br />
log4j.appender.appenderName = fully.qualified.name.of.appender.class<br />
log4j.appender.appenderName.option1 = value1<br />
...<br />
log4j.appender.appenderName.option = valueN<br />
appenderName就是指定日志信息输出到哪个地方。您可以同时指定多个输出目的地。</p>
<p>log4j支持的输出目的地：<br />
org.apache.log4j.ConsoleAppender 控制台<br />
org.apache.log4j.FileAppender 文件<br />
org.apache.log4j.DailyRollingFileAppender 每天产生一个日志文件<br />
org.apache.log4j.RollingFileAppender （文件大小到达指定尺寸的时候产生一个新的文件），<br />
org.apache.log4j.WriterAppender （将日志信息以流格式发送到任意指定的地方）<br />
org.apache.log4j.net.SMTPAppender 邮件<br />
org.apache.log4j.jdbc.JDBCAppender 数据库<br />
其他如：GUI组件、甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等</p>
<p>举例：</p>
<p><br />
输出到控制台<br />
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender（指定输出到控制台）<br />
log4j.appender.Threshold=DEBUG（指定输出类别）<br />
log4j.appender.CONSOLE.Target=System.out<br />
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout（指定输出布局）<br />
log4j.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n（指定输出格式）</p>
<p>输出到文件</p>
<p>&nbsp;&nbsp; log4j.appender.FILE=org.apache.log4j.FileAppender（指定输出到文件）<br />
&nbsp;&nbsp; log4j.appender.FILE.File=file.log（指定输出的路径及文件名）<br />
&nbsp;&nbsp; log4j.appender.FILE.Append=false<br />
&nbsp;&nbsp; log4j.appender.FILE.layout=org.apache.log4j.PatternLayout（指定输出的布局）<br />
&nbsp;&nbsp; log4j.appender.FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n（指定输出的格式）</p>
<p>输出到文件（轮换"日志文件",当日志文件达到指定大小时，该文件就被关闭并备份，然后创建一个新的日志文件）</p>
<p>&nbsp; log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender（指定输出到文件）<br />
&nbsp; log4j.appender.ROLLING_FILE.Threshold=ERROR（指定输出类别）<br />
&nbsp; log4j.appender.ROLLING_FILE.File=rolling.log（指定输出的路径及文件名）<br />
&nbsp; log4j.appender.ROLLING_FILE.Append=true<br />
&nbsp; log4j.appender.ROLLING_FILE.MaxFileSize=10KB（指定输出到文件的大小）<br />
&nbsp; log4j.appender.ROLLING_FILE.MaxBackupIndex=1<br />
&nbsp; log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout（指定采用输出布局）<br />
&nbsp; log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n（指定采用输出格式）</p>
<p>输出到Socket<br />
&nbsp;log4j.appender.SOCKET=org.apache.log4j.RollingFileAppender（指定输出到Socket）<br />
&nbsp;log4j.appender.SOCKET.RemoteHost=localhost（远程主机）<br />
&nbsp;log4j.appender.SOCKET.Port=5001（远程主机端口）<br />
&nbsp;log4j.appender.SOCKET.LocationInfo=true<br />
&nbsp;log4j.appender.SOCKET.layout=org.apache.log4j.PatternLayout（布局）<br />
&nbsp;log4j.appender.SOCET.layout.ConversionPattern =[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD]%n%c[CATEGORY]%n %m[MESSAGE]%n%n（输出格式）</p>
<p>输出到邮件<br />
log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender（指定输出到邮件）<br />
&nbsp;log4j.appender.MAIL.Threshold=FATAL<br />
&nbsp;log4j.appender.MAIL.BufferSize=10<br />
&nbsp;<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#108;&#111;&#103;&#52;&#106;&#46;&#97;&#112;&#112;&#101;&#110;&#100;&#101;&#114;&#46;&#77;&#65;&#73;&#76;&#46;&#70;&#114;&#111;&#109;&#61;&#99;&#104;&#101;&#110;&#121;&#108;&#64;&#104;&#111;&#108;&#108;&#121;&#99;&#114;&#109;&#46;&#99;&#111;&#109;"><font color="#1d58d1">log4j.appender.MAIL.From=chenyl@hollycrm.com</font></a>（发件人）<br />
&nbsp;log4j.appender.MAIL.SMTPHost=mail.hollycrm.com（SMTP服务器）<br />
&nbsp;log4j.appender.MAIL.Subject=Log4J Message<br />
&nbsp;<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#108;&#111;&#103;&#52;&#106;&#46;&#97;&#112;&#112;&#101;&#110;&#100;&#101;&#114;&#46;&#77;&#65;&#73;&#76;&#46;&#84;&#111;&#61;&#99;&#104;&#101;&#110;&#121;&#108;&#64;&#104;&#111;&#108;&#108;&#121;&#99;&#114;&#109;&#46;&#99;&#111;&#109;"><font color="#1d58d1">log4j.appender.MAIL.To=chenyl@hollycrm.com</font></a>（收件人）<br />
&nbsp;log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout（布局）<br />
&nbsp;log4j.appender.MAIL.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n（格式）</p>
<br />
<p>输出到数据库<br />
&nbsp;log4j.appender.DATABASE=org.apache.log4j.jdbc.JDBCAppender（指定输出到数据库）<br />
&nbsp;log4j.appender.DATABASE.URL=jdbc:mysql://localhost:3306/test（指定数据库URL）<br />
&nbsp;log4j.appender.DATABASE.driver=com.mysql.jdbc.Driver（指定数据库driver）<br />
&nbsp;log4j.appender.DATABASE.user=root（指定数据库用户）<br />
&nbsp;log4j.appender.DATABASE.password=root（指定数据库用户密码）<br />
&nbsp;log4j.appender.DATABASE.sql=INSERT INTO LOG4J (Message) VALUES ('[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n')（组织SQL语句）<br />
&nbsp;log4j.appender.DATABASE.layout=org.apache.log4j.PatternLayout（布局）<br />
&nbsp;log4j.appender.DATABASE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n（格式）</p>
<p>5、日志类别补充<br />
有时我们需要对某个特定的部分指定有别于根类别的日志类别，可以指定某个包的优先级<br />
如：<br />
&nbsp; log4j.category.com.neusoft.mbip.dm.util=ERROR ，其中com.neusoft.mbip.dm.util为我们需要特别指定日志类别的部分。<br />
&nbsp;<br />
&nbsp; 或者可以指定输出文件的优先级<br />
&nbsp; log4j.appender.Errorlog.Threshold=ERROR<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;三、 常用log4j配置&nbsp;</p>
<p>常用log4j配置，一般可以采用两种方式，.properties和.xml,下面举两个简单的例子：</p>
<p>1、log4j.properties</p>
<p>### 设置org.zblog域对应的级别INFO,DEBUG,WARN,ERROR和输出地A1，A2 ##<br />
log4j.category.org.zblog=ERROR,A1<br />
log4j.category.org.zblog=INFO,A2</p>
<p>log4j.appender.A1=org.apache.log4j.ConsoleAppender<br />
### 设置输出地A1，为ConsoleAppender(控制台) ##<br />
log4j.appender.A1.layout=org.apache.log4j.PatternLayout<br />
### 设置A1的输出布局格式PatterLayout,(可以灵活地指定布局模式）##<br />
log4j.appender.A1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%c]-[%p] %m%n<br />
### 配置日志输出的格式##</p>
<p>log4j.appender.A2=org.apache.log4j.RollingFileAppender<br />
### 设置输出地A2到文件（文件大小到达指定尺寸的时候产生一个新的文件）##<br />
log4j.appender.A2.File=E:/study/log4j/zhuwei.html<br />
### 文件位置##<br />
log4j.appender.A2.MaxFileSize=500KB<br />
### 文件大小##<br />
log4j.appender.A2.MaxBackupIndex=1<br />
log4j.appender.A2.layout=org.apache.log4j.HTMLLayout<br />
##指定采用html方式输出</p>
<p>2、log4j.xml</p>
<p>&lt;?xml version="1.0" encoding="GB2312" ?&gt;<br />
&lt;!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"&gt;</p>
<p>&lt;log4j:configuration xmlns:log4j="<a href="http://jakarta.apache.org/log4j/"><font color="#1d58d1">http://jakarta.apache.org/log4j/</font></a>"&gt;</p>
<p>&lt;appender name="org.zblog.all" class="org.apache.log4j.RollingFileAppender"&gt;<br />
&lt;!-- 设置通道ID:org.zblog.all和输出方式：org.apache.log4j.RollingFileAppender --&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;param name="File" value="E:/study/log4j/all.output.log" /&gt;&lt;!-- 设置File参数：日志输出文件名 --&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;param name="Append" value="false" /&gt;&lt;!-- 设置是否在重新启动服务时，在原有日志的基础添加新日志 --&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;layout class="org.apache.log4j.PatternLayout"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param name="ConversionPattern" value="%p (%c:%L)- %m%n" /&gt;&lt;!-- 设置输出文件项目和格式 --&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/layout&gt;<br />
&lt;/appender&gt;</p>
<p>&lt;appender name="org.zblog.zcw" class="org.apache.log4j.RollingFileAppender"&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;param name="File" value="E:/study/log4j/zhuwei.output.log" /&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;param name="Append" value="true" /&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;param name="MaxFileSize" value="10240" /&gt; &lt;!-- 设置文件大小 --&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;layout class="org.apache.log4j.PatternLayout"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param name="ConversionPattern" value="%p (%c:%L)- %m%n" /&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/layout&gt;<br />
&lt;/appender&gt;</p>
<p>&lt;logger name="zcw.log"&gt; &lt;!-- 设置域名限制，即zcw.log域及以下的日志均输出到下面对应的通道中 --&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;level value="debug" /&gt;&lt;!-- 设置级别 --&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;appender-ref ref="org.zblog.zcw" /&gt;&lt;!-- 与前面的通道id相对应 --&gt;<br />
&lt;/logger&gt;</p>
<p>&lt;root&gt; &lt;!-- 设置接收所有输出的通道 --&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;appender-ref ref="org.zblog.all" /&gt;&lt;!-- 与前面的通道id相对应 --&gt;<br />
&lt;/root&gt;</p>
<p>&lt;/log4j:configuration&gt;</p>
<p><br />
3、配置文件加载方法：</p>
<p>import org.apache.log4j.Logger;<br />
import org.apache.log4j.PropertyConfigurator;<br />
import org.apache.log4j.xml.DOMConfigurator;</p>
<p>public class Log4jApp {<br />
&nbsp;&nbsp;&nbsp; public static void main(String[] args) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DOMConfigurator.configure("E:/study/log4j/log4j.xml");//加载.xml文件<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //PropertyConfigurator.configure("E:/study/log4j/log4j.properties");//加载.properties文件</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Logger log=Logger.getLogger("org.zblog.test");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log.info("测试");<br />
&nbsp;&nbsp;&nbsp; }<br />
}</p>
<p>4、项目使用log4j<br />
在web应用中，可以将配置文件的加载放在一个单独的servlet中，并在web.xml中配置该servlet在应用启动时候加载。<br />
对于在多人项目中，可以给每一个人设置一个输出通道，这样在每个人在构建Logger时，用自己的域名称，让调试信<br />
息输出到自己的log文件中。</p>
<p>四、log4j配置举例（properties）</p>
<p>#log4j.rootLogger = [ level ] , appenderName, appenderName,<br />
#类别level 为 OFF、FATAL、ERROR、WARN、INFO、DEBUG、log、ALL或自定义的优先级<br />
#Log4j常用的优先级FATAL&gt;ERROR&gt;WARN&gt;INFO&gt;DEBUG</p>
<p>#stdout为控制台 ，Errorlog为错误记录日志 ，<br />
log4j.rootCategory=INFO,stdout,Runlog,Errorlog</p>
<p><br />
#输出的appender的格式为<br />
#log4j.appender.appenderName = fully.qualified.name.of.appender.class<br />
#log4j.appender.appenderName.option1 = value1<br />
#log4j.appender.appenderName.option = valueN<br />
#Log4j中appender支持的输出<br />
#org.apache.log4j.ConsoleAppender 控制台<br />
#org.apache.log4j.FileAppender 文件<br />
#org.apache.log4j.DailyRollingFileAppender 每天产生一个日志文件<br />
#org.apache.log4j.RollingFileAppender （文件大小到达指定尺寸的时候产生一个新的文件），<br />
#org.apache.log4j.WriterAppender （将日志信息以流格式发送到任意指定的地方）<br />
#org.apache.log4j.net.SMTPAppender 邮件<br />
#org.apache.log4j.jdbc.JDBCAppender 数据库</p>
<p>＃定义输出的形式<br />
log4j.appender.stdout=org.apache.log4j.ConsoleAppender<br />
log4j.appender.Runlog=org.apache.log4j.DailyRollingFileAppender<br />
log4j.appender.Errorlog=org.apache.log4j.DailyRollingFileAppender</p>
<p><br />
#可以指定输出文件的优先级<br />
log4j.appender.Errorlog.Threshold=ERROR</p>
<p>#指定输出的文件<br />
log4j.appender.Runlog.File=D:\UserInfoSyn\WebRoot\WEB-INF\runlog\runlog.log<br />
log4j.appender.Errorlog.File=D:\UserInfoSyn\WebRoot\WEB-INF\errorlog\errorlog.log</p>
<p><br />
#Log4j的layout布局<br />
#org.apache.log4j.HTMLLayout 以HTML表格形式布局<br />
#org.apache.log4j.PatternLayout 可以灵活地指定布局模式<br />
#org.apache.log4j.SimpleLayout&nbsp; 包含日志信息的级别和信息字符串<br />
#org.apache.log4j.TTCCLayout&nbsp;&nbsp;&nbsp; 包含日志产生的时间、线程、类别等等信息</p>
<p>log4j.appender.stdout.layout=org.apache.log4j.PatternLayout<br />
log4j.appender.Runlog.layout=org.apache.log4j.PatternLayout<br />
log4j.appender.Errorlog.layout=org.apache.log4j.PatternLayout</p>
<p>#输出格式,log4j javadoc org.apache.log4j.PatternLayout<br />
#-X号:X信息输出时左对齐；<br />
#%p:日志信息级别<br />
# %d{}:日志信息产生时间<br />
# %c:日志信息所在地（类名）<br />
# %m:产生的日志具体信息<br />
# %n:%n:输出日志信息换行<br />
log4j.appender.stdout.layout.ConversionPattern= %5p %d{yyyy-MM-dd HH:mm:ss} %c %m %n<br />
log4j.appender.Runlog.layout.ConversionPattern= %5p %d{yyyy-MM-dd HH:mm:ss} %c %m %n<br />
log4j.appender.Errorlog.layout.ConversionPattern= %5p %d{yyyy-MM-dd HH:mm:ss} %c %m %n</p>
<p>#指定某个包的优先级<br />
log4j.category.com.neusoft.mbip.dm.util=ERROR</p>
<p><br />
#示例<br />
###################<br />
# Console Appender<br />
###################<br />
#log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender<br />
#log4j.appender.Threshold=DEBUG<br />
#log4j.appender.CONSOLE.Target=System.out<br />
#log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout<br />
#log4j.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n<br />
#log4j.appender.CONSOLE.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD] n%c[CATEGORY]%n%m[MESSAGE]%n%n</p>
<p><br />
#####################<br />
# File Appender<br />
#####################<br />
#log4j.appender.FILE=org.apache.log4j.FileAppender<br />
#log4j.appender.FILE.File=file.log<br />
#log4j.appender.FILE.Append=false<br />
#log4j.appender.FILE.layout=org.apache.log4j.PatternLayout<br />
#log4j.appender.FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n<br />
# Use this layout for LogFactor 5 analysis</p>
<p>########################<br />
# Rolling File????? RollingFileAppender??????????????????<br />
########################<br />
#log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender<br />
#log4j.appender.ROLLING_FILE.Threshold=ERROR<br />
# 文件位置<br />
#log4j.appender.ROLLING_FILE.File=rolling.log<br />
#log4j.appender.ROLLING_FILE.Append=true<br />
#文件大小<br />
#log4j.appender.ROLLING_FILE.MaxFileSize=10KB<br />
#指定采用输出布局和输出格式<br />
#log4j.appender.ROLLING_FILE.MaxBackupIndex=1<br />
#log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout<br />
#log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n</p>
<p>####################<br />
# Socket Appender<br />
####################<br />
#log4j.appender.SOCKET=org.apache.log4j.RollingFileAppender<br />
#log4j.appender.SOCKET.RemoteHost=localhost<br />
#log4j.appender.SOCKET.Port=5001<br />
#log4j.appender.SOCKET.LocationInfo=true<br />
# Set up for Log Facter 5<br />
#log4j.appender.SOCKET.layout=org.apache.log4j.PatternLayout<br />
#log4j.appender.SOCET.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD]%n%c[CATEGORY]%n%m[MESSAGE]%n%n</p>
<p>########################<br />
# SMTP Appender<br />
#######################<br />
#log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender<br />
#log4j.appender.MAIL.Threshold=FATAL<br />
#log4j.appender.MAIL.BufferSize=10<br />
<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#35;&#108;&#111;&#103;&#52;&#106;&#46;&#97;&#112;&#112;&#101;&#110;&#100;&#101;&#114;&#46;&#77;&#65;&#73;&#76;&#46;&#70;&#114;&#111;&#109;&#61;&#99;&#104;&#101;&#110;&#121;&#108;&#64;&#104;&#111;&#108;&#108;&#121;&#99;&#114;&#109;&#46;&#99;&#111;&#109;"><font color="#1d58d1">#log4j.appender.MAIL.From=chenyl@hollycrm.com</font></a><br />
#log4j.appender.MAIL.SMTPHost=mail.hollycrm.com<br />
#log4j.appender.MAIL.Subject=Log4J Message<br />
<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#35;&#108;&#111;&#103;&#52;&#106;&#46;&#97;&#112;&#112;&#101;&#110;&#100;&#101;&#114;&#46;&#77;&#65;&#73;&#76;&#46;&#84;&#111;&#61;&#99;&#104;&#101;&#110;&#121;&#108;&#64;&#104;&#111;&#108;&#108;&#121;&#99;&#114;&#109;&#46;&#99;&#111;&#109;"><font color="#1d58d1">#log4j.appender.MAIL.To=chenyl@hollycrm.com</font></a><br />
#log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout<br />
#log4j.appender.MAIL.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n</p>
<p>########################<br />
# JDBC Appender<br />
#######################<br />
#log4j.appender.DATABASE=org.apache.log4j.jdbc.JDBCAppender<br />
#log4j.appender.DATABASE.URL=jdbc:mysql://localhost:3306/test<br />
#log4j.appender.DATABASE.driver=com.mysql.jdbc.Driver<br />
#log4j.appender.DATABASE.user=root<br />
#log4j.appender.DATABASE.password=<br />
#log4j.appender.DATABASE.sql=INSERT INTO LOG4J (Message) VALUES ('[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n')<br />
#log4j.appender.DATABASE.layout=org.apache.log4j.PatternLayout<br />
#log4j.appender.DATABASE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n</p>
<p>########################<br />
# Log Factor 5 Appender<br />
########################<br />
#log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender<br />
#log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000</p>
<p>###################<br />
#自定义Appender<br />
###################<br />
#log4j.appender.im = net.cybercorlin.util.logger.appender.IMAppender<br />
#log4j.appender.im.host = mail.cybercorlin.net<br />
#log4j.appender.im.username = username<br />
#log4j.appender.im.password = password<br />
#log4j.appender.im.recipient = <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#99;&#111;&#114;&#108;&#105;&#110;&#64;&#99;&#121;&#98;&#101;&#114;&#99;&#111;&#114;&#108;&#105;&#110;&#46;&#110;&#101;&#116;"><font color="#1d58d1">corlin@cybercorlin.net</font></a><br />
#log4j.appender.im.layout=org.apache.log4j.PatternLayout<br />
#log4j.appender.im.layout.ConversionPattern =[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n</p>
<img src ="http://www.blogjava.net/xinwuhen/aggbug/193689.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2008-04-17 11:31 <a href="http://www.blogjava.net/xinwuhen/archive/2008/04/17/193689.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于web.xml配置的详细说明</title><link>http://www.blogjava.net/xinwuhen/archive/2008/04/15/193043.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Tue, 15 Apr 2008 03:42:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2008/04/15/193043.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/193043.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2008/04/15/193043.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/193043.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/193043.html</trackback:ping><description><![CDATA[<font size="2">1 定义头和根元素<br />
<br />
部署描述符文件就像所有XML文件一样，必须以一个XML头开始。这个头声明可以使用的XML版本并给出文件的字符编码。<br />
DOCYTPE声明必须立即出现在此头之后。这个声明告诉服务器适用的servlet规范的版本（如2.2或2.3）并指定管理此文件其余部分内容的语法的DTD(Document Type Definition，文档类型定义)。<br />
所有部署描述符文件的顶层（根）元素为web-app。请注意，XML元素不像HTML，他们是大小写敏感的。因此，web-App和WEB-APP都是不合法的，web-app必须用小写。<br />
<br />
2 部署描述符文件内的元素次序<br />
<br />
XML 元素不仅是大小写敏感的，而且它们还对出现在其他元素中的次序敏感。例如，XML头必须是文件中的第一项，DOCTYPE声明必须是第二项，而web- app元素必须是第三项。在web-app元素内，元素的次序也很重要。服务器不一定强制要求这种次序，但它们允许（实际上有些服务器就是这样做的）完全拒绝执行含有次序不正确的元素的Web应用。这表示使用非标准元素次序的web.xml文件是不可移植的。<br />
下面的列表给出了所有可直接出现在web-app元素内的合法元素所必需的次序。例如，此列表说明servlet元素必须出现在所有servlet-mapping元素之前。请注意，所有这些元素都是可选的。因此，可以省略掉某一元素，但不能把它放于不正确的位置。<br />
l icon icon元素指出IDE和GUI工具用来表示Web应用的一个和两个图像文件的位置。<br />
l display-name display-name元素提供GUI工具可能会用来标记这个特定的Web应用的一个名称。<br />
l description description元素给出与此有关的说明性文本。<br />
l context-param context-param元素声明应用范围内的初始化参数。<br />
l filter 过滤器元素将一个名字与一个实现javax.servlet.Filter接口的类相关联。<br />
l filter-mapping 一旦命名了一个过滤器，就要利用filter-mapping元素把它与一个或多个servlet或JSP页面相关联。<br />
l listener servlet API的版本2.3增加了对事件监听程序的支持，事件监听程序在建立、修改和删除会话或servlet环境时得到通知。Listener元素指出事件监听程序类。<br />
l servlet 在向servlet或JSP页面制定初始化参数或定制URL时，必须首先命名servlet或JSP页面。Servlet元素就是用来完成此项任务的。<br />
l servlet-mapping 服务器一般为servlet提供一个缺省的URL：</font><a href="http://host/webAppPrefix/servlet/ServletName" target="_blank"><font size="2">http://host/webAppPrefix/servlet/ServletName</font></a><font size="2">。但是，常常会更改这个URL，以便servlet可以访问初始化参数或更容易地处理相对URL。在更改缺省URL时，使用servlet-mapping元素。<br />
l session-config 如果某个会话在一定时间内未被访问，服务器可以抛弃它以节省内存。可通过使用HttpSession的setMaxInactiveInterval方法明确设置单个会话对象的超时值，或者可利用session-config元素制定缺省超时值。<br />
l mime-mapping 如果Web应用具有想到特殊的文件，希望能保证给他们分配特定的MIME类型，则mime-mapping元素提供这种保证。<br />
l welcom-file-list welcome-file-list元素指示服务器在收到引用一个目录名而不是文件名的URL时，使用哪个文件。<br />
l error-page error-page元素使得在返回特定HTTP状态代码时，或者特定类型的异常被抛出时，能够制定将要显示的页面。<br />
l taglib taglib元素对标记库描述符文件（Tag Libraryu Descriptor file）指定别名。此功能使你能够更改TLD文件的位置，而不用编辑使用这些文件的JSP页面。<br />
l resource-env-ref resource-env-ref元素声明与资源相关的一个管理对象。<br />
l resource-ref resource-ref元素声明一个资源工厂使用的外部资源。<br />
l security-constraint security-constraint元素制定应该保护的URL。它与login-config元素联合使用<br />
l login-config 用login-config元素来指定服务器应该怎样给试图访问受保护页面的用户授权。它与sercurity-constraint元素联合使用。<br />
l security-role security-role元素给出安全角色的一个列表，这些角色将出现在servlet元素内的security-role-ref元素的role-name子元素中。分别地声明角色可使高级IDE处理安全信息更为容易。<br />
l env-entry env-entry元素声明Web应用的环境项。<br />
l ejb-ref ejb-ref元素声明一个EJB的主目录的引用。<br />
l ejb-local-ref ejb-local-ref元素声明一个EJB的本地主目录的应用。<br />
<br />
3 分配名称和定制的UL<br />
<br />
在web.xml中完成的一个最常见的任务是对servlet或JSP页面给出名称和定制的URL。用servlet元素分配名称，使用servlet-mapping元素将定制的URL与刚分配的名称相关联。<br />
3.1 分配名称<br />
为了提供初始化参数，对servlet或JSP页面定义一个定制URL或分配一个安全角色，必须首先给servlet或JSP页面一个名称。可通过 servlet元素分配一个名称。最常见的格式包括servlet-name和servlet-class子元素（在web-app元素内），如下所示：<br />
&lt;servlet&gt;<br />
&lt;servlet-name&gt;Test&lt;/servlet-name&gt;<br />
&lt;servlet-class&gt;moreservlets.TestServlet&lt;/servlet-class&gt;<br />
&lt;/servlet&gt; <br />
这表示位于WEB-INF/classes/moreservlets/TestServlet的servlet已经得到了注册名Test。给 servlet一个名称具有两个主要的含义。首先，初始化参数、定制的URL模式以及其他定制通过此注册名而不是类名引用此servlet。其次,可在 URL而不是类名中使用此名称。因此，利用刚才给出的定义，URL </font><a href="http://host/webAppPrefix/servlet/Test" target="_blank"><font size="2">http://host/webAppPrefix/servlet/Test</font></a><font size="2"> 可用于 </font><a href="http://host/webAppPrefix/servlet/moreservlets.TestServlet" target="_blank"><font size="2">http://host/webAppPrefix/servlet/moreservlets.TestServlet</font></a><font size="2"> 的场所。<br />
请记住：XML元素不仅是大小写敏感的，而且定义它们的次序也很重要。例如，web-app元素内所有servlet元素必须位于所有servlet- mapping元素（下一小节介绍）之前，而且还要位于5.6节和5.11节讨论的与过滤器或文档相关的元素（如果有的话）之前。类似地，servlet 的servlet-name子元素也必须出现在servlet-class之前。5.2节"部署描述符文件内的元素次序"将详细介绍这种必需的次序。<br />
例如，程序清单5-1给出了一个名为TestServlet的简单servlet，它驻留在moreservlets程序包中。因为此servlet是扎根在一个名为deployDemo的目录中的Web应用的组成部分，所以TestServlet.class放在deployDemo/WEB- INF/classes/moreservlets中。程序清单5-2给出将放置在deployDemo/WEB-INF/内的web.xml文件的一部分。此web.xml文件使用servlet-name和servlet-class元素将名称Test与TestServlet.class相关联。图 5-1和图5-2分别显示利用缺省URL和注册名调用TestServlet时的结果。<br />
<br />
程序清单5-1 TestServlet.java<br />
package moreservlets;<br />
<br />
import java.io.*;<br />
import javax.servlet.*;<br />
import javax.servlet.http.*;<br />
<br />
/** Simple servlet used to illustrate servlet naming<br />
* and custom URLs.<br />
* &lt;P&gt;<br />
* Taken from More Servlets and JavaServer Pages<br />
* from Prentice Hall and Sun Microsystems Press,<br />
* </font><a href="http://www.moreservlets.com/." target="_blank"><font size="2">http://www.moreservlets.com/.</font></a><br />
<font size="2">* &#169; 2002 Marty Hall; may be freely used or adapted.<br />
*/<br />
<br />
public class TestServlet extends HttpServlet {<br />
public void doGet(HttpServletRequest request,<br />
HttpServletResponse response)<br />
throws ServletException, IOException {<br />
response.setContentType("text/html");<br />
PrintWriter out = response.getWriter();<br />
String uri = request.getRequestURI();<br />
out.println(ServletUtilities.headWithTitle("Test Servlet") +<br />
"&lt;BODY BGCOLOR=\"#FDF5E6\"&gt;\n" +<br />
"&lt;H2&gt;URI: " + uri + "&lt;/H2&gt;\n" +<br />
"&lt;/BODY&gt;&lt;/HTML&gt;");<br />
}<br />
}<br />
<br />
<br />
程序清单5-2 web.xml（说明servlet名称的摘录）<br />
&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;<br />
&lt;!DOCTYPE web-app<br />
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"<br />
"</font><a href="http://java.sun.com/dtd/web-app_2_3.dtd" target="_blank"><font size="2">http://java.sun.com/dtd/web-app_2_3.dtd</font></a><font size="2">"&gt;<br />
<br />
&lt;web-app&gt;<br />
&lt;!-- &#8230; --&gt;<br />
&lt;servlet&gt;<br />
&lt;servlet-name&gt;Test&lt;/servlet-name&gt;<br />
&lt;servlet-class&gt;moreservlets.TestServlet&lt;/servlet-class&gt;<br />
&lt;/servlet&gt;<br />
&lt;!-- &#8230; --&gt;<br />
&lt;/web-app&gt;<br />
<br />
3.2 定义定制的URL<br />
大多数服务器具有一个缺省的serlvet URL：<br />
</font><a href="http://host/webAppPrefix/servlet/packageName.ServletName" target="_blank"><font size="2">http://host/webAppPrefix/servlet/packageName.ServletName</font></a><font size="2">。虽然在开发中使用这个URL很方便，但是我们常常会希望另一个URL用于部署。例如，可能会需要一个出现在Web应用顶层的URL（如，http: //host/webAppPrefix/Anyname），并且在此URL中没有servlet项。位于顶层的URL简化了相对URL的使用。此外，对许多开发人员来说，顶层URL看上去比更长更麻烦的缺省URL更简短。<br />
事实上，有时需要使用定制的URL。比如，你可能想关闭缺省URL映射，以便更好地强制实施安全限制或防止用户意外地访问无初始化参数的servlet。如果你禁止了缺省的URL，那么你怎样访问servlet呢？这时只有使用定制的URL了。<br />
为了分配一个定制的URL，可使用servlet-mapping元素及其servlet-name和url-pattern子元素。Servlet- name元素提供了一个任意名称，可利用此名称引用相应的servlet；url-pattern描述了相对于Web应用的根目录的URL。url- pattern元素的值必须以斜杠（/）起始。<br />
下面给出一个简单的web.xml摘录，它允许使用URL </font><a href="http://host/webAppPrefix/UrlTest" target="_blank"><font size="2">http://host/webAppPrefix/UrlTest</font></a><font size="2">而不是</font><a href="http://host/webAppPrefix/servlet/Test" target="_blank"><font size="2">http://host/webAppPrefix/servlet/Test</font></a><font size="2">或<br />
http: //host/webAppPrefix/servlet/moreservlets.TestServlet。请注意，仍然需要XML头、 DOCTYPE声明以及web-app封闭元素。此外，可回忆一下，XML元素出现地次序不是随意的。特别是，需要把所有servlet元素放在所有 servlet-mapping元素之前。<br />
&lt;servlet&gt;<br />
&lt;servlet-name&gt;Test&lt;/servlet-name&gt;<br />
&lt;servlet-class&gt;moreservlets.TestServlet&lt;/servlet-class&gt;<br />
&lt;/servlet&gt;<br />
&lt;!-- ... --&gt;<br />
&lt;servlet-mapping&gt;<br />
&lt;servlet-name&gt;Test&lt;/servlet-name&gt;<br />
&lt;url-pattern&gt;/UrlTest&lt;/url-pattern&gt;<br />
&lt;/servlet-mapping&gt;<br />
URL模式还可以包含通配符。例如，下面的小程序指示服务器发送所有以Web应用的URL前缀开始，以..asp结束的请求到名为BashMS的servlet。<br />
&lt;servlet&gt;<br />
&lt;servlet-name&gt;BashMS&lt;/servlet-name&gt;<br />
&lt;servlet-class&gt;msUtils.ASPTranslator&lt;/servlet-class&gt;<br />
&lt;/servlet&gt;<br />
&lt;!-- ... --&gt;<br />
&lt;servlet-mapping&gt;<br />
&lt;servlet-name&gt;BashMS&lt;/servlet-name&gt;<br />
&lt;url-pattern&gt;/*.asp&lt;/url-pattern&gt;<br />
&lt;/servlet-mapping&gt;<br />
3.3 命名JSP页面<br />
因为JSP页面要转换成sevlet，自然希望就像命名servlet一样命名JSP页面。毕竟，JSP页面可能会从初始化参数、安全设置或定制的URL中受益，正如普通的serlvet那样。虽然JSP页面的后台实际上是servlet这句话是正确的，但存在一个关键的猜疑：即，你不知道JSP页面的实际类名（因为系统自己挑选这个名字）。因此，为了命名JSP页面，可将jsp-file元素替换为servlet-calss元素，如下所示：<br />
&lt;servlet&gt;<br />
&lt;servlet-name&gt;Test&lt;/servlet-name&gt;<br />
&lt;jsp-file&gt;/TestPage.jsp&lt;/jsp-file&gt;<br />
&lt;/servlet&gt;<br />
命名JSP页面的原因与命名servlet的原因完全相同：即为了提供一个与定制设置（如，初始化参数和安全设置）一起使用的名称，并且，以便能更改激活 JSP页面的URL（比方说，以便多个URL通过相同页面得以处理，或者从URL中去掉.jsp扩展名）。但是，在设置初始化参数时，应该注意，JSP页面是利用jspInit方法，而不是init方法读取初始化参数的。<br />
例如，程序清单5-3给出一个名为TestPage.jsp的简单JSP页面，它的工作只是打印出用来激活它的URL的本地部分。TestPage.jsp放置在deployDemo应用的顶层。程序清单5-4给出了用来分配一个注册名PageName，然后将此注册名与</font><a href="http://host/webAppPrefix/UrlTest2/anything" target="_blank"><font size="2">http://host/webAppPrefix/UrlTest2/anything</font></a><font size="2"> 形式的URL相关联的web.xml文件（即，deployDemo/WEB-INF/web.xml）的一部分。<br />
<br />
程序清单5-3 TestPage.jsp<br />
&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"&gt;<br />
&lt;HTML&gt;<br />
&lt;HEAD&gt;<br />
&lt;TITLE&gt;<br />
JSP Test Page<br />
&lt;/TITLE&gt;<br />
&lt;/HEAD&gt;<br />
&lt;BODY BGCOLOR="#FDF5E6"&gt;<br />
&lt;H2&gt;URI: &lt;%= request.getRequestURI() %&gt;&lt;/H2&gt;<br />
&lt;/BODY&gt;<br />
&lt;/HTML&gt;<br />
<br />
<br />
程序清单5-4 web.xml（说明JSP页命名的摘录）<br />
&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;<br />
&lt;!DOCTYPE web-app<br />
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"<br />
"</font><a href="http://java.sun.com/dtd/web-app_2_3.dtd" target="_blank"><font size="2">http://java.sun.com/dtd/web-app_2_3.dtd</font></a><font size="2">"&gt;<br />
<br />
&lt;web-app&gt;<br />
&lt;!-- ... --&gt;<br />
&lt;servlet&gt;<br />
&lt;servlet-name&gt;PageName&lt;/servlet-name&gt;<br />
&lt;jsp-file&gt;/TestPage.jsp&lt;/jsp-file&gt;<br />
&lt;/servlet&gt;<br />
&lt;!-- ... --&gt;<br />
&lt;servlet-mapping&gt;<br />
&lt;servlet-name&gt; PageName &lt;/servlet-name&gt;<br />
&lt;url-pattern&gt;/UrlTest2/*&lt;/url-pattern&gt;<br />
&lt;/servlet-mapping&gt;<br />
&lt;!-- ... --&gt;<br />
&lt;/web-app&gt;<br />
<br />
<br />
4 禁止激活器servlet<br />
<br />
对servlet或JSP页面建立定制URL的一个原因是，这样做可以注册从 init（servlet）或jspInit（JSP页面）方法中读取得初始化参数。但是，初始化参数只在是利用定制URL模式或注册名访问 servlet或JSP页面时可以使用，用缺省URL </font><a href="http://host/webAppPrefix/servlet/ServletName" target="_blank"><font size="2">http://host/webAppPrefix/servlet/ServletName</font></a><font size="2"> 访问时不能使用。因此，你可能会希望关闭缺省URL，这样就不会有人意外地调用初始化servlet了。这个过程有时称为禁止激活器servlet，因为多数服务器具有一个用缺省的servlet URL注册的标准servlet，并激活缺省的URL应用的实际servlet。<br />
有两种禁止此缺省URL的主要方法：<br />
l 在每个Web应用中重新映射/servlet/模式。<br />
l 全局关闭激活器servlet。<br />
重要的是应该注意到，虽然重新映射每个Web应用中的/servlet/模式比彻底禁止激活servlet所做的工作更多，但重新映射可以用一种完全可移植的方式来完成。相反，全局禁止激活器servlet完全是针对具体机器的，事实上有的服务器（如ServletExec）没有这样的选择。下面的讨论对每个Web应用重新映射/servlet/ URL模式的策略。后面提供在Tomcat中全局禁止激活器servlet的详细内容。<br />
4.1 重新映射/servlet/URL模式<br />
在一个特定的Web应用中禁止以</font><a href="http://host/webAppPrefix/servlet/" target="_blank"><font size="2">http://host/webAppPrefix/servlet/</font></a><font size="2"> 开始的URL的处理非常简单。所需做的事情就是建立一个错误消息servlet，并使用前一节讨论的url-pattern元素将所有匹配请求转向该 servlet。只要简单地使用：<br />
&lt;url-pattern&gt;/servlet/*&lt;/url-pattern&gt;<br />
作为servlet-mapping元素中的模式即可。<br />
例如，程序清单5-5给出了将SorryServlet servlet（程序清单5-6）与所有以</font><a href="http://host/webAppPrefix/servlet/" target="_blank"><font size="2">http://host/webAppPrefix/servlet/</font></a><font size="2"> 开头的URL相关联的部署描述符文件的一部分。<br />
<br />
程序清单5-5 web.xml（说明JSP页命名的摘录）<br />
&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;<br />
&lt;!DOCTYPE web-app<br />
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"<br />
"</font><a href="http://java.sun.com/dtd/web-app_2_3.dtd" target="_blank"><font size="2">http://java.sun.com/dtd/web-app_2_3.dtd</font></a><font size="2">"&gt;<br />
<br />
&lt;web-app&gt;<br />
&lt;!-- ... --&gt;<br />
&lt;servlet&gt;<br />
&lt;servlet-name&gt;Sorry&lt;/servlet-name&gt;<br />
&lt;servlet-class&gt;moreservlets.SorryServlet&lt;/servlet-class&gt;<br />
&lt;/servlet&gt;<br />
&lt;!-- ... --&gt;<br />
&lt;servlet-mapping&gt;<br />
&lt;servlet-name&gt; Sorry &lt;/servlet-name&gt;<br />
&lt;url-pattern&gt;/servlet/*&lt;/url-pattern&gt;<br />
&lt;/servlet-mapping&gt;<br />
&lt;!-- ... --&gt;<br />
&lt;/web-app&gt;<br />
<br />
<br />
程序清单5-6 SorryServlet.java<br />
package moreservlets;<br />
<br />
import java.io.*;<br />
import javax.servlet.*;<br />
import javax.servlet.http.*;<br />
<br />
/** Simple servlet used to give error messages to<br />
* users who try to access default servlet URLs<br />
* (i.e., </font><a href="http://host/webAppPrefix/servlet/ServletName" target="_blank"><font size="2">http://host/webAppPrefix/servlet/ServletName</font></a><font size="2">)<br />
* in Web applications that have disabled this<br />
* behavior.<br />
* &lt;P&gt;<br />
* Taken from More Servlets and JavaServer Pages<br />
* from Prentice Hall and Sun Microsystems Press,<br />
* </font><a href="http://www.moreservlets.com/." target="_blank"><font size="2">http://www.moreservlets.com/.</font></a><br />
<font size="2">* &#169; 2002 Marty Hall; may be freely used or adapted.<br />
*/<br />
<br />
public class SorryServlet extends HttpServlet {<br />
public void doGet(HttpServletRequest request,<br />
HttpServletResponse response)<br />
throws ServletException, IOException {<br />
response.setContentType("text/html");<br />
PrintWriter out = response.getWriter();<br />
String title = "Invoker Servlet Disabled.";<br />
out.println(ServletUtilities.headWithTitle(title) +<br />
"&lt;BODY BGCOLOR=\"#FDF5E6\"&gt;\n" +<br />
"&lt;H2&gt;" + title + "&lt;/H2&gt;\n" +<br />
"Sorry, access to servlets by means of\n" +<br />
"URLs that begin with\n" +<br />
"</font><a href="http://host/webAppPrefix/servlet/" target="_blank"><font size="2">http://host/webAppPrefix/servlet/</font></a><font size="2">\n" +<br />
"has been disabled.\n" + <br />
"&lt;/BODY&gt;&lt;/HTML&gt;");<br />
}<br />
<br />
public void doPost(HttpServletRequest request,<br />
HttpServletResponse response)<br />
throws ServletException, IOException {<br />
doGet(request, response);<br />
}<br />
}<br />
<br />
<br />
4.2 全局禁止激活器：Tomcat<br />
Tomcat 4中用来关闭缺省URL的方法与Tomcat 3中所用的很不相同。下面介绍这两种方法：<br />
1．禁止激活器： Tomcat 4<br />
Tomcat 4用与前面相同的方法关闭激活器servlet，即利用web.xml中的url-mapping元素进行关闭。不同之处在于Tomcat使用了放在 install_dir/conf中的一个服务器专用的全局web.xml文件，而前面使用的是存放在每个Web应用的WEB-INF目录中的标准 web.xml文件。<br />
因此，为了在Tomcat 4中关闭激活器servlet，只需在install_dir/conf/web.xml中简单地注释出/servlet/* URL映射项即可，如下所示：<br />
&lt;!-- <br />
&lt;servlet-mapping&gt;<br />
&lt;servlet-name&gt;invoker&lt;/servlet-name&gt;<br />
&lt;url-pattern&gt;/servlet/*&lt;/url-pattern&gt;<br />
&lt;/servlet-mapping&gt;<br />
--&gt;<br />
再次提醒，应该注意这个项是位于存放在install_dir/conf的Tomcat专用的web.xml文件中的，此文件不是存放在每个Web应用的WEB-INF目录中的标准web.xml。<br />
2．禁止激活器：Tomcat3<br />
在Apache Tomcat的版本3中，通过在install_dir/conf/server.xml中注释出InvokerInterceptor项全局禁止缺省 servlet URL。例如，下面是禁止使用缺省servlet URL的server.xml文件的一部分。<br />
&lt;!-- <br />
&lt;RequsetInterceptor <br />
className="org.apache.tomcat.request.InvokerInterceptor"<br />
debug="0" prefix="/servlet/" /&gt;<br />
--&gt;<br />
<br />
5 初始化和预装载servlet与JSP页面<br />
<br />
这里讨论控制servlet和JSP页面的启动行为的方法。特别是，说明了怎样分配初始化参数以及怎样更改服务器生存期中装载servlet和JSP页面的时刻。<br />
5.1 分配servlet初始化参数<br />
利用init-param元素向servlet提供初始化参数，init-param元素具有param-name和param-value子元素。例如，在下面的例子中，如果initServlet servlet是利用它的注册名（InitTest）访问的，它将能够从其方法中调用getServletConfig(). getInitParameter("param1")获得"Value 1"，调用getServletConfig().getInitParameter("param2")获得"2"。<br />
&lt;servlet&gt;<br />
&lt;servlet-name&gt;InitTest&lt;/servlet-name&gt;<br />
&lt;servlet-class&gt;moreservlets.InitServlet&lt;/servlet-class&gt;<br />
&lt;init-param&gt;<br />
&lt;param-name&gt;param1&lt;/param-name&gt;<br />
&lt;param-value&gt;value1&lt;/param-value&gt;<br />
&lt;/init-param&gt;<br />
&lt;init-param&gt;<br />
&lt;param-name&gt;param2&lt;/param-name&gt;<br />
&lt;param-value&gt;2&lt;/param-value&gt;<br />
&lt;/init-param&gt;<br />
&lt;/servlet&gt;<br />
在涉及初始化参数时，有几点需要注意：<br />
l 返回值。GetInitParameter的返回值总是一个String。因此，在前一个例子中，可对param2使用Integer.parseInt获得一个int。<br />
l JSP中的初始化。JSP页面使用jspInit而不是init。JSP页面还需要使用jsp-file元素代替servlet-class。<br />
l 缺省URL。初始化参数只在通过它们的注册名或与它们注册名相关的定制URL模式访问Servlet时可以使用。因此，在这个例子中，param1和 param2初始化参数将能够在使用URL </font><a href="http://host/webAppPrefix/servlet/InitTest" target="_blank"><font size="2">http://host/webAppPrefix/servlet/InitTest</font></a><font size="2"> 时可用，但在使用URL </font><a href="http://host/webAppPrefix/servlet/myPackage.InitServlet" target="_blank"><font size="2">http://host/webAppPrefix/servlet/myPackage.InitServlet</font></a><font size="2"> 时不能使用。<br />
例如，程序清单5-7给出一个名为InitServlet的简单servlet，它使用init方法设置firstName和emailAddress字段。程序清单5-8给出分配名称InitTest给servlet的web.xml文件。<br />
程序清单5-7 InitServlet.java<br />
package moreservlets;<br />
<br />
import java.io.*;<br />
import javax.servlet.*;<br />
import javax.servlet.http.*;<br />
<br />
/** Simple servlet used to illustrate servlet<br />
* initialization parameters.<br />
* &lt;P&gt;<br />
* Taken from More Servlets and JavaServer Pages<br />
* from Prentice Hall and Sun Microsystems Press,<br />
* </font><a href="http://www.moreservlets.com/." target="_blank"><font size="2">http://www.moreservlets.com/.</font></a><br />
<font size="2">* &#169; 2002 Marty Hall; may be freely used or adapted.<br />
*/<br />
<br />
public class InitServlet extends HttpServlet {<br />
private String firstName, emailAddress;<br />
<br />
public void init() {<br />
ServletConfig config = getServletConfig();<br />
firstName = config.getInitParameter("firstName");<br />
emailAddress = config.getInitParameter("emailAddress");<br />
}<br />
<br />
public void doGet(HttpServletRequest request,<br />
HttpServletResponse response)<br />
throws ServletException, IOException {<br />
response.setContentType("text/html");<br />
PrintWriter out = response.getWriter();<br />
String uri = request.getRequestURI();<br />
out.println(ServletUtilities.headWithTitle("Init Servlet") +<br />
"&lt;BODY BGCOLOR=\"#FDF5E6\"&gt;\n" +<br />
"&lt;H2&gt;Init Parameters:&lt;/H2&gt;\n" +<br />
"&lt;UL&gt;\n" +<br />
"&lt;LI&gt;First name: " + firstName + "\n" +<br />
"&lt;LI&gt;Email address: " + emailAddress + "\n" +<br />
"&lt;/UL&gt;\n" + <br />
"&lt;/BODY&gt;&lt;/HTML&gt;");<br />
}<br />
}<br />
<br />
<br />
程序清单5-8 web.xml（说明初始化参数的摘录）<br />
&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;<br />
&lt;!DOCTYPE web-app<br />
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"<br />
"</font><a href="http://java.sun.com/dtd/web-app_2_3.dtd" target="_blank"><font size="2">http://java.sun.com/dtd/web-app_2_3.dtd</font></a><font size="2">"&gt;<br />
<br />
&lt;web-app&gt;<br />
&lt;!-- ... --&gt;<br />
&lt;servlet&gt;<br />
&lt;servlet-name&gt;InitTest&lt;/servlet-name&gt;<br />
&lt;servlet-class&gt;moreservlets.InitServlet&lt;/servlet-class&gt;<br />
&lt;init-param&gt;<br />
&lt;param-name&gt;firstName&lt;/param-name&gt;<br />
&lt;param-value&gt;Larry&lt;/param-value&gt;<br />
&lt;/init-param&gt;<br />
&lt;init-param&gt;<br />
&lt;param-name&gt;emailAddress&lt;/param-name&gt;<br />
&lt;param-value&gt;</font><a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#69;&#108;&#108;&#105;&#115;&#111;&#110;&#64;&#77;&#105;&#99;&#114;&#111;&#115;&#111;&#102;&#116;&#46;&#99;&#111;&#109;"><font size="2">Ellison@Microsoft.com</font></a><font size="2">&lt;/param-value&gt;<br />
&lt;/init-param&gt;<br />
&lt;/servlet&gt;<br />
&lt;!-- ... --&gt;<br />
&lt;/web-app&gt;<br />
<br />
5.2 分配JSP初始化参数<br />
给JSP页面提供初始化参数在三个方面不同于给servlet提供初始化参数。<br />
1）使用jsp-file而不是servlet-class。因此，WEB-INF/web.xml文件的servlet元素如下所示：<br />
&lt;servlet&gt;<br />
&lt;servlet-name&gt;PageName&lt;/servlet-name&gt;<br />
&lt;jsp-file&gt;/RealPage.jsp&lt;/jsp-file&gt;<br />
&lt;init-param&gt;<br />
&lt;param-name&gt;...&lt;/param-name&gt;<br />
&lt;param-value&gt;...&lt;/param-value&gt;<br />
&lt;/init-param&gt;<br />
...<br />
&lt;/servlet&gt;<br />
2) 几乎总是分配一个明确的URL模式。对servlet，一般相应地使用以</font><a href="http://host/webAppPrefix/servlet/" target="_blank"><font size="2">http://host/webAppPrefix/servlet/</font></a><font size="2"> 开始的缺省URL。只需记住，使用注册名而不是原名称即可。这对于JSP页面在技术上也是合法的。例如，在上面给出的例子中，可用URL </font><a href="http://host/webAppPrefix/servlet/PageName" target="_blank"><font size="2">http://host/webAppPrefix/servlet/PageName</font></a><font size="2"> 访问RealPage.jsp的对初始化参数具有访问权的版本。但在用于JSP页面时，许多用户似乎不喜欢应用常规的servlet的URL。此外，如果 JSP页面位于服务器为其提供了目录清单的目录中（如，一个既没有index.html也没有index.jsp文件的目录），则用户可能会连接到此 JSP页面，单击它，从而意外地激活未初始化的页面。因此，好的办法是使用url-pattern（5.3节）将JSP页面的原URL与注册的 servlet名相关联。这样，客户机可使用JSP页面的普通名称，但仍然激活定制的版本。例如，给定来自项目1的servlet定义，可使用下面的 servlet-mapping定义：<br />
&lt;servlet-mapping&gt;<br />
&lt;servlet-name&gt;PageName&lt;/servlet-name&gt;<br />
&lt;url-pattern&gt;/RealPage.jsp&lt;/url-pattern&gt;<br />
&lt;/servlet-mapping&gt;<br />
3）JSP页使用jspInit而不是init。自动从JSP页面建立的servlet或许已经使用了inti方法。因此，使用JSP声明提供一个init方法是不合法的，必须制定jspInit方法。<br />
为了说明初始化JSP页面的过程，程序清单5-9给出了一个名为InitPage.jsp的JSP页面，它包含一个jspInit方法且放置于 deployDemo Web应用层次结构的顶层。一般，</font><a href="http://host/deployDemo/InitPage.jsp" target="_blank"><font size="2">http://host/deployDemo/InitPage.jsp</font></a><font size="2"> 形式的URL将激活此页面的不具有初始化参数访问权的版本，从而将对firstName和emailAddress变量显示null。但是， web.xml文件（程序清单5-10）分配了一个注册名，然后将该注册名与URL模式/InitPage.jsp相关联。<br />
<br />
程序清单5-9 InitPage.jsp<br />
&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"&gt;<br />
&lt;HTML&gt;<br />
&lt;HEAD&gt;&lt;TITLE&gt;JSP Init Test&lt;/TITLE&gt;&lt;/HEAD&gt;<br />
&lt;BODY BGCOLOR="#FDF5E6"&gt;<br />
&lt;H2&gt;Init Parameters:&lt;/H2&gt;<br />
&lt;UL&gt;<br />
&lt;LI&gt;First name: &lt;%= firstName %&gt;<br />
&lt;LI&gt;Email address: &lt;%= emailAddress %&gt;<br />
&lt;/UL&gt;<br />
&lt;/BODY&gt;&lt;/HTML&gt;<br />
&lt;%!<br />
private String firstName, emailAddress;<br />
<br />
public void jspInit() {<br />
ServletConfig config = getServletConfig();<br />
firstName = config.getInitParameter("firstName");<br />
emailAddress = config.getInitParameter("emailAddress");<br />
}<br />
%&gt;<br />
<br />
<br />
程序清单5-10 web.xml（说明JSP页面的init参数的摘录）<br />
&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;<br />
&lt;!DOCTYPE web-app<br />
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"<br />
"</font><a href="http://java.sun.com/dtd/web-app_2_3.dtd" target="_blank"><font size="2">http://java.sun.com/dtd/web-app_2_3.dtd</font></a><font size="2">"&gt;<br />
<br />
&lt;web-app&gt;<br />
&lt;!-- ... --&gt;<br />
&lt;servlet&gt;<br />
&lt;servlet-name&gt;InitPage&lt;/servlet-name&gt;<br />
&lt;jsp-file&gt;/InitPage.jsp&lt;/jsp-file&gt;<br />
&lt;init-param&gt;<br />
&lt;param-name&gt;firstName&lt;/param-name&gt;<br />
&lt;param-value&gt;Bill&lt;/param-value&gt;<br />
&lt;/init-param&gt;<br />
&lt;init-param&gt;<br />
&lt;param-name&gt;emailAddress&lt;/param-name&gt;<br />
&lt;param-value&gt;</font><a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#103;&#97;&#116;&#101;&#115;&#64;&#111;&#114;&#97;&#99;&#108;&#101;&#46;&#99;&#111;&#109;"><font size="2">gates@oracle.com</font></a><font size="2">&lt;/param-value&gt;<br />
&lt;/init-param&gt;<br />
&lt;/servlet&gt;<br />
&lt;!-- ... --&gt; <br />
&lt;servlet-mapping&gt;<br />
&lt;servlet-name&gt; InitPage&lt;/servlet-name&gt;<br />
&lt;url-pattern&gt;/InitPage.jsp&lt;/url-pattern&gt;<br />
&lt;/servlet-mapping&gt;<br />
&lt;!-- ... --&gt;<br />
&lt;/web-app&gt;<br />
<br />
<br />
5.3 提供应用范围内的初始化参数<br />
一般，对单个地servlet或JSP页面分配初始化参数。指定的servlet或JSP页面利用ServletConfig的getInitParameter方法读取这些参数。但是，在某些情形下，希望提供可由任意servlet或JSP页面借助ServletContext的getInitParameter方法读取的系统范围内的初始化参数。<br />
可利用context-param元素声明这些系统范围内的初始化值。context-param元素应该包含param-name、param-value以及可选的description子元素，如下所示：<br />
&lt;context-param&gt;<br />
&lt;param-name&gt;support-email&lt;/param-name&gt;<br />
&lt;param-value&gt;</font><a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#98;&#108;&#97;&#99;&#107;&#104;&#111;&#108;&#101;&#64;&#109;&#121;&#99;&#111;&#109;&#112;&#97;&#110;&#121;&#46;&#99;&#111;&#109;"><font size="2">blackhole@mycompany.com</font></a><font size="2">&lt;/param-value&gt;<br />
&lt;/context-param&gt;<br />
可回忆一下，为了保证可移植性，web.xml内的元素必须以正确的次序声明。但这里应该注意，context-param元素必须出现任意与文档有关的元素（icon、display-name或description）之后及filter、filter-mapping、listener或 servlet元素之前。<br />
5.4 在服务器启动时装载servlet<br />
假如servlet或JSP页面有一个要花很长时间执行的init （servlet）或jspInit（JSP）方法。例如，假如init或jspInit方法从某个数据库或ResourceBundle查找产量。这种情况下，在第一个客户机请求时装载servlet的缺省行为将对第一个客户机产生较长时间的延迟。因此，可利用servlet的load-on- startup元素规定服务器在第一次启动时装载servlet。下面是一个例子。<br />
&lt;servlet&gt;<br />
&lt;servlet-name&gt; &#8230; &lt;/servlet-name&gt;<br />
&lt;servlet-class&gt; &#8230; &lt;/servlet-class&gt; &lt;!-- Or jsp-file --&gt;<br />
&lt;load-on-startup/&gt;<br />
&lt;/servlet&gt;<br />
可以为此元素体提供一个整数而不是使用一个空的load-on-startup。想法是服务器应该在装载较大数目的servlet或JSP页面之前装载较少数目的servlet或JSP页面。例如，下面的servlet项（放置在Web应用的WEB-INF目录下的web.xml文件中的web-app元素内）将指示服务器首先装载和初始化SearchServlet，然后装载和初始化由位于Web应用的result目录中的index.jsp文件产生的 servlet。<br />
&lt;servlet&gt;<br />
&lt;servlet-name&gt;Search&lt;/servlet-name&gt;<br />
&lt;servlet-class&gt;myPackage.SearchServlet&lt;/servlet-class&gt; &lt;!-- Or jsp-file --&gt;<br />
&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;<br />
&lt;/servlet&gt;<br />
&lt;servlet&gt;<br />
&lt;servlet-name&gt;Results&lt;/servlet-name&gt;<br />
&lt;servlet-class&gt;/results/index.jsp&lt;/servlet-class&gt; &lt;!-- Or jsp-file --&gt;<br />
&lt;load-on-startup&gt;2&lt;/load-on-startup&gt;<br />
&lt;/servlet&gt;<br />
<br />
6 声明过滤器<br />
<br />
servlet版本2.3引入了过滤器的概念。虽然所有支持servlet API版本2.3的服务器都支持过滤器，但为了使用与过滤器有关的元素，必须在web.xml中使用版本2.3的DTD。<br />
过滤器可截取和修改进入一个servlet或JSP页面的请求或从一个servlet或JSP页面发出的相应。在执行一个servlet或JSP页面之前，必须执行第一个相关的过滤器的doFilter方法。在该过滤器对其FilterChain对象调用doFilter时，执行链中的下一个过滤器。如果没有其他过滤器，servlet或JSP页面被执行。过滤器具有对到来的ServletRequest对象的全部访问权，因此，它们可以查看客户机名、查找到来的cookie等。为了访问servlet或JSP页面的输出，过滤器可将响应对象包裹在一个替身对象（stand-in object）中，比方说把输出累加到一个缓冲区。在调用FilterChain对象的doFilter方法之后，过滤器可检查缓冲区，如有必要，就对它进行修改，然后传送到客户机。<br />
例如，程序清单5-11帝国难以了一个简单的过滤器，只要访问相关的servlet或JSP页面，它就截取请求并在标准输出上打印一个报告（开发过程中在桌面系统上运行时，大多数服务器都可以使用这个过滤器）。<br />
<br />
程序清单5-11 ReportFilter.java<br />
package moreservlets;<br />
<br />
import java.io.*;<br />
import javax.servlet.*;<br />
import javax.servlet.http.*;<br />
import java.util.*;<br />
<br />
/** Simple filter that prints a report on the standard output <br />
* whenever the associated servlet or JSP page is accessed.<br />
* &lt;P&gt;<br />
* Taken from More Servlets and JavaServer Pages<br />
* from Prentice Hall and Sun Microsystems Press,<br />
* </font><a href="http://www.moreservlets.com/." target="_blank"><font size="2">http://www.moreservlets.com/.</font></a><br />
<font size="2">* &#169; 2002 Marty Hall; may be freely used or adapted.<br />
*/<br />
<br />
public class ReportFilter implements Filter {<br />
public void doFilter(ServletRequest request,<br />
ServletResponse response,<br />
FilterChain chain)<br />
throws ServletException, IOException {<br />
HttpServletRequest req = (HttpServletRequest)request;<br />
System.out.println(req.getRemoteHost() +<br />
" tried to access " +<br />
req.getRequestURL() +<br />
" on " + new Date() + ".");<br />
chain.doFilter(request,response);<br />
}<br />
<br />
public void init(FilterConfig config)<br />
throws ServletException {<br />
}<br />
<br />
public void destroy() {}<br />
}<br />
<br />
一旦建立了一个过滤器，可以在web.xml中利用filter元素以及filter-name（任意名称）、file-class（完全限定的类名）和（可选的）init-params子元素声明它。请注意，元素在web.xml的web-app元素中出现的次序不是任意的；允许服务器（但不是必需的）强制所需的次序，并且实际中有些服务器也是这样做的。但这里要注意，所有filter元素必须出现在任意filter-mapping元素之前， filter-mapping元素又必须出现在所有servlet或servlet-mapping元素之前。<br />
例如，给定上述的ReportFilter类，可在web.xml中作出下面的filter声明。它把名称Reporter与实际的类ReportFilter（位于moreservlets程序包中）相关联。<br />
&lt;filter&gt;<br />
&lt;filter-name&gt;Reporter&lt;/filter-name&gt;<br />
&lt;filter-class&gt;moresevlets.ReportFilter&lt;/filter-class&gt;<br />
&lt;/filter&gt;<br />
一旦命名了一个过滤器，可利用filter-mapping元素把它与一个或多个servlet或JSP页面相关联。关于此项工作有两种选择。<br />
首先，可使用filter-name和servlet-name子元素把此过滤器与一个特定的servlet名（此servlet名必须稍后在相同的 web.xml文件中使用servlet元素声明）关联。例如，下面的程序片断指示系统只要利用一个定制的URL访问名为SomeServletName 的servlet或JSP页面，就运行名为Reporter的过滤器。<br />
&lt;filter-mapping&gt;<br />
&lt;filter-name&gt;Reporter&lt;/filter-name&gt;<br />
&lt;servlet-name&gt;SomeServletName&lt;/servlet-name&gt;<br />
&lt;/filter-mapping&gt;<br />
其次，可利用filter-name和url-pattern子元素将过滤器与一组servlet、JSP页面或静态内容相关联。例如，相面的程序片段指示系统只要访问Web应用中的任意URL，就运行名为Reporter的过滤器。<br />
&lt;filter-mapping&gt;<br />
&lt;filter-name&gt;Reporter&lt;/filter-name&gt;<br />
&lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br />
&lt;/filter-mapping&gt;<br />
例如，程序清单5-12给出了将ReportFilter过滤器与名为PageName的servlet相关联的web.xml文件的一部分。名字 PageName依次又与一个名为TestPage.jsp的JSP页面以及以模式http: //host/webAppPrefix/UrlTest2/ 开头的URL相关联。TestPage.jsp的源代码已经JSP页面命名的谈论在前面的3节"分配名称和定制的URL"中给出。事实上，程序清单5- 12中的servlet和servlet-name项从该节原封不动地拿过来的。给定这些web.xml项，可看到下面的标准输出形式的调试报告（换行是为了容易阅读）。<br />
audit.irs.gov tried to access <br />
</font><a href="http://mycompany.com/deployDemo/UrlTest2/business/tax-plan.html" target="_blank"><font size="2">http://mycompany.com/deployDemo/UrlTest2/business/tax-plan.html</font></a><br />
<font size="2">on Tue Dec 25 13:12:29 EDT 2001.<br />
<br />
程序清单5-12 Web.xml（说明filter用法的摘录）<br />
&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;<br />
&lt;!DOCTYPE web-app<br />
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"<br />
"</font><a href="http://java.sun.com/dtd/web-app_2_3.dtd" target="_blank"><font size="2">http://java.sun.com/dtd/web-app_2_3.dtd</font></a><font size="2">"&gt;<br />
<br />
&lt;web-app&gt;<br />
&lt;filter&gt;<br />
&lt;filter-name&gt;Reporter&lt;/filter-name&gt;<br />
&lt;filter-class&gt;moresevlets.ReportFilter&lt;/filter-class&gt;<br />
&lt;/filter&gt;<br />
&lt;!-- ... --&gt;<br />
&lt;filter-mapping&gt;<br />
&lt;filter-name&gt;Reporter&lt;/filter-name&gt;<br />
&lt;servlet-name&gt;PageName&lt;/servlet-name&gt;<br />
&lt;/filter-mapping&gt;<br />
&lt;!-- ... --&gt;<br />
&lt;servlet&gt;<br />
&lt;servlet-name&gt;PageName&lt;/servlet-name&gt;<br />
&lt;jsp-file&gt;/RealPage.jsp&lt;/jsp-file&gt;<br />
&lt;/servlet&gt;<br />
&lt;!-- ... --&gt;<br />
&lt;servlet-mapping&gt;<br />
&lt;servlet-name&gt; PageName &lt;/servlet-name&gt;<br />
&lt;url-pattern&gt;/UrlTest2/*&lt;/url-pattern&gt;<br />
&lt;/servlet-mapping&gt;<br />
&lt;!-- ... --&gt;<br />
&lt;/web-app&gt;<br />
<br />
<br />
7 指定欢迎页<br />
<br />
假如用户提供了一个像http: //host/webAppPrefix/directoryName/ 这样的包含一个目录名但没有包含文件名的URL，会发生什么事情呢？用户能得到一个目录表？一个错误？还是标准文件的内容？如果得到标准文件内容，是 index.html、index.jsp、default.html、default.htm或别的什么东西呢？<br />
Welcome-file-list 元素及其辅助的welcome-file元素解决了这个模糊的问题。例如，下面的web.xml项指出，如果一个URL给出一个目录名但未给出文件名，服务器应该首先试用index.jsp，然后再试用index.html。如果两者都没有找到，则结果有赖于所用的服务器（如一个目录列表）。<br />
&lt;welcome-file-list&gt;<br />
&lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt;<br />
&lt;welcome-file&gt;index.html&lt;/welcome-file&gt;<br />
&lt;/welcome-file-list&gt;<br />
虽然许多服务器缺省遵循这种行为，但不一定必须这样。因此，明确地使用welcom-file-list保证可移植性是一种良好的习惯。<br />
<br />
8 指定处理错误的页面<br />
<br />
现在我了解到，你在开发servlet和JSP页面时从不会犯错误，而且你的所有页面是那样的清晰，一般的程序员都不会被它们的搞糊涂。但是，是人总会犯错误的，用户可能会提供不合规定的参数，使用不正确的URL或者不能提供必需的表单字段值。除此之外，其它开发人员可能不那么细心，他们应该有些工具来克服自己的不足。<br />
error-page元素就是用来克服这些问题的。它有两个可能的子元素，分别是：error-code和exception- type。第一个子元素error-code指出在给定的HTTP错误代码出现时使用的URL。第二个子元素excpetion-type指出在出现某个给定的Java异常但未捕捉到时使用的URL。error-code和exception-type都利用location元素指出相应的URL。此 URL必须以/开始。location所指出的位置处的页面可通过查找HttpServletRequest对象的两个专门的属性来访问关于错误的信息，这两个属性分别是：javax.servlet.error.status_code和javax.servlet.error.message。<br />
可回忆一下，在web.xml内以正确的次序声明web-app的子元素很重要。这里只要记住，error-page出现在web.xml文件的末尾附近，servlet、servlet-name和welcome-file-list之后即可。<br />
<br />
8.1 error-code元素<br />
为了更好地了解error-code元素的值，可考虑一下如果不正确地输入文件名，大多数站点会作出什么反映。这样做一般会出现一个404错误信息，它表示不能找到该文件，但几乎没提供更多有用的信息。另一方面，可以试一下在</font><a href="http://www.microsoft.com/" target="_blank"><font size="2">www.microsoft.com</font></a><font size="2">、</font><a href="http://www.ibm.com/" target="_blank"><font size="2">www.ibm.com</font></a><font size="2"> 处或者特别是在</font><a href="http://www.bea.com/" target="_blank"><font size="2">www.bea.com</font></a><font size="2"> 处输出未知的文件名。这是会得出有用的消息，这些消息提供可选择的位置，以便查找感兴趣的页面。提供这样有用的错误页面对于Web应用来说是很有价值得。事实上rm-error-page子元素）。由form-login-page给出的HTML表单必须具有一个j_security_check的 ACTION属性、一个名为j_username的用户名文本字段以及一个名为j_password的口令字段。<br />
例如，程序清单5-19指示服务器使用基于表单的验证。Web应用的顶层目录中的一个名为login.jsp的页面将收集用户名和口令，并且失败的登陆将由相同目录中名为login-error.jsp的页面报告。<br />
<br />
程序清单5-19 web.xml（说明login-config的摘录）<br />
&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;<br />
&lt;!DOCTYPE web-app<br />
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"<br />
"</font><a href="http://java.sun.com/dtd/web-app_2_3.dtd" target="_blank"><font size="2">http://java.sun.com/dtd/web-app_2_3.dtd</font></a><font size="2">"&gt;<br />
<br />
&lt;web-app&gt;<br />
&lt;!-- ... --&gt;<br />
&lt;security-constraint&gt; ... &lt;/security-constraint&gt;<br />
&lt;login-config&gt;<br />
&lt;auth-method&gt; FORM &lt;/auth-method&gt;<br />
&lt;form-login-config&gt;<br />
&lt;form-login-page&gt;/login.jsp&lt;/form-login-page&gt;<br />
&lt;form-error-page&gt;/login-error.jsp&lt;/form-error-page&gt;<br />
&lt;/form-login-config&gt;<br />
&lt;/login-config&gt;<br />
&lt;!-- ... --&gt;<br />
&lt;/web-app&gt;<br />
<br />
<br />
9.2 限制对Web资源的访问<br />
现在，可以指示服务器使用何种验证方法了。"了不起，"你说道，"除非我能指定一个来收到保护的 URL，否则没有多大用处。"没错。指出这些URL并说明他们应该得到何种保护正是security-constriaint元素的用途。此元素在 web.xml中应该出现在login-config的紧前面。它包含是个可能的子元素，分别是：web-resource-collection、 auth-constraint、user-data-constraint和display-name。下面各小节对它们进行介绍。<br />
l web-resource-collection<br />
此元素确定应该保护的资源。所有security-constraint元素都必须包含至少一个web-resource-collection项。此元素由一个给出任意标识名称的web-resource-name元素、一个确定应该保护的URL的url-pattern元素、一个指出此保护所适用的 HTTP命令（GET、POST等，缺省为所有方法）的http-method元素和一个提供资料的可选description元素组成。例如，下面的 Web-resource-collection项（在security-constratint元素内）指出Web应用的proprietary目录中所有文档应该受到保护。<br />
&lt;security-constraint&gt;<br />
&lt;web-resource-coolection&gt;<br />
&lt;web-resource-name&gt;Proprietary&lt;/web-resource-name&gt;<br />
&lt;url-pattern&gt;/propritary/*&lt;/url-pattern&gt;<br />
&lt;/web-resource-coolection&gt;<br />
&lt;!-- ... --&gt;<br />
&lt;/security-constraint&gt;<br />
重要的是应该注意到，url-pattern仅适用于直接访问这些资源的客户机。特别是，它不适合于通过MVC体系结构利用 RequestDispatcher来访问的页面，或者不适合于利用类似jsp:forward的手段来访问的页面。这种不匀称如果利用得当的话很有好处。例如，servlet可利用MVC体系结构查找数据，把它放到bean中，发送请求到从bean中提取数据的JSP页面并显示它。我们希望保证决不直接访问受保护的JSP页面，而只是通过建立该页面将使用的bean的servlet来访问它。url-pattern和auth-contraint元素可通过声明不允许任何用户直接访问JSP页面来提供这种保证。但是，这种不匀称的行为可能让开发人员放松警惕，使他们偶然对应受保护的资源提供不受限制的访问。 <br />
l auth-constraint<br />
尽管web-resource-collention元素质出了哪些URL应该受到保护，但是auth-constraint元素却指出哪些用户应该具有受保护资源的访问权。此元素应该包含一个或多个标识具有访问权限的用户类别role- name元素，以及包含（可选）一个描述角色的description元素。例如，下面web.xml中的security-constraint元素部门规定只有指定为Administrator或Big Kahuna（或两者）的用户具有指定资源的访问权。<br />
&lt;security-constraint&gt;<br />
&lt;web-resource-coolection&gt; ... &lt;/web-resource-coolection&gt;<br />
&lt;auth-constraint&gt;<br />
&lt;role-name&gt;administrator&lt;/role-name&gt;<br />
&lt;role-name&gt;kahuna&lt;/role-name&gt;<br />
&lt;/auth-constraint&gt;<br />
&lt;/security-constraint&gt;<br />
重要的是认识到，到此为止，这个过程的可移植部分结束了。服务器怎样确定哪些用户处于任何角色以及它怎样存放用户的口令，完全有赖于具体的系统。<br />
例如，Tomcat使用install_dir/conf/tomcat-users.xml将用户名与角色名和口令相关联，正如下面例子中所示，它指出用户joe（口令bigshot）和jane（口令enaj）属于administrator和kahuna角色。<br />
&lt;tomcat-users&gt;<br />
&lt;user name="joe" password="bigshot" roles="administrator,kahuna" /&gt;<br />
&lt;user name="jane" password="enaj" roles="kahuna" /&gt;<br />
&lt;/tomcat-users&gt;<br />
l user-data-constraint<br />
这个可选的元素指出在访问相关资源时使用任何传输层保护。它必须包含一个transport-guarantee子元素（合法值为NONE、 INTEGRAL或CONFIDENTIAL），并且可选地包含一个description元素。transport-guarantee为NONE值将对所用的通讯协议不加限制。INTEGRAL值表示数据必须以一种防止截取它的人阅读它的方式传送。虽然原理上（并且在未来的HTTP版本中），在 INTEGRAL和CONFIDENTIAL之间可能会有差别，但在当前实践中，他们都只是简单地要求用SSL。例如，下面指示服务器只允许对相关资源做 HTTPS连接：<br />
&lt;security-constraint&gt;<br />
&lt;!-- ... --&gt;<br />
&lt;user-data-constraint&gt;<br />
&lt;transport-guarantee&gt;CONFIDENTIAL&lt;/transport-guarantee&gt;<br />
&lt;/user-data-constraint&gt;<br />
&lt;/security-constraint&gt;<br />
l display-name<br />
security-constraint的这个很少使用的子元素给予可能由GUI工具使用的安全约束项一个名称。<br />
9.3 分配角色名<br />
迄今为止，讨论已经集中到完全由容器（服务器）处理的安全问题之上了。但servlet以及JSP页面也能够处理它们自己的安全问题。<br />
例如，容器可能允许用户从bigwig或bigcheese角色访问一个显示主管人员额外紧贴的页面，但只允许bigwig用户修改此页面的参数。完成这种更细致的控制的一种常见方法是调用HttpServletRequset的isUserInRole方法，并据此修改访问。<br />
Servlet的 security-role-ref子元素提供出现在服务器专用口令文件中的安全角色名的一个别名。例如，假如编写了一个调用 request.isUserInRole（"boss"）的servlet，但后来该servlet被用在了一个其口令文件调用角色manager而不是boss的服务器中。下面的程序段使该servlet能够使用这两个名称中的任何一个。<br />
&lt;servlet&gt;<br />
&lt;!-- ... --&gt;<br />
&lt;security-role-ref&gt;<br />
&lt;role-name&gt;boss&lt;/role-name&gt; &lt;!-- New alias --&gt;<br />
&lt;role-link&gt;manager&lt;/role-link&gt; &lt;!-- Real name --&gt;<br />
&lt;/security-role-ref&gt;<br />
&lt;/servlet&gt;<br />
也可以在web-app内利用security-role元素提供将出现在role-name元素中的所有安全角色的一个全局列表。分别地生命角色使高级IDE容易处理安全信息。<br />
<br />
10 控制会话超时<br />
<br />
如果某个会话在一定的时间内未被访问，服务器可把它扔掉以节约内存。可利用HttpSession的setMaxInactiveInterval方法直接设置个别会话对象的超时值。如果不采用这种方法，则缺省的超时值由具体的服务器决定。但可利用session-config和session- timeout元素来给出一个适用于所有服务器的明确的超时值。超时值的单位为分钟，因此，下面的例子设置缺省会话超时值为三个小时（180分钟）。<br />
&lt;session-config&gt;<br />
&lt;session-timeout&gt;180&lt;/session-timeout&gt;<br />
&lt;/session-config&gt;<br />
<br />
11 Web应用的文档化<br />
<br />
越来越多的开发环境开始提供servlet和JSP的直接支持。例子有Borland Jbuilder Enterprise Edition、Macromedia UltraDev、Allaire JRun Studio（写此文时，已被Macromedia收购）以及IBM VisuaAge for Java等。<br />
大量的web.xml元素不仅是为服务器设计的，而且还是为可视开发环境设计的。它们包括icon、display-name和discription等。<br />
可回忆一下，在web.xml内以适当地次序声明web-app子元素很重要。不过，这里只要记住icon、display-name和description是web.xml的web-app元素内的前三个合法元素即可。<br />
l icon<br />
icon元素指出GUI工具可用来代表Web应用的一个和两个图像文件。可利用small-icon元素指定一幅16 x 16的GIF或JPEG图像，用large-icon元素指定一幅32 x 32的图像。下面举一个例子： <br />
&lt;icon&gt;<br />
&lt;small-icon&gt;/images/small-book.gif&lt;/small-icon&gt;<br />
&lt;large-icon&gt;/images/tome.jpg&lt;/large-icon&gt;<br />
&lt;/icon&gt;<br />
l display-name<br />
display-name元素提供GUI工具可能会用来标记此Web应用的一个名称。下面是个例子。<br />
&lt;display-name&gt;Rare Books&lt;/display-name&gt;<br />
l description<br />
description元素提供解释性文本，如下所示：<br />
&lt;description&gt;<br />
This Web application represents the store developed for<br />
rare-books.com, an online bookstore specializing in rare<br />
and limited-edition books.<br />
&lt;/description&gt;<br />
<br />
12 关联文件与MIME类型<br />
<br />
服务器一般都具有一种让Web站点管理员将文件扩展名与媒体相关联的方法。例如，将会自动给予名为mom.jpg的文件一个image/jpeg的MIME 类型。但是，假如你的Web应用具有几个不寻常的文件，你希望保证它们在发送到客户机时分配为某种MIME类型。mime-mapping元素（具有 extension和mime-type子元素）可提供这种保证。例如，下面的代码指示服务器将application/x-fubar的MIME类型分配给所有以.foo结尾的文件。<br />
&lt;mime-mapping&gt;<br />
&lt;extension&gt;foo&lt;/extension&gt;<br />
&lt;mime-type&gt;application/x-fubar&lt;/mime-type&gt;<br />
&lt;/mime-mapping&gt;<br />
或许，你的Web应用希望重载（override）标准的映射。例如，下面的代码将告诉服务器在发送到客户机时指定.ps文件作为纯文本（text/plain）而不是作为PostScript（application/postscript）。<br />
&lt;mime-mapping&gt;<br />
&lt;extension&gt;ps&lt;/extension&gt;<br />
&lt;mime-type&gt;application/postscript&lt;/mime-type&gt;<br />
&lt;/mime-mapping&gt;<br />
<br />
<br />
13 定位TLD<br />
<br />
JSP taglib元素具有一个必要的uri属性，它给出一个TLD（Tag Library Descriptor）文件相对于Web应用的根的位置。TLD文件的实际名称在发布新的标签库版本时可能会改变，但我们希望避免更改所有现有JSP页面。此外，可能还希望使用保持taglib元素的简练性的一个简短的uri。这就是部署描述符文件的taglib元素派用场的所在了。Taglib包含两个子元素：taglib-uri和taglib-location。taglib-uri元素应该与用于JSP taglib元素的uri属性的东西相匹配。Taglib-location元素给出TLD文件的实际位置。例如，假如你将文件chart-tags- 1.3beta.tld放在WebApp/WEB-INF/tlds中。现在，假如web.xml在web-app元素内包含下列内容。<br />
&lt;taglib&gt;<br />
&lt;taglib-uri&gt;/charts.tld&lt;/taglib-uri&gt;<br />
&lt;taglib-location&gt;<br />
/WEB-INF/tlds/chart-tags-1.3beta.tld<br />
&lt;/taglib-location&gt;<br />
&lt;/taglib&gt;<br />
给出这个说明后，JSP页面可通过下面的简化形式使用标签库。<br />
&lt;%@ taglib uri="/charts.tld" prefix="somePrefix" %&gt;<br />
<br />
14 指定应用事件监听程序<br />
<br />
应用事件监听器程序是建立或修改servlet环境或会话对象时通知的类。它们是servlet规范的版本2.3中的新内容。这里只简单地说明用来向Web应用注册一个监听程序的web.xml的用法。<br />
注册一个监听程序涉及在web.xml的web-app元素内放置一个listener元素。在listener元素内，listener-class元素列出监听程序的完整的限定类名，如下所示：<br />
&lt;listener&gt;<br />
&lt;listener-class&gt;package.ListenerClass&lt;/listener-class&gt;<br />
&lt;/listener&gt;<br />
虽然listener元素的结构很简单，但请不要忘记，必须正确地给出web-app元素内的子元素的次序。listener元素位于所有的servlet 元素之前以及所有filter-mapping元素之后。此外，因为应用生存期监听程序是serlvet规范的2.3版本中的新内容，所以必须使用 web.xml DTD的2.3版本，而不是2.2版本。<br />
例如，程序清单5-20给出一个名为ContextReporter的简单的监听程序，只要Web应用的Servlet-Context建立（如装载Web应用）或消除（如服务器关闭）时，它就在标准输出上显示一条消息。程序清单5-21给出此监听程序注册所需要的web.xml文件的一部分。<br />
<br />
程序清单5-20 ContextReporterjava<br />
package moreservlets;<br />
<br />
import javax.servlet.*;<br />
import java.util.*;<br />
<br />
/** Simple listener that prints a report on the standard output <br />
* when the ServletContext is created or destroyed.<br />
* &lt;P&gt;<br />
* Taken from More Servlets and JavaServer Pages<br />
* from Prentice Hall and Sun Microsystems Press,<br />
* </font><a href="http://www.moreservlets.com/." target="_blank"><font size="2">http://www.moreservlets.com/.</font></a><br />
<font size="2">* &#169; 2002 Marty Hall; may be freely used or adapted.<br />
*/<br />
<br />
public class ContextReporter implements ServletContextListener {<br />
public void contextInitialized(ServletContextEvent event) {<br />
System.out.println("Context created on " +<br />
new Date() + ".");<br />
}<br />
<br />
public void contextDestroyed(ServletContextEvent event) {<br />
System.out.println("Context destroyed on " +<br />
new Date() + ".");<br />
}<br />
}<br />
<br />
<br />
程序清单5-21 web.xml（声明一个监听程序的摘录）<br />
&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;<br />
&lt;!DOCTYPE web-app<br />
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"<br />
"</font><a href="http://java.sun.com/dtd/web-app_2_3.dtd" target="_blank"><font size="2">http://java.sun.com/dtd/web-app_2_3.dtd</font></a><font size="2">"&gt;<br />
<br />
&lt;web-app&gt;<br />
&lt;!-- ... --&gt;<br />
&lt;filter-mapping&gt; &#8230; &lt;/filter-mapping&gt;<br />
&lt;listener&gt;<br />
&lt;listener-class&gt;package.ListenerClass&lt;/listener-class&gt;<br />
&lt;/listener&gt;<br />
&lt;servlet&gt; ... &lt;/servlet&gt;<br />
&lt;!-- ... --&gt;<br />
&lt;/web-app&gt;<br />
<br />
<br />
15 J2EE元素<br />
<br />
本节描述用作J2EE环境组成部分的Web应用的web.xml元素。这里将提供一个简明的介绍，详细内容可以参阅</font><a href="http://java.sun.com/j2ee/j2ee-1_3-fr-spec.pdf" target="_blank"><font size="2">http://java.sun.com/j2ee/j2ee-1_3-fr-spec.pdf</font></a><font size="2">的Java 2 Plantform Enterprise Edition版本1.3规范的第5章。<br />
l distributable<br />
distributable 元素指出，Web应用是以这样的方式编程的：即，支持集群的服务器可安全地在多个服务器上分布Web应用。例如，一个可分布的应用必须只使用 Serializable对象作为其HttpSession对象的属性，而且必须避免用实例变量（字段）来实现持续性。distributable元素直接出现在discription元素之后，并且不包含子元素或数据，它只是一个如下的标志。<br />
&lt;distributable /&gt;<br />
l resource-env-ref<br />
resource -env-ref元素声明一个与某个资源有关的管理对象。此元素由一个可选的description元素、一个resource-env-ref- name元素（一个相对于java:comp/env环境的JNDI名）以及一个resource-env-type元素（指定资源类型的完全限定的类），如下所示：<br />
&lt;resource-env-ref&gt;<br />
&lt;resource-env-ref-name&gt;<br />
jms/StockQueue<br />
&lt;/resource-env-ref-name&gt;<br />
&lt;resource-env-ref-type&gt;<br />
javax.jms.Queue<br />
&lt;/resource-env-ref-type&gt;<br />
&lt;/resource-env-ref&gt;<br />
l env-entry<br />
env -entry元素声明Web应用的环境项。它由一个可选的description元素、一个env-entry-name元素（一个相对于java: comp/env环境JNDI名）、一个env-entry-value元素（项值）以及一个env-entry-type元素（java.lang程序包中一个类型的完全限定类名，java.lang.Boolean、java.lang.String等）组成。下面是一个例子：<br />
&lt;env-entry&gt;<br />
&lt;env-entry-name&gt;minAmout&lt;/env-entry-name&gt;<br />
&lt;env-entry-value&gt;100.00&lt;/env-entry-value&gt;<br />
&lt;env-entry-type&gt;minAmout&lt;/env-entry-type&gt;<br />
&lt;/env-entry&gt;<br />
l ejb-ref<br />
ejb -ref元素声明对一个EJB的主目录的应用。它由一个可选的description元素、一个ejb-ref-name元素（相对于java: comp/env的EJB应用）、一个ejb-ref-type元素（bean的类型，Entity或Session）、一个home元素（bean的主目录接口的完全限定名）、一个remote元素（bean的远程接口的完全限定名）以及一个可选的ejb-link元素（当前bean链接的另一个 bean的名称）组成。<br />
l ejb-local-ref<br />
ejb-local-ref元素声明一个EJB的本地主目录的引用。除了用local-home代替home外，此元素具有与ejb-ref元素相同的属性并以相同的方式使用。<br />
<br />
<br />
<br />
<br />
<br />
<br />
17:42 | 固定链接 | 评论 (0) | 引用通告 (0) | 记录它 | 计算机与 Internet <br />
<br />
<br />
固定链接 关闭 <br />
<br />
</font><a href="http://spaces.msn.com/members/tsfy/Blog/cns!1pFtRRZqZXTCdE5YlUjqVIcQ!116.entry" target="_blank"><font size="2">http://spaces.msn.com/members/tsfy/Blog/cns!1pFtRRZqZXTCdE5YlUjqVIcQ!116.entry</font></a><font size="2"> <br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
4月14日 <br />
<br />
<br />
<br />
给你的session加个监听器 <br />
<br />
<br />
今天一个学生问我怎么实现在网页里显示在线用户的名称——他已经使用了session，但是无法处理用户离开的情况，然后导致在线用户列表的无限增大。跟他说了自己在application中进行超时检查，更新application的时候就比较当前所有列表中的session是否超过自己指定的时间间隔。后来想了想，又给他提了使用给session加监听器的方法。但是提的时候自己也没有做过，所以只是说这种方式很复杂，建议他还是自己进行超时检查。刚才又看了看资料，发现实际上给session加监听器的方式很简单，不禁觉得自己有点误人子弟了，现在将方法写在这，借以告诫自己以后要严谨。<br />
首先写一个SessionBinder类,它实现了HttpSessionBindingListener接口的valueBound方法和valueUnbound方法，示例代码如下：<br />
public class SessionBinder implements HttpSessionBindingListener {<br />
&nbsp; public void valueBound(HttpSessionBindingEvent event){<br />
&nbsp; &nbsp; //you can do anything you want!this method will be called when this binder is bind with any session.<br />
&nbsp; }<br />
<br />
&nbsp; public void valueUnbound(HttpSessionBindingEvent event) {<br />
&nbsp; &nbsp; //you can do something while this session is invalidate<br />
&nbsp; }<br />
}<br />
现在写好了SessionBinder，我们现在选择在一个servlet中向session中加入这个监听器——在jsp中的代码书写与此相同<br />
//省略前面的代码，此操作可能发生在servlet的doGet方法中，也可能是doPost方法中<br />
&nbsp; HttpSession session = req.getSession(true);//首先获得需要加入监听器的session对象，req是HttpRequest对象<br />
&nbsp; SessionBinder sb = new SessionBinder();//建立一个监听器对象<br />
&nbsp; session.putValue("BinderObject",sb);//将监听器加入此session中，从此时开始执行sb的valueBound方法<br />
//省略后面的代码<br />
随后，如果整个session超时或者被用户中止之后，sb的valueUnbound自动执行<br />
呵呵，以上代码以供参考</font><br />
<img src ="http://www.blogjava.net/xinwuhen/aggbug/193043.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2008-04-15 11:42 <a href="http://www.blogjava.net/xinwuhen/archive/2008/04/15/193043.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Tomcat启动分析</title><link>http://www.blogjava.net/xinwuhen/archive/2008/04/15/193030.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Tue, 15 Apr 2008 03:14:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2008/04/15/193030.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/193030.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2008/04/15/193030.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/193030.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/193030.html</trackback:ping><description><![CDATA[<h3>1 - Tomcat Server的组成部分 </h3>
<p><strong>1.1 - Server </strong></p>
<p>A Server element represents the entire Catalina servlet container. (Singleton) </p>
<p><strong>1.2 - Service </strong></p>
<p>A Service element represents the combination of one or more Connector components that share a single Engine<br />
Service是这样一个集合：它由一个或者多个Connector组成，以及一个Engine，负责处理所有Connector所获得的客户请求<br />
</p>
<p><strong>1.3 - Connector </strong></p>
<p>一个Connector将在某个指定端口上侦听客户请求，并将获得的请求交给Engine来处理，从Engine处获得回应并返回客户<br />
TOMCAT有两个典型的Connector，一个直接侦听来自browser的http请求，一个侦听来自其它WebServer的请求<br />
Coyote Http/1.1 Connector 在端口8080处侦听来自客户browser的http请求<br />
Coyote JK2 Connector 在端口8009处侦听来自其它WebServer(Apache)的servlet/jsp代理请求<br />
</p>
<p><strong>1.4 - Engine </strong></p>
<p>The Engine element represents the entire request processing machinery associated with a particular Service<br />
It receives and processes all requests from one or more Connectors<br />
and returns the completed response to the Connector for ultimate transmission back to the client<br />
Engine下可以配置多个虚拟主机Virtual Host，每个虚拟主机都有一个域名<br />
当Engine获得一个请求时，它把该请求匹配到某个Host上，然后把该请求交给该Host来处理<br />
Engine有一个默认虚拟主机，当请求无法匹配到任何一个Host上的时候，将交给该默认Host来处理<br />
</p>
<p><strong>1.5 - Host </strong>
<p>
<p>代表一个Virtual Host，虚拟主机，每个虚拟主机和某个网络域名Domain Name相匹配<br />
每个虚拟主机下都可以部署(deploy)一个或者多个Web App，每个Web App对应于一个Context，有一个Context path<br />
当Host获得一个请求时，将把该请求匹配到某个Context上，然后把该请求交给该Context来处理<br />
匹配的方法是&#8220;最长匹配&#8221;，所以一个path==""的Context将成为该Host的默认Context<br />
所有无法和其它Context的路径名匹配的请求都将最终和该默认Context匹配<br />
</p>
<p><strong>1.6 - Context </strong></p>
<p>一个Context对应于一个Web Application，一个Web Application由一个或者多个Servlet组成<br />
Context在创建的时候将根据配置文件$CATALINA_HOME/conf/web.xml和$WEBAPP_HOME/WEB-INF/web.xml载入Servlet类<br />
当Context获得请求时，将在自己的映射表(mapping table)中寻找相匹配的Servlet类<br />
如果找到，则执行该类，获得请求的回应，并返回<br />
</p>
<h3>2 - Tomcat Server的结构图 </h3>
<p><img src="http://docs.huihoo.com/apache/tomcat/heavyz/01-startup.gif" tppabs="http://zooo.51.net/heavyz/cs/tomcat/notes/01-startup.gif"  alt="" /> </p>
<h3>3 - 配置文件$CATALINA_HOME/conf/server.xml的说明 </h3>
<p>该文件描述了如何启动Tomcat Server </p>
<p><tt>
<pre><font color="green">
&lt;!-----------------------------------------------------------------------------------------------&gt;
</font>
<font color="green">
&lt;!-- 启动Server
在端口8005处等待关闭命令
如果接受到"SHUTDOWN"字符串则关闭服务器
--&gt;
</font>
&lt;Server port="8005" shutdown="SHUTDOWN" debug="0"&gt;
<font color="green">
&lt;!-- Listener ???
目前没有看到这里
--&gt;
</font>
&lt;Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" debug="0"/&gt;
&lt;Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" debug="0"/&gt;
<font color="green">
&lt;!-- Global JNDI resources ???
目前没有看到这里，先略去
--&gt;
</font>
&lt;GlobalNamingResources&gt;
... ... ... ...
&lt;/GlobalNamingResources&gt;
<font color="green">
&lt;!-- Tomcat的Standalone Service
Service是一组Connector的集合
它们共用一个Engine来处理所有Connector收到的请求
--&gt;
</font>
&lt;Service name="Tomcat-Standalone"&gt;
<font color="green">
&lt;!-- Coyote HTTP/1.1 Connector
className : 该Connector的实现类是org.apache.coyote.tomcat4.CoyoteConnector
port : 在端口号8080处侦听来自客户browser的HTTP1.1请求
minProcessors : 该Connector先创建5个线程等待客户请求，每个请求由一个线程负责
maxProcessors : 当现有的线程不够服务客户请求时，若线程总数不足75个，则创建新线程来处理请求
acceptCount : 当现有线程已经达到最大数75时，为客户请求排队
当队列中请求数超过100时，后来的请求返回Connection refused错误
redirectport : 当客户请求是https时，把该请求转发到端口8443去
其它属性略
--&gt;
</font>
&lt;Connector className="org.apache.coyote.tomcat4.CoyoteConnector"
port="8080"
minProcessors="5" maxProcessors="75" acceptCount="100"
enableLookups="true"
redirectPort="8443"
debug="0"
connectionTimeout="20000"
useURIValidationHack="false"
disableUploadTimeout="true" /&gt;
<font color="green">
&lt;!-- Engine用来处理Connector收到的Http请求
它将匹配请求和自己的虚拟主机，并把请求转交给对应的Host来处理
默认虚拟主机是localhost
--&gt;
</font>
&lt;Engine name="Standalone" defaultHost="localhost" debug="0"&gt;
<font color="green">
&lt;!-- 日志类，目前没有看到，略去先 --&gt;
</font>
&lt;Logger className="org.apache.catalina.logger.FileLogger" .../&gt;
<font color="green">
&lt;!-- Realm，目前没有看到，略去先 --&gt;
</font>
&lt;Realm className="org.apache.catalina.realm.UserDatabaseRealm" .../&gt;
<font color="green">
&lt;!-- 虚拟主机localhost
appBase : 该虚拟主机的根目录是webapps/
它将匹配请求和自己的Context的路径，并把请求转交给对应的Context来处理
--&gt;
</font>
&lt;Host name="localhost" debug="0" appBase="webapps" unpackWARs="true" autoDeploy="true"&gt;
<font color="green">
&lt;!-- 日志类，目前没有看到，略去先 --&gt;
</font>
&lt;Logger className="org.apache.catalina.logger.FileLogger" .../&gt;
<font color="green">
&lt;!-- Context，对应于一个Web App
path : 该Context的路径名是""，故该Context是该Host的默认Context
docBase : 该Context的根目录是webapps/mycontext/
--&gt;
</font>
&lt;Context path="" docBase="mycontext" debug="0"/&gt;
<font color="green">
&lt;!-- 另外一个Context，路径名是/wsota --&gt;
</font>
&lt;Context path="/wsota" docBase="wsotaProject" debug="0"/&gt;
&lt;/Host&gt;
&lt;/Engine&gt;
&lt;/Service&gt;
&lt;/Server&gt;
<font color="green">
&lt;!-----------------------------------------------------------------------------------------------&gt;
</font>
</pre>
</tt>
<p>&nbsp;</p>
<h3>4 - Context的部署配置文件web.xml的说明 </h3>
<p>一个Context对应于一个Web App，每个Web App是由一个或者多个servlet组成的<br />
当一个Web App被初始化的时候，它将用自己的ClassLoader对象载入&#8220;部署配置文件web.xml&#8221;中定义的每个servlet类<br />
它首先载入在$CATALINA_HOME/conf/web.xml中部署的servlet类<br />
然后载入在自己的Web App根目录下的WEB-INF/web.xml中部署的servlet类<br />
web.xml文件有两部分：servlet类定义和servlet映射定义<br />
每个被载入的servlet类都有一个名字，且被填入该Context的映射表(mapping table)中，和某种URL PATTERN对应<br />
当该Context获得请求时，将查询mapping table，找到被请求的servlet，并执行以获得请求回应<br />
</p>
<p>分析一下所有的Context共享的web.xml文件，在其中定义的servlet被所有的Web App载入<br />
</p>
<p><tt>
<pre><font color="green">
&lt;!-----------------------------------------------------------------------------------------------&gt;
</font>
&lt;web-app&gt;
<font color="green">
&lt;!-- 概述：
该文件是所有的WEB APP共用的部署配置文件，
每当一个WEB APP被DEPLOY，该文件都将先被处理，然后才是WEB APP自己的/WEB-INF/web.xml
--&gt;
</font>
<font color="green">
&lt;!--  +-------------------------+  --&gt;
&lt;!--  |    servlet类定义部分    |  --&gt;
&lt;!--  +-------------------------+  --&gt;
</font>
<font color="green">
&lt;!-- DefaultServlet
当用户的HTTP请求无法匹配任何一个servlet的时候，该servlet被执行
URL PATTERN MAPPING : /
--&gt;
</font>
&lt;servlet&gt;
&lt;servlet-name&gt;default&lt;/servlet-name&gt;
&lt;servlet-class&gt;
org.apache.catalina.servlets.DefaultServlet
&lt;/servlet-class&gt;
&lt;init-param&gt;
&lt;param-name&gt;debug&lt;/param-name&gt;
&lt;param-value&gt;0&lt;/param-value&gt;
&lt;/init-param&gt;
&lt;init-param&gt;
&lt;param-name&gt;listings&lt;/param-name&gt;
&lt;param-value&gt;true&lt;/param-value&gt;
&lt;/init-param&gt;
&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
&lt;/servlet&gt;
<font color="green">
&lt;!-- InvokerServlet
处理一个WEB APP中的匿名servlet
当一个servlet被编写并编译放入/WEB-INF/classes/中，却没有在/WEB-INF/web.xml中定义的时候
该servlet被调用，把匿名servlet映射成/servlet/ClassName的形式
URL PATTERN MAPPING : /servlet/*
--&gt;
</font>
&lt;servlet&gt;
&lt;servlet-name&gt;invoker&lt;/servlet-name&gt;
&lt;servlet-class&gt;
org.apache.catalina.servlets.InvokerServlet
&lt;/servlet-class&gt;
&lt;init-param&gt;
&lt;param-name&gt;debug&lt;/param-name&gt;
&lt;param-value&gt;0&lt;/param-value&gt;
&lt;/init-param&gt;
&lt;load-on-startup&gt;2&lt;/load-on-startup&gt;
&lt;/servlet&gt;
<font color="green">
&lt;!-- JspServlet
当请求的是一个JSP页面的时候（*.jsp）该servlet被调用
它是一个JSP编译器，将请求的JSP页面编译成为servlet再执行
URL PATTERN MAPPING : *.jsp
--&gt;
</font>
&lt;servlet&gt;
&lt;servlet-name&gt;jsp&lt;/servlet-name&gt;
&lt;servlet-class&gt;org.apache.jasper.servlet.JspServlet&lt;/servlet-class&gt;
&lt;init-param&gt;
&lt;param-name&gt;logVerbosityLevel&lt;/param-name&gt;
&lt;param-value&gt;WARNING&lt;/param-value&gt;
&lt;/init-param&gt;
&lt;load-on-startup&gt;3&lt;/load-on-startup&gt;
&lt;/servlet&gt;
<font color="green">
&lt;!--  +---------------------------+  --&gt;
&lt;!--  |    servlet映射定义部分    |  --&gt;
&lt;!--  +---------------------------+  --&gt;
</font>
&lt;servlet-mapping&gt;
&lt;servlet-name&gt;default&lt;/servlet-name&gt;
&lt;url-pattern&gt;/&lt;/url-pattern&gt;
&lt;/servlet-mapping&gt;
&lt;servlet-mapping&gt;
&lt;servlet-name&gt;invoker&lt;/servlet-name&gt;
&lt;url-pattern&gt;/servlet/*&lt;/url-pattern&gt;
&lt;/servlet-mapping&gt;
&lt;servlet-mapping&gt;
&lt;servlet-name&gt;jsp&lt;/servlet-name&gt;
&lt;url-pattern&gt;*.jsp&lt;/url-pattern&gt;
&lt;/servlet-mapping&gt;
<font color="green">
&lt;!--  +------------------------+  --&gt;
&lt;!--  |    其它部分，略去先    |  --&gt;
&lt;!--  +------------------------+  --&gt;
</font>
... ... ... ...
&lt;/web-app&gt;
<font color="green">
&lt;!-----------------------------------------------------------------------------------------------&gt;
</font>
</pre>
</tt>
<p>&nbsp;</p>
<h3>5 - Tomcat Server处理一个http请求的过程 </h3>
<p>假设来自客户的请求为：<br />
http://localhost:8080/wsota/wsota_index.jsp<br />
</p>
<p>1) 请求被发送到本机端口8080，被在那里侦听的Coyote HTTP/1.1 Connector获得<br />
2) Connector把该请求交给它所在的Service的Engine来处理，并等待来自Engine的回应<br />
3) Engine获得请求localhost/wsota/wsota_index.jsp，匹配它所拥有的所有虚拟主机Host<br />
4) Engine匹配到名为localhost的Host（即使匹配不到也把请求交给该Host处理，因为该Host被定义为该Engine的默认主机）<br />
5) localhost Host获得请求/wsota/wsota_index.jsp，匹配它所拥有的所有Context<br />
6) Host匹配到路径为/wsota的Context（如果匹配不到就把该请求交给路径名为""的Context去处理）<br />
7) path="/wsota"的Context获得请求/wsota_index.jsp，在它的mapping table中寻找对应的servlet<br />
8) Context匹配到URL PATTERN为*.jsp的servlet，对应于JspServlet类<br />
9) 构造HttpServletRequest对象和HttpServletResponse对象，作为参数调用JspServlet的doGet或doPost方法<br />
10)Context把执行完了之后的HttpServletResponse对象返回给Host<br />
11)Host把HttpServletResponse对象返回给Engine<br />
12)Engine把HttpServletResponse对象返回给Connector<br />
13)Connector把HttpServletResponse对象返回给客户browser<br />
</p>
<img src ="http://www.blogjava.net/xinwuhen/aggbug/193030.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2008-04-15 11:14 <a href="http://www.blogjava.net/xinwuhen/archive/2008/04/15/193030.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出hibernate之PO,VO,load,get</title><link>http://www.blogjava.net/xinwuhen/archive/2008/04/09/191666.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Wed, 09 Apr 2008 04:58:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2008/04/09/191666.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/191666.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2008/04/09/191666.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/191666.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/191666.html</trackback:ping><description><![CDATA[<p>今天老师重新详细讲解了hibernate 里的POVO.</p>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最开始理解的POVO,感觉就是通过SAVE()方法,将OBJ&nbsp;持久化到数据库<font color="#ffcc99">.</font><font color="#333399">如果要UPDATE,只要将oBJ 里属性SET一个新值,然后执行下UPDATE就好</font>(<font color="#ff6600">这是种错误的概念</font>),因为那时还没怎么接触POVO,一开始看到这个已经感到很强大了,马上就在脑子中记住了POVO.</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 本以为在项目中可以得心应手的利用这个好处,结果错误的理解让我出了很多异常:</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#ff0000">a different object with the same identifier value was already associated with the session;</font></div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 上面就是其中一个,原因是对于POVO的理解错误,引起的,先看下面的一段代码:</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;Cat princess = new Cat();//新建一个Cat对象<br />
&nbsp;&nbsp;princess.setId("402881830c2cf0f3010c2cf0f8b40001");//将对象set一个数据库中已存在的ＩＤ<br />
&nbsp;&nbsp;princess.setName("Princess");<br />
&nbsp;&nbsp;princess.setSex('F');<br />
&nbsp;&nbsp;princess.setWeight(18.8f);<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;Cat princess2 = new Cat();//又新建一个Cat对象<br />
&nbsp;&nbsp;princess2.setId("402881830c2cf0f3010c2cf0f8b40001");//同时将这个对象也set相同的ＩＤ<br />
&nbsp;&nbsp;princess2.setName("Princess");<br />
&nbsp;&nbsp;princess2.setSex('F');<br />
&nbsp;&nbsp;princess2.setWeight(19.8f);<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;Session session = HibernateSessionFactory.currentSession();//好戏出场了，我们先current a Session<br />
&nbsp;&nbsp;Transaction tx = session.beginTransaction();//开始事物(Transaction到底是什么也不太懂，我只知道它可以将缓存中数据写入数据库)</div>
<div>//&nbsp;&nbsp;Cat c = (Cat)session.load(Cat.class, "402881830c2cf0f3010c2cf0f8b40001");<br />
//&nbsp;&nbsp;c.setWeight(20.3f);<br />
&nbsp;&nbsp;session.saveOrUpdate(princess);//此时我们用session保存了princess，这之后的princess应该是持久化了，成了ＰＯ<br />
&nbsp;&nbsp;session.saveOrUpdate(princess2);//如果按我一开始的理解，此时princess2应该也是可以持久化的（看上面兰色部分），因为princess2只是将princess更新了而已（<font color="#ff0000">这是致命的错误</font>）．<br />
&nbsp;&nbsp;tx.commit();<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;HibernateSessionFactory.closeSession();</div>
<div>　　</div>
<div>　　　执行的结果总是那么讽刺，&nbsp;<font color="#ff0000">a different object with the same identifier value was already associated with the session</font></div>
<div><font color="#ff0000">　　　</font>遇到了问题，总是最让人兴奋与无奈的时候．还是来看看为什么出错吧：</div>
<div>　　首先来讲讲ＰＯＶＯ，ＰＯ又名persistence　object，持久化对象，是指在对象通过save(),update(),load(),get();后，在session的Entity map实体容器里将持久话的对象add进去，也就是说，在我session.saveOrUpdate(princess);时，实体容器里已经将key和对象加入了．因为map是通过不同key来加ＯＢＪ的,而在hibernate里ＩＤ是唯一标识，使用ＩＤ来当做key是最好不过的了．因此Session 的实体容器只能加入一个id的对象．当session.saveOrUpdate(princess2);的时候，session准备把princess2也add到entityMap里时，由于相同的id,也就是key，它就报异常了<font color="#ff0000">a different object with the same identifier ..</font><font color="#333333">恭喜中标．</font></div>
<div>&nbsp;</div>
<div>　　也就是说ＰＯ是在session 的实体容器里可引用的对象，当我要更新ＰＯ时，<font color="#333399">可以set一个属性值，然后只要tx.commit();动作，就可以更新了</font>（让我个人感到非常惊讶的地方）．</div>
<div>　　除了save();之外，同样通过load,update,get也可以获得ＰＯ．不过load和get有一少许区别（在使用的版本3.0中）,get(id)就直接把ＤＯ获得（马上执行select操作），而load则不同，它会先对要load的ＩＤ做个标记，当要使用这个导出的对象时，它再执行.用上面的例子:</div>
<div>&nbsp;</div>
<div>&nbsp;&nbsp; &nbsp;Cat c = (Cat)session.load(Cat.class, "402881830c2cf0f3010c2cf0f8b40001");//此时只是做标记<br />
&nbsp;&nbsp; &nbsp;c.setWeight(20.3f);//这个时候才真正的执行了select 语句．</div>
<img src ="http://www.blogjava.net/xinwuhen/aggbug/191666.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2008-04-09 12:58 <a href="http://www.blogjava.net/xinwuhen/archive/2008/04/09/191666.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java序列化---转载</title><link>http://www.blogjava.net/xinwuhen/archive/2008/03/26/188791.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Wed, 26 Mar 2008 08:45:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2008/03/26/188791.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/188791.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2008/03/26/188791.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/188791.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/188791.html</trackback:ping><description><![CDATA[<h3><strong><u>文件I/O：文件流&#8594;序列化</u></strong></h3>
<br />
★<strong>文件流</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp; 文件操作是最简单最直接也是最容易想到的一种方式，我们说的文件操作不仅仅是通过FileInputStream/FileOutputStream这么&#8220;裸&#8221;的方式直接把数据写入到本地文件（像我以前写的一个扫雷的小游戏JavaMine就是这样保存一局的状态的），这样就比较&#8220;底层&#8221;了。 <br />
<br />
主要类与方法和描述 <br />
<div class="codeStyle">
<ol>
    <li><font color="#ff0000">FileInputStream</font>.read() <em><font color="#339900">//从本地文件读取二进制格式的数据 </font></em>
    <li><font color="#ff0000">FileReader</font>.read() <em><font color="#339900">//从本地文件读取字符（文本）数据 </font></em>
    <li><font color="#ff0000">FileOutputStream</font>.write() <em><font color="#339900">//保存二进制数据到本地文件 </font></em>
    <li><font color="#ff0000">FileWriter</font>.write() <em><font color="#339900">//保存字符数据到本地文件</font></em> </li>
</ol>
</div>
<br />
★<strong>XML</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp; 和上面的单纯的I/O方式相比，XML就显得&#8220;高档&#8221;得多，以至于成为一种数据交换的标准。以<strong>DOM方式</strong>为例，它关心的是首先<strong>在内存中构造文档树</strong>，数据保存在某个结点上（可以是叶子结点，也可以是标签结点的属性），构造好了以后一次性的写入到外部文件，但我们只需要知道文件的位置，并不知道I/O是怎么操作的，XML操作方式可能多数人也实践过，所以这里也只列出相关的方法，供初学者预先了解一下。主要的包是<a class="l2" href="http://java.sun.com/j2se/1.4.2/docs/api/javax/xml/parsers/package-summary.html" target="_blank">javax.xml.parsers</a>，<a class="l2" href="http://java.sun.com/j2se/1.4.2/docs/api/org/w3c/dom/package-summary.html" target="_blank">org.w3c.dom</a>，<a class="l2" href="http://java.sun.com/j2se/1.4.2/docs/api/javax/xml/transform/package-summary.html" target="_blank">javax.xml.transform</a>。 <br />
<br />
主要类与方法和描述 <br />
<div class="codeStyle">
<ol>
    <li><font color="#ff0000">DocumentBuilderFactory</font>.newDocumentBuilder().parse() <em><font color="#339900">//解析一个外部的XML文件，得到一个Document对象的DOM树 </font></em>
    <li><font color="#ff0000">DocumentBuilderFactory</font>.newInstance().newDocumentBuilder().newDocument() <em><font color="#339900">//初始化一棵DOM树 </font></em>
    <li><font color="#ff0000">Document</font>.getDocumentElement().appendChild() <em><font color="#339900">//为一个标签结点添加一个子结点 </font></em>
    <li><font color="#ff0000">Document</font>.createTextNode() <em><font color="#339900">//生成一个字符串结点 </font></em>
    <li><font color="#ff0000">Node</font>.getChildNodes() <em><font color="#339900">//取得某个结点的所有下一层子结点 </font></em>
    <li><font color="#ff0000">Node</font>.removeChild()&nbsp;&nbsp;<em><font color="#339900">//删除某个结点的子结点 </font></em>
    <li><font color="#ff0000">Document</font>.getElementsByTagName() 查找所有指定名称的标签结点&nbsp;&nbsp;
    <li><font color="#ff0000">Document</font>.getElementById() <em><font color="#339900">//查找指定名称的一个标签结点，如果有多个符合，则返回某一个，通常是第一个 </font></em>
    <li><font color="#ff0000">Element</font>.getAttribute() <em><font color="#339900">//取得一个标签的某个属性的的值 </font></em>
    <li><font color="#ff0000">Element</font>.setAttribute() <em><font color="#339900">//设置一个标签的某个属性的的值 </font></em>
    <li><font color="#ff0000">Element</font>.removeAttribute() <em><font color="#339900">//删除一个标签的某个属性 </font></em>
    <li><font color="#ff0000">TransformerFactory</font>.newInstance().newTransformer().transform() <em><font color="#339900">//将一棵DOM树写入到外部XML文件</font></em> </li>
</ol>
</div>
<br />
★<strong>序列化</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp; 使用基本的文件读写方式存取数据，如果我们仅仅保存<strong>相同类型</strong>的数据，则可以用同一种格式保存，譬如在我的JavaMine中保存一个盘局时，需要保存每一个方格的坐标、是否有地雷，是否被翻开等，这些信息组合成一个&#8220;复合类型&#8221;；相反，如果有多种<strong>不同类型</strong>的数据，那我们要么把它分解成若干部分，以相同类型（譬如String）保存，要么我们需要在程序中添加解析不同类型数据格式的逻辑，这就很不方便。于是我们期望用一种比较&#8220;高&#8221;的层次上处理数据，程序员应该<strong>花尽可能少的时间和代码对数据进行解析</strong>，事实上，序列化操作为我们提供了这样一条途径。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 序列化（Serialization）大家可能都有所接触，它可以把对象以某种特定的编码格式写入或从外部字节流（即<a class="l2" href="http://java.sun.com/j2se/1.4.2/docs/api/java/io/ObjectInputStream.html" target="_blank">ObjectInputStream</a>/<a class="l2" href="http://java.sun.com/j2se/1.4.2/docs/api/java/io/ObjectOutputStream.html" target="_blank">ObjectOutputStream</a>）中读取。序列化一个对象非常之简单，仅仅实现一下Serializable接口即可，甚至都不用为它专门添加任何方法： <br />
<div class="codeStyle">
<ol>
    <li><strong><font color="#0000ff">public</font></strong> <strong><font color="#0000ff">class</font></strong> MySerial <strong><font color="#0000ff">implements</font></strong> java.io.<strong><a href="http://www.javaresearch.org/source/jdk142/java/io/Serializable.java.html" target="_blank"><font class="classLink"><u>Serializable</u></font></a></strong>
    <li>{
    <li>&nbsp;&nbsp;<em><font color="#339900">//...</font></em>
    <li>} </li>
</ol>
</div>
<br />
但有一个条件：即<strong>你要序列化的类当中，它的每个属性都必须是是&#8220;可序列化&#8221;的</strong>。这句话说起来有点拗口，其实所有<strong>基本类型</strong>（就是int，char，boolean之类的）<strong>都是&#8220;可序列化&#8221;的</strong>，而你可以看看JDK文档，会发现很多类其实已经实现了Serializable（即已经是&#8220;可序列化&#8221;的了），于是这些类的对象以及基本数据类型都可以直接作为你需要序列化的那个类的内部属性。如果碰到了不是&#8220;可序列化&#8221;的属性怎么办？对不起，那这个属性的类还需要事先实现Serializable接口，如此递归，<strong>直到所有属性都是&#8220;可序列化&#8221;的</strong>。 <br />
<br />
主要类与方法和描述 <br />
<div class="codeStyle">
<ol>
    <li><font color="#ff0000">ObjectOutputStream</font>.writeObject() <em><font color="#339900">//将一个对象序列化到外部字节流 </font></em>
    <li><font color="#ff0000">ObjectInputStream</font>.readObject() <em><font color="#339900">//从外部字节流读取并重新构造对象</font></em> </li>
</ol>
</div>
<br />
&nbsp;&nbsp;&nbsp;&nbsp; 从实际应用上看来，&#8220;Serializable&#8221;这个接口并没有定义任何方法，仿佛它只是一个标记（或者说像是Java的关键字）而已，一旦虚拟机看到这个&#8220;<strong>标记</strong>&#8221;，就会尝试调用自身<strong>预定义的序列化机制</strong>，除非你在实现Serializable接口的同时还定义了私有的readObject()或writeObject()方法。这一点很奇怪。不过你要是不愿意让系统使用缺省的方式进行序列化，那就必须定义上面提到的两个方法： <br />
<div class="codeStyle">
<ol>
    <li><strong><font color="#0000ff">public</font></strong> <strong><font color="#0000ff">class</font></strong> MySerial <strong><font color="#0000ff">implements</font></strong> java.io.<strong><a href="http://www.javaresearch.org/source/jdk142/java/io/Serializable.java.html" target="_blank"><font class="classLink"><u>Serializable</u></font></a></strong>
    <li>{
    <li>&nbsp;&nbsp;<strong><font color="#0000ff">private</font></strong> <strong><font color="#0000ff">void</font></strong> writeObject(java.io.<strong><a href="http://www.javaresearch.org/source/jdk142/java/io/ObjectOutputStream.java.html" target="_blank"><font class="classLink"><u>ObjectOutputStream</u></font></a></strong> out) <strong><font color="#0000ff">throws</font></strong> <font color="#ff0000">IOException</font>
    <li>&nbsp;&nbsp; {
    <li>&nbsp;&nbsp;&nbsp;&nbsp;<em><font color="#339900">//...</font></em>
    <li>&nbsp;&nbsp; }
    <li>&nbsp;&nbsp;<strong><font color="#0000ff">private</font></strong> <strong><font color="#0000ff">void</font></strong> readObject(java.io.<strong><a href="http://www.javaresearch.org/source/jdk142/java/io/ObjectInputStream.java.html" target="_blank"><font class="classLink"><u>ObjectInputStream</u></font></a></strong> in) <strong><font color="#0000ff">throws</font></strong> <font color="#ff0000">IOException</font>, <strong><a href="http://www.javaresearch.org/source/jdk142/java/lang/ClassNotFoundException.java.html" target="_blank"><font class="classLink"><u>ClassNotFoundException</u></font></a></strong>
    <li>&nbsp;&nbsp; {
    <li>&nbsp;&nbsp;&nbsp;&nbsp;<em><font color="#339900">//...</font></em>
    <li>&nbsp;&nbsp; }
    <li>&nbsp;&nbsp;<em><font color="#339900">//...</font></em>
    <li>}&nbsp;&nbsp; </li>
</ol>
</div>
<br />
&nbsp;&nbsp;&nbsp;&nbsp; 譬如你可以在上面的writeObject()里调用默认的序列化方法ObjectOutputStream.<a class="l2" href="http://java.sun.com/j2se/1.4.2/docs/api/java/io/ObjectOutputStream.html#defaultWriteObject()" target="_blank">defaultWriteObject</a>();譬如你不愿意将某些敏感的属性和信息序列化，你也可以调用ObjectOutputStream.writeObject()方法明确指定需要序列化那些属性。关于用户可定制的序列化方法，我们将在后面提到。 <br />
<br />
★<strong>Bean</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp; 上面的序列化只是一种基本应用，你把一个对象序列化到外部文件以后，用notepad打开那个文件，只能从为数不多的一些可读字符中猜到这是有关这个类的信息文件，这需要你熟悉序列化文件的字节编码方式，那将是比较痛苦的（在<a class="l2" href="http://www.china-pub.com/computers/common/info.asp?id=14354" target="_blank">《Core Java 2》第一卷</a>里提到了相关编码方式，有兴趣的话可以查看参考资料），某些情况下我们可能需要被序列化的文件具有更好的可读性。另一方面，作为Java组件的核心概念&#8220;<a class="l2" href="http://java.sun.com/j2se/1.4.2/docs/guide/beans/index.html" target="_blank">JavaBeans</a>&#8221;，从JDK 1.4开始，其规范里也要求支持文本方式的&#8220;<strong>长期的持久化</strong>&#8221;（long-term persistence）。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 打开<a class="l2" href="http://java.sun.com/j2se/1.4.2/docs/api/index.html" target="_blank">JDK文档</a>，<a class="l2" href="http://java.sun.com/j2se/1.4.2/docs/api/java/beans/package-summary.html" target="_blank">java.beans包</a>里的有一个名为&#8220;<a class="l2" href="http://java.sun.com/j2se/1.4.2/docs/api/java/beans/Encoder.html" target="_blank">Encoder</a>&#8221;的类，这就是一个可以序列化bean的实用类。和它相关的两个主要类有<a class="l2" href="http://java.sun.com/j2se/1.4.2/docs/api/java/beans/XMLEncoder.html" target="_blank">XMLEcoder</a>和<a class="l2" href="http://java.sun.com/j2se/1.4.2/docs/api/java/beans/XMLDecoder.html" target="_blank">XMLDecoder</a>，显然，这是以XML文件的格式保存和读取bean的工具。他们的用法也很简单，和上面ObjectOutputStream/ObjectInputStream比较类似。 <br />
<br />
主要类与方法和描述 <br />
<div class="codeStyle">
<ol>
    <li><font color="#ff0000">XMLEncoder</font>.writeObject() <em><font color="#339900">//将一个对象序列化到外部字节流 </font></em>
    <li><font color="#ff0000">XMLDecoder</font>.readObject() <em><font color="#339900">//从外部字节流读取并重新构造对象 </font></em></li>
</ol>
</div>
<br />
&nbsp;&nbsp;&nbsp;&nbsp; 如果一个bean是如下格式：<br />
<div class="codeStyle">
<ol>
    <li><strong><font color="#0000ff">public</font></strong> <strong><font color="#0000ff">class</font></strong> MyBean
    <li>{
    <li>&nbsp;&nbsp;<strong><font color="#0000ff">int</font></strong> i;
    <li>&nbsp;&nbsp;<strong><font color="#0000ff">char</font></strong>[] c;
    <li>&nbsp;&nbsp;<strong><a href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></strong> s;
    <li>&nbsp;&nbsp;<em><font color="#339900">//...(get和set操作省略)...</font></em>
    <li>}&nbsp;&nbsp; </li>
</ol>
</div>
<br />
那么通过XMLEcoder序列化出来的XML文件具有这样的形式： <br />
<br />
&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />
&lt;java version="1.4.0" class="java.beans.XMLDecoder"&gt;<br />
&nbsp;&nbsp; &lt;object class="MyBean"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;void property="i"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;int&gt;1&lt;/int&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;/void&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;void property="c"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;array class="char" length="3"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;void index="0"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;int&gt;a&lt;/int&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/void&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;void index="1"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;int&gt;b&lt;/int&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/void&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;void index="2"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;int&gt;c&lt;/int&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/void&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/array&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;/void&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;void property="s"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;string&gt;fox jump!&lt;/string&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;/void&gt;<br />
&nbsp;&nbsp; &lt;/object&gt;<br />
&lt;/java&gt; <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; 像<a class="l2" href="http://java.sun.com/j2se/1.4.2/docs/guide/awt/index.html" target="_blank">AWT</a>和<a class="l2" href="http://java.sun.com/j2se/1.4.2/docs/guide/swing/index.html" target="_blank">Swing</a>中很多可视化组件都是bean，当然也是可以用这种方式序列化的，下面就是从JDK文档中摘录的一个<a class="l2" href="http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/JFrame.html" target="_blank">JFrame</a>序列化以后的XML文件： <br />
<br />
&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />
&lt;java version="1.0" class="java.beans.XMLDecoder"&gt;<br />
&nbsp;&nbsp; &lt;object class="javax.swing.JFrame"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;void property="name"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;string&gt;frame1&lt;/string&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;/void&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;void property="bounds"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;object class="java.awt.Rectangle"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;int&gt;0&lt;/int&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;int&gt;0&lt;/int&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;int&gt;200&lt;/int&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;int&gt;200&lt;/int&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/object&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;/void&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;void property="contentPane"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;void method="add"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;object class="javax.swing.JButton"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;void property="label"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;string&gt;Hello&lt;/string&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/void&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/object&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/void&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;/void&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;void property="visible"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;boolean&gt;true&lt;/boolean&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;/void&gt;<br />
&nbsp;&nbsp; &lt;/object&gt;<br />
&lt;/java&gt; <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; 因此但你想要保存的数据是一些不是太复杂的类型的话，把它做成bean再序列化也不失为一种方便的选择。 <br />
<br />
★<strong>Properties</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp; 在以前我总结的一篇关于集合框架的小文章里提到过，<a class="l2" href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/Properties.html" target="_blank">Properties</a>是历史集合类的一个典型的例子，这里主要不是介绍它的集合特性。大家可能都经常接触一些<strong>配置文件</strong>，如Windows的ini文件，Apache的conf文件，还有Java里的properties文件等，这些文件当中的数据以<strong>&#8220;关键字-值&#8221;对</strong>的方式保存。&#8220;<strong>环境变量</strong>&#8221;这个概念都知道吧，它也是一种&#8220;key-value&#8221;对，以前也常常看到版上问&#8220;如何取得系统某某信息&#8221;之类的问题，其实很多都保存在环境变量里，只要用一条<br />
<div class="codeStyle">
<ol>
    <li><strong><a href="http://www.javaresearch.org/source/jdk142/java/lang/System.java.html" target="_blank"><font class="classLink"><u>System</u></font></a></strong>.getProperties().list(<strong><a href="http://www.javaresearch.org/source/jdk142/java/lang/System.java.html" target="_blank"><font class="classLink"><u>System</u></font></a></strong>.out);&nbsp;&nbsp; </li>
</ol>
</div>
<br />
就能获得全部环境变量的列表： <br />
<br />
-- listing properties --<br />
java.runtime.name=Java(TM) 2 Runtime Environment, Stand...<br />
sun.boot.library.path=C:\Program Files\Java\j2re1.4.2_05\bin<br />
java.vm.version=1.4.2_05-b04<br />
java.vm.vendor=Sun Microsystems Inc.<br />
java.vendor.url=http://java.sun.com/<br />
path.separator=;<br />
java.vm.name=Java HotSpot(TM) Client VM<br />
file.encoding.pkg=sun.io<br />
user.country=CN<br />
sun.os.patch.level=Service Pack 1<br />
java.vm.specification.name=Java Virtual Machine Specification<br />
user.dir=d:\my documents\项目\eclipse\SWTDemo<br />
java.runtime.version=1.4.2_05-b04<br />
java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment<br />
java.endorsed.dirs=C:\Program Files\Java\j2re1.4.2_05\li...<br />
os.arch=x86<br />
java.io.tmpdir=C:\DOCUME~1\cn2lx0q0\LOCALS~1\Temp\<br />
line.separator=<br />
<br />
java.vm.specification.vendor=Sun Microsystems Inc.<br />
user.variant=<br />
os.name=Windows XP<br />
sun.java2d.fontpath=<br />
java.library.path=C:\Program Files\Java\j2re1.4.2_05\bi...<br />
java.specification.name=Java Platform API Specification<br />
java.class.version=48.0<br />
java.util.prefs.PreferencesFactory=java.util.prefs.WindowsPreferencesFac...<br />
os.version=5.1<br />
user.home=D:\Users\cn2lx0q0<br />
user.timezone=<br />
java.awt.printerjob=sun.awt.windows.WPrinterJob<br />
file.encoding=GBK<br />
java.specification.version=1.4<br />
user.name=cn2lx0q0<br />
java.class.path=d:\my documents\项目\eclipse\SWTDemo\bi...<br />
java.vm.specification.version=1.0<br />
sun.arch.data.model=32<br />
java.home=C:\Program Files\Java\j2re1.4.2_05<br />
java.specification.vendor=Sun Microsystems Inc.<br />
user.language=zh<br />
awt.toolkit=sun.awt.windows.WToolkit<br />
java.vm.info=mixed mode<br />
java.version=1.4.2_05<br />
java.ext.dirs=C:\Program Files\Java\j2re1.4.2_05\li...<br />
sun.boot.class.path=C:\Program Files\Java\j2re1.4.2_05\li...<br />
java.vendor=Sun Microsystems Inc.<br />
file.separator=\<br />
java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport...<br />
sun.cpu.endian=little<br />
sun.io.unicode.encoding=UnicodeLittle<br />
sun.cpu.isalist=pentium i486 i386<br />
<br />
<br />
主要类与方法和描述 <br />
<div class="codeStyle">
<ol>
    <li>load() <em><font color="#339900">//从一个外部流读取属性 </font></em>
    <li>store() <em><font color="#339900">//将属性保存到外部流（特别是文件） </font></em>
    <li>getProperty() <em><font color="#339900">//取得一个指定的属性 </font></em>
    <li>setProperty() <em><font color="#339900">//设置一个指定的属性 </font></em>
    <li>list() <em><font color="#339900">//列出这个Properties对象包含的全部&#8220;key-value&#8221;对 </font></em>
    <li><strong><a href="http://www.javaresearch.org/source/jdk142/java/lang/System.java.html" target="_blank"><font class="classLink"><u>System</u></font></a></strong>.getProperties() <em><font color="#339900">//取得系统当前的环境变量 </font></em></li>
</ol>
</div>
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; 你可以这样保存一个properties文件： <br />
<br />
<div class="codeStyle">
<ol>
    <li><font color="#ff0000">Properties</font> prop = <strong><font color="#0000ff">new</font></strong> <font color="#ff0000">Properties</font>();
    <li>prop.setProperty(<font color="#ff33ff">"key1"</font>, <font color="#ff33ff">"value1"</font>);
    <li>...
    <li><font color="#ff0000">FileOutputStream</font> out = <strong><font color="#0000ff">new</font></strong> <font color="#ff0000">FileOutputStream</font>(<font color="#ff33ff">"config.properties"</font>);
    <li>prop.store(out, <font color="#ff33ff">"--这里是文件头，可以加入注释--"</font>);&nbsp;&nbsp; </li>
</ol>
</div>
<br />
★<strong>Preferences</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp; 如果我说Java里面可以不使用JNI的手段操作Windows的注册表你信不信？很多软件的菜单里都有&#8220;Setting&#8221;或&#8220;Preferences&#8221;这样的选项用来设定或修改软件的配置，这些配置信息可以保存到一个像上面所述的配置文件当中，如果是Windows平台下，也可能会保存到系统注册表中。从JDK 1.4开始，Java在<a class="l2" href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/package-summary.html" target="_blank">java.util</a>下加入了一个专门处理用户和系统配置信息的<a class="l2" href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/prefs/package-summary.html" target="_blank">java.util.prefs</a>包，其中一个类<a class="l2" href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/prefs/Preferences.html" target="_blank">Preferences</a>是一种比较&#8220;高级&#8221;的玩意。从本质上讲，Preferences本身是一个与平台无关的东西，但不同的OS对它的SPI（Service Provider Interface）的实现却是与平台相关的，因此，在不同的系统中你可能看到首选项保存为本地文件、LDAP目录项、数据库条目等，像在Windows平台下，它就保存到了系统注册表中。不仅如此，你还可以把首选项导出为XML文件或从XML文件导入。 <br />
<br />
主要类与方法和描述 <br />
<div class="codeStyle">
<ol>
    <li>systemNodeForPackage() <em><font color="#339900">//根据指定的Class对象得到一个Preferences对象，这个对象的注册表路径是从&#8220;HKEY_LOCAL_MACHINE\&#8221;开始的 </font></em>
    <li>systemRoot() <em><font color="#339900">//得到以注册表路径HKEY_LOCAL_MACHINE\SOFTWARE\Javasoft\Prefs 为根结点的Preferences对象 </font></em>
    <li>userNodeForPackage() <em><font color="#339900">//根据指定的Class对象得到一个Preferences对象，这个对象的注册表路径是从&#8220;HKEY_CURRENT_USER\&#8221;开始的 </font></em>
    <li>userRoot() <em><font color="#339900">//得到以注册表路径HKEY_CURRENT_USER\SOFTWARE\Javasoft\Prefs 为根结点的Preferences对象 </font></em>
    <li>putXXX() <em><font color="#339900">//设置一个属性的值，这里XXX可以为基本数值型类型，如int、long等，但首字母大写，表示参数为相应的类型，也可以不写而直接用put，参数则为字符串 </font></em>
    <li>getXXX() <em><font color="#339900">//得到一个属性的值 </font></em>
    <li>exportNode() <em><font color="#339900">//将全部首选项导出为一个XML文件 </font></em>
    <li>exportSubtree() <em><font color="#339900">//将部分首选项导出为一个XML文件 </font></em>
    <li>importPreferences() <em><font color="#339900">//从XML文件导入首选项 </font></em></li>
</ol>
</div>
<br />
&nbsp;&nbsp;&nbsp;&nbsp; 你可以按如下步骤保存数据：<br />
<div class="codeStyle">
<ol>
    <li><font color="#ff0000">Preferences</font> myPrefs1 = <font color="#ff0000">Preferences</font>.userNodeForPackage(<strong><font color="#0000ff">this</font></strong>);<em><font color="#339900">// 这种方法是在&#8220;HKEY_CURRENT_USER\&#8221;下按当前类的路径建立一个注册表项</font></em>
    <li><font color="#ff0000">Preferences</font> myPrefs2 = <font color="#ff0000">Preferences</font>.systemNodeForPackage(<strong><font color="#0000ff">this</font></strong>);<em><font color="#339900">// 这种方法是在&#8220;HKEY_LOCAL_MACHINE\&#8221;下按当前类的路径建立一个注册表项</font></em>
    <li><font color="#ff0000">Preferences</font> myPrefs3 = <font color="#ff0000">Preferences</font>.userRoot().node(<font color="#ff33ff">"com.jungleford.demo"</font>);<em><font color="#339900">// 这种方法是在&#8220;HKEY_CURRENT_USER\SOFTWARE\Javasoft\Prefs\&#8221;下按&#8220;com\jungleford\demo&#8221;的路径建立一个注册表项</font></em>
    <li><font color="#ff0000">Preferences</font> myPrefs4 = <font color="#ff0000">Preferences</font>.systemRoot().node(<font color="#ff33ff">"com.jungleford.demo"</font>);<em><font color="#339900">// 这种方法是在&#8220;HKEY_LOCAL_MACHINE\SOFTWARE\Javasoft\Prefs\&#8221;下按&#8220;com\jungleford\demo&#8221;的路径建立一个注册表项</font></em>
    <li>myPrefs1.putInt(<font color="#ff33ff">"key1"</font>, 10);
    <li>myPrefs1.putDouble(<font color="#ff33ff">"key2"</font>, -7.15);
    <li>myPrefs1.put(<font color="#ff33ff">"key3"</font>, <font color="#ff33ff">"value3"</font>);
    <li><font color="#ff0000">FileOutputStream</font> out = <strong><font color="#0000ff">new</font></strong> <font color="#ff0000">FileOutputStream</font>(<font color="#ff33ff">"prefs.xml"</font>);
    <li>myPrefs1.exportNode(out); </li>
</ol>
</div>
<br />
<h3><strong><u>网络I/O：Socket&#8594;RMI</u></strong></h3>
<br />
★<strong>Socket</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp; Socket编程可能大家都很熟，所以就不多讨论了，只是说通过socket把数据保存到远端服务器或从网络socket读取数据也不失为一种值得考虑的方式。<br />
<br />
★<strong>RMI</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp; RMI机制其实就是RPC（远程过程调用）的Java版本，它使用socket作为基本传输手段，同时也是序列化最重要的一个应用。现在网络传输从编程的角度来看基本上都是<strong>以流的方式</strong>操作，socket就是一个例子，将对象转换成字节流的一个重要目标就是为了方便网络传输。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 想象一下传统的<strong>单机环境</strong>下的程序设计，对于Java语言的函数（方法）调用（注意与C语言函数调用的区别）的参数传递，会有两种情况：如果是<strong>基本数据类型</strong>，这种情况下和C语言是一样的，采用<strong>值传递</strong>方式；如果是<strong>对象</strong>，则传递的是对象的<strong>引用</strong>，包括返回值也是引用，而不是一个完整的对象拷贝！试想一下在<strong>不同的虚拟机</strong>之间进行方法调用，即使是两个完全同名同类型的对象他们也很可能是不同的引用！此外对于方法调用过程，由于被调用过程的压栈，内存&#8220;现场&#8221;完全被被调用者占有，当被调用方法返回时，才将调用者的地址写回到程序计数器（PC），恢复调用者的状态，如果是两个虚拟机，根本不可能用简单压栈的方式来保存调用者的状态。因为种种原因，我们才需要建立RMI通信实体之间的&#8220;代理&#8221;对象，譬如&#8220;存根&#8221;就相当于远程服务器对象在客户机上的代理，stub就是这么来的，当然这是后话了。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 本地对象与远程对象（未必是物理位置上的不同机器，只要不是在同一个虚拟机内皆为&#8220;远程&#8221;）之间传递参数和返回值，可能有这么几种情形：<br />
<ul>
    <li>值传递：这又包括两种子情形：如果是基本数据类型，那么都是&#8220;可序列化&#8221;的，统统序列化成可传输的字节流；如果是对象，而且不是&#8220;远程对象&#8221;（所谓&#8220;远程对象&#8221;是实现了java.rmi.Remote接口的对象），本来对象传递的应该是引用，但由于上述原因，引用是不足以证明对象身份的，所以传递的仍然是<strong>一个序列化的拷贝</strong>（当然这个对象也必须满足上述&#8220;可序列化&#8221;的条件）。 <br />
    <li>引用传递：可以引用传递的只能是&#8220;远程对象&#8221;。这里所谓的&#8220;引用&#8221;不要理解成了真的只是一个符号，它其实是一个留在（客户机）本地stub中的，和远端服务器上那个真实的对象张得一模一样的<strong>镜像</strong>而已！只是因为它有点&#8220;特权&#8221;（不需要经过序列化），在本地内存里已经有了一个实例，真正引用的其实是这个&#8220;孪生子&#8221;。 </li>
</ul>
<br />
&nbsp;&nbsp;&nbsp;&nbsp; 由此可见，序列化在RMI当中占有多么重要的地位。<br />
<h3><strong><u>数据库I/O：CMP、Hibernate</u></strong></h3>
<br />
★<strong>什么是&#8220;Persistence&#8221;</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp; 用过VMWare的朋友大概都知道当一个guest OS正在运行的时候点击&#8220;Suspend&#8221;将虚拟OS挂起，它会把整个虚拟内存的内容保存到磁盘上，譬如你为虚拟OS分配了128M的运行内存，那挂起以后你会在虚拟OS所在的目录下找到一个同样是128M的文件，这就是虚拟OS内存的完整镜像！这种内存的镜像手段其实就是&#8220;Persistence&#8221;（持久化）概念的由来。<br />
<br />
★<strong>CMP和Hibernate</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp; 因为我对J2EE的东西不是太熟悉，随便找了点材料看看，所以担心说的不到位，这次就不作具体总结了，人要学习&#8230;&#8230;真是一件痛苦的事情<img height="20" alt="[cry]" src="http://www.javaresearch.org/faces/9.gif" width="20" border="0" /><br />
<h3><strong><u>序列化再探讨</u></strong></h3>
<br />
&nbsp;&nbsp;&nbsp;&nbsp; 从以上技术的讨论中我们不难体会到，序列化是Java之所以能够出色地实现其鼓吹的两大卖点??分布式（distributed）和跨平台（OS independent）的一个重要基础。TIJ（即&#8220;<a class="l2" href="http://www.mindview.net/Books/TIJ/" target="_blank">Thinking in Java</a>&#8221;）谈到I/O系统时，把序列化称为&#8220;lightweight persistence&#8221;??&#8220;轻量级的持久化&#8221;，这确实很有意思。<br />
<br />
★<strong>为什么叫做&#8220;序列&#8221;化？</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp; 开场白里我说更习惯于把&#8220;Serialization&#8221;称为&#8220;序列化&#8221;而不是&#8220;串行化&#8221;，这是有原因的。介绍这个原因之前先回顾一些计算机基本的知识，我们知道现代计算机的内存空间都是<strong>线性编址</strong>的（什么是&#8220;线性&#8221;知道吧，就是一个元素只有一个唯一的&#8220;前驱&#8221;和唯一的&#8220;后继&#8221;，当然头尾元素是个例外；对于地址来说，它的下一个地址当然不可能有两个，否则就乱套了），&#8220;地址&#8221;这个概念推广到数据结构，就相当于&#8220;指针&#8221;，这个在本科低年级大概就知道了。注意了，既然是线性的，那&#8220;地址&#8221;就可以看作是内存空间的&#8220;序号&#8221;，说明它的组织是有顺序的，&#8220;<strong>序号</strong>&#8221;或者说&#8220;序列号&#8221;正是&#8220;Serialization&#8221;机制的一种体现。为什么这么说呢？譬如我们有两个对象a和b,分别是类A和B的实例，它们都是可序列化的，而A和B都有一个类型为C的属性，根据前面我们说过的原则，C当然也必须是可序列化的。<br />
<div class="codeStyle">
<ol>
    <li><strong><font color="#0000ff">import</font></strong> java.io.*;
    <li>...
    <li><strong><font color="#0000ff">class</font></strong> A <strong><font color="#0000ff">implements</font></strong> <strong><a href="http://www.javaresearch.org/source/jdk142/java/io/Serializable.java.html" target="_blank"><font class="classLink"><u>Serializable</u></font></a></strong>
    <li>{
    <li>&nbsp;&nbsp; C c;
    <li>&nbsp;&nbsp; ...
    <li>}
    <li>
    <li><strong><font color="#0000ff">class</font></strong> B <strong><font color="#0000ff">implements</font></strong> <strong><a href="http://www.javaresearch.org/source/jdk142/java/io/Serializable.java.html" target="_blank"><font class="classLink"><u>Serializable</u></font></a></strong>
    <li>{
    <li>&nbsp;&nbsp; C c;
    <li>&nbsp;&nbsp; ...
    <li>}
    <li>
    <li><strong><font color="#0000ff">class</font></strong> C <strong><font color="#0000ff">implements</font></strong> <strong><a href="http://www.javaresearch.org/source/jdk142/java/io/Serializable.java.html" target="_blank"><font class="classLink"><u>Serializable</u></font></a></strong>
    <li>{
    <li>&nbsp;&nbsp; ...
    <li>}
    <li>
    <li>A a;
    <li>B b;
    <li>C c1;
    <li>... </li>
</ol>
</div>
<br />
&nbsp;&nbsp;&nbsp;&nbsp; 注意，这里我们在实例化a和b的时候，有意让他们的c属性使用同一个C类型对象的引用，譬如c1，那么请试想一下，但我们序列化a和b的时候，它们的c属性在外部字节流（当然可以不仅仅是文件）里保存的是一份拷贝还是两份拷贝呢？序列化在这里使用的是一种<strong>类似于&#8220;指针&#8221;的方案</strong>：它为每个被序列化的对象标上一个&#8220;<strong>序列号</strong>&#8221;（serial number），但序列化一个对象的时候，如果其某个属性对象是已经被序列化的，那么这里只向输出流写入该属性的序列号；从字节流恢复被序列化的对象时，也根据序列号找到对应的流来恢复。这就是&#8220;序列化&#8221;名称的由来！这里我们看到&#8220;序列化&#8221;和&#8220;指针&#8221;是极相似的，只不过&#8220;指针&#8221;是内存空间的地址链，而序列化用的是<strong>外部流中的&#8220;序列号链&#8221;</strong>。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 使用&#8220;序列号&#8221;而不是内存地址来标识一个被序列化的对象，是因为从流中恢复对象到内存，其地址可能就未必是原来的地址了??我们需要的只是这些对象之间的引用关系，而不是死板的原始位置，这在RMI中就更是必要，在两台不同的机器之间传递对象（流），根本就不可能指望它们在两台机器上都具有相同的内存地址。 <br />
<br />
★<strong>更灵活的&#8220;序列化&#8221;：transient属性和Externalizable</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp; Serializable确实很方便，方便到你几乎不需要做任何额外的工作就可以轻松将内存中的对象保存到外部。但有两个问题使得Serializable的威力收到束缚：<br />
&nbsp;&nbsp;&nbsp;&nbsp; 一个是效率问题，《Core Java 2》中指出，Serializable使用系统默认的序列化机制会影响软件的运行速度，因为需要为每个属性的引用编号和查号，再加上I/O操作的时间（I/O和内存读写差的可是一个数量级的大小），其代价当然是可观的。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 另一个困扰是&#8220;裸&#8221;的Serializable<strong>不可定制</strong>，傻乎乎地什么都给你序列化了，不管你是不是想这么做。其实你可以有至少三种定制序列化的选择。其中一种前面已经提到了，就是在implements Serializable的类里面添加私有的writeObject()和readObject()方法（这种Serializable就不裸了，<img height="20" alt="[:E]" src="http://www.javaresearch.org/faces/13.gif" width="20" border="0" />），在这两个方法里，该序列化什么，不该序列化什么，那就由你说了算了，你当然可以在这两个方法体里面分别调用ObjectOutputStream.<a class="l2" href="http://java.sun.com/j2se/1.4.2/docs/api/java/io/ObjectOutputStream.html#defaultWriteObject()" target="_blank">defaultWriteObject</a>()和ObjectInputStream.<a class="l2" href="http://java.sun.com/j2se/1.4.2/docs/api/java/io/ObjectInputStream.html#defaultReadObject()" target="_blank">defaultReadObject</a>()仍然执行<strong>默认的序列化动作</strong>（那你在代码上不就做无用功了？呵呵），也可以用ObjectOutputStream.writeObject()和ObjectInputStream.readObject()方法对你中意的属性进行序列化。但虚拟机一看到你定义了这两个方法，它就不再用默认的机制了。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 如果仅仅为了跳过某些属性不让它序列化，上面的动作似乎显得麻烦，更简单的方法是对不想序列化的属性加上<strong>transient</strong>关键字，说明它是个&#8220;暂态变量&#8221;，默认序列化的时候就不会把这些属性也塞到外部流里了。当然，你如果定义writeObject()和readObject()方法的化，仍然可以把暂态变量进行序列化。题外话，像<strong>transient</strong>、<strong>violate</strong>、<strong>finally</strong>这样的关键字初学者可能会不太重视，而现在有的公司招聘就偏偏喜欢问这样的问题 :(<br />
&nbsp;&nbsp;&nbsp;&nbsp; 再一个方案就是不实现Serializable而改成实现<a class="l2" href="http://java.sun.com/j2se/1.4.2/docs/api/java/io/Externalizable.html" target="_blank">Externalizable</a>接口。我们研究一下这两个接口的源代码，发现它们很类似，甚至容易混淆。我们要记住的是：Externalizable默认并<strong>不保存任何对象相关信息</strong>！任何保存和恢复对象的动作都是你自己定义的。Externalizable包含两个public的方法：<br />
<div class="codeStyle">
<ol>
    <li><strong><font color="#0000ff">public</font></strong> <strong><font color="#0000ff">void</font></strong> writeExternal(<font color="#ff0000">ObjectOutput</font> out) <strong><font color="#0000ff">throws</font></strong> <font color="#ff0000">IOException</font>;
    <li><strong><font color="#0000ff">public</font></strong> <strong><font color="#0000ff">void</font></strong> readExternal(<font color="#ff0000">ObjectInput</font> in) <strong><font color="#0000ff">throws</font></strong> <font color="#ff0000">IOException</font>, <strong><a href="http://www.javaresearch.org/source/jdk142/java/lang/ClassNotFoundException.java.html" target="_blank"><font class="classLink"><u>ClassNotFoundException</u></font></a></strong>; </li>
</ol>
</div>
<br />
&nbsp;&nbsp;&nbsp;&nbsp; 乍一看这和上面的writeObject()和readObject()几乎差不多，但Serializable和Externalizable走的是两个不同的流程：Serializable在对象不存在的情况下，就可以仅凭外部的字节序列把整个对象重建出来；但Externalizable在重建对象时，先是调用该类的默认构造函数（即不含参数的那个构造函数）使得内存中先有这么一个实例，然后再调用readExternal方法对实例中的属性进行恢复，因此，如果默认构造函数中和readExternal方法中都没有赋值的那些属性，特别他们是非基本类型的话，将会是空（null）。在这里需要注意的是，<strong>transient只能用在对Serializable而不是Externalizable的实现里面</strong>。 <br />
<br />
★<strong>序列化与克隆</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp; 从&#8220;可序列化&#8221;的递归定义来看，一个序列化的对象貌似对象内存映象的外部克隆，如果没有共享引用的属性的化，那么应该是一个<strong>深度克隆</strong>。关于克隆的话题有可以谈很多，这里就不细说了，有兴趣的话可以参考<a class="l2" href="http://www-900.ibm.com/developerWorks/cn/" target="_blank">IBM developerWorks</a>上的一篇文章：<a class="l2" href="http://www-900.ibm.com/developerWorks/cn/java/l-jpointer/index.shtml" target="_blank">JAVA中的指针,引用及对象的clone</a><br />
<h3><strong><u>一点启示</u></strong></h3>
<br />
&nbsp;&nbsp;&nbsp;&nbsp; 作为一个实际的应用，我在写那个简易的邮件客户端JExp的时候曾经对比过好几种保存Message对象（主要是几个关键属性和邮件的内容）到本地的方法，譬如XML、Properties等，最后还是选择了用序列化的方式，因为这种方法最简单， 大约可算是&#8220;学以致用&#8221;罢。这里&#8220;存取程序状态&#8221;其实只是一个引子话题罢了，我想说的是??就如同前面我们讨论的关于logging的话题一样??在Java面前对同一个问题你可以有很多种solution：熟悉文件操作的，你可能会觉得Properties、XML或Bean比较方便，然后又发现了还有Preferences这么一个东东，大概又会感慨&#8220;天外有天&#8221;了，等到你接触了很多种新方法以后，结果又会&#8220;殊途同归&#8221;，重新反省Serialization机制本身。这不仅是Java，科学也是同样的道理。 <br />
<br />
++++++++ 相关链接 ++++++++<br />
1:&gt; <a title="Java序列化技术" href="http://203.208.37.104/search?q=cache:tIo86hdMwGEJ:zhangjunhd.blog.51cto.com/113473/49756+java%E5%BA%8F%E5%88%97%E5%8C%96%E5%92%8C%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96&amp;hl=zh-CN&amp;ct=clnk&amp;cd=8&amp;gl=cn&amp;st_usg=ALhdy28tiVusAZvcY_-BG0v5wnv02Lv7Ig">Java序列化技术</a><br />
2:&gt; <a title="Bean与XML的序列化与反序列化" href="http://www.javaref.cn/egs/java.beans/WriteXml.html">Bean与XML的序列化与反序列化</a><br />
++++++++++++++++++++++++<br />
<img src ="http://www.blogjava.net/xinwuhen/aggbug/188791.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2008-03-26 16:45 <a href="http://www.blogjava.net/xinwuhen/archive/2008/03/26/188791.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Keytool工具介绍</title><link>http://www.blogjava.net/xinwuhen/archive/2008/03/13/185958.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Thu, 13 Mar 2008 03:02:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2008/03/13/185958.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/185958.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2008/03/13/185958.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/185958.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/185958.html</trackback:ping><description><![CDATA[<font class="header1">Sun Java Keytool 基本介绍 </font>
<p><font class="header2">Keytool</font> 是一个JAVA环境下的安全钥匙与证书的管理工具.它管理一个存储了私有钥匙和验证相应公共钥匙的与它们相关联的X.509 证书链的keystore(相当一个数据库，里面可存放多个X.509标准的证书). </p>
<p>Keytool 是一个有效的安全钥匙和证书的管理工具. 它能够使用户使用数字签名来管理他们自己的私有/公共钥匙对,管理用来作自我鉴定的相关的证书,管理数据完整性和鉴定服务.它还能使用户在通信时缓存它们的公共钥匙. </p>
<p>一个证书是某一实体(个人,公司等)的数字签名,指出其他实体的公共钥匙(或其他信息)的详细的值.当数据被签名后,这个签名信息被用来检验数据的完整性和真实性.完整性指数据没有被修改和篡改,真实性指数据从任何产生和签名的一方真正的传输到达.</p>
<p>Keytool 把钥匙和证书储存到一个keystore.默任的实现keystore的是一个文件.它用一个密码保护钥匙. </p>
<table cellspacing="0" cellpadding="0" width="360">
    <tbody>
        <tr>
            <td width="360" background="/images/dotted_bg.gif" height="1"></td>
        </tr>
    </tbody>
</table>
<p><font class="header1">Keystore有两个不同的入口:</font> </p>
<p>1.钥匙入口:保存了非常敏感的加密的钥匙信息,并且是用一个保护的格式存储以防止未被授权的访问.以这种形式存储的钥匙是秘密钥匙,或是一个对应证书链中公有钥匙的私有钥匙. </p>
<p>2.信任证书入口:包含一个属于其他部分的单一公共钥匙证书.它之所以被称为"信任证书",是因为keystore信任的证书中的公共钥匙真正属于证书所有者的身份识别. </p>
<table cellspacing="0" cellpadding="0" width="360">
    <tbody>
        <tr>
            <td width="360" background="/images/dotted_bg.gif" height="1"></td>
        </tr>
    </tbody>
</table>
<p><font class="header1">Keystore的别名:</font> </p>
<p>所有的keystore入口(钥匙和信任证书入口)是通过唯一的别名访问.别名是 不区分大小写的.如别名Hugo和hugo指向同一个keystore入口. </p>
<p>可以在加一个入口到keystore的时候使用-genkey参数来产生一个钥匙对(公共钥匙和私有钥匙)时指定别名.也可以用-import参数加一个证书或证书链到信任证书,例如：</p>
<p>keytool -genkey -alias myssl -keypass mysslpasswd </p>
<p>其中myssl为别名,mysslpasswd为myssl别名的密码.这行命令的作用是产生一个新的公共/私有钥匙对. </p>
<p>假如你想修改密码,可以用: </p>
<p>keytool -keypasswd -alias myssl -keypass mysslpasswd -new newpass </p>
<p>将旧密码mysslpasswd改为newpass. </p>
<table cellspacing="0" cellpadding="0" width="360">
    <tbody>
        <tr>
            <td width="360" background="/images/dotted_bg.gif" height="1"></td>
        </tr>
    </tbody>
</table>
<p><font class="header1">Keystore的产生:</font> </p>
<p>1.当使用-genkey 或-import或-identitydb命令添加数据到一个keystore,而当这个keystore不存在时,产生一个keystore.默认名是.keystore,存放到user-home目录. </p>
<p>2.当用-keystore指定时,将产生指定的keystore. </p>
<table cellspacing="0" cellpadding="0" width="360">
    <tbody>
        <tr>
            <td width="360" background="/images/dotted_bg.gif" height="1"></td>
        </tr>
    </tbody>
</table>
<p><font class="header1">Keystore的实现:</font> </p>
<p>Keytool 类位于java.security包下,提供一个非常好的接口去取得和修改一个keystore中的信息. 目前有两个命令行:keytool和jarsinger,一个GUI工具Policy 可以实现keystore.由于keystore是公开的,用户可以用它写一些额外的安全应用程序. </p>
<p>Keystore还有一个sun公司提供的內在实现.它把keystore作为一个文件来实现.利用了一个keystore类型(格式)"JKS".它用单独的密码保护每一个私有钥匙.也用可能不同的密码保护整个keystore的完整性. </p>
<table cellspacing="0" cellpadding="0" width="360">
    <tbody>
        <tr>
            <td width="360" background="/images/dotted_bg.gif" height="1"></td>
        </tr>
    </tbody>
</table>
<p><font class="header1">Keystore支持的算法和钥匙大小:</font> </p>
<p>keytool允许用户指定钥匙对和注册密码服务供应者所提供的签名算法.缺省的钥匙对产生算法是"DSA".假如私有钥匙是"DSA"类型,缺省签名算法是"SHA1withDSA",假如私有钥匙是"RSA"类型,缺省算法是"MD5withRSA". </p>
<p>当产生一个DSA钥匙对,钥匙必须在512-1024位之间.对任何算法的缺省钥匙大小是1024位. </p>
<table cellspacing="0" cellpadding="0" width="360">
    <tbody>
        <tr>
            <td width="360" background="/images/dotted_bg.gif" height="1"></td>
        </tr>
    </tbody>
</table>
<p><font class="header1">Keytool应用实例:</font> </p>
<p><font class="header2">1.产生一个keystore:</font> </p>
<p>keytool -genkey -alias myssl -keyalg RSA -keystore myssl.jks </p>
<p>运行这个命令,系统提示: </p>
<p><font class="header2">Enter keystore password:(输入keystore密码:)</font> <br />
yourpassword(输入密码)</p>
<p><font class="header2">What is your first and last name?(您的名字与姓氏是什么？) </font><br />
[Unknown]: www.myssl.cn(输入申请的证书的域名) </p>
<p><font class="header2">What is the name of your organizational unit? (您的组织单位名称是什么？)</font> <br />
[Unknown]:Fastcom(输入你所在组织单位的名字) </p>
<p><font class="header2">What is the name of your organization? (您的组织名称是什么？)</font> <br />
[Unknown]:Fastcom (输入你所在组织的名字) </p>
<p><font class="header2">What is the name of your City or Locality?(您所在的城市或区域名称是什么？)</font> <br />
[Unknown]:Shanghai(输入所在城市的名字) </p>
<p><font class="header2">What is the name of your State or Province? (您所在的州或省份名称是什么？)</font> <br />
[Unknown]:Shanghai(输入所在省份名字) </p>
<p><font class="header2">What is the two-letter country code for this unit?(该单位的两字母国家代码是什么？) </font><br />
[Unknown]:CN(输入国家名字,如果是中国，请输入CN) </p>
<p><font class="header2">Is CN=www.myssl.cn, OU=fastcom, O=fastcom, L=Shanghai, ST=Shanghai, C=CN correct? [no]:</font><br />
yes </p>
<p><font class="header2">2.检查一个keystore: </font></p>
<p>keytool -list -v -keystore myssl.jks </p>
<p><font class="header2">Enter keystore password:</font>yourpassword(输入密码) </p>
<p>将显示keystore內容如下: </p>
<p>Keystore type: jks <br />
Keystore provider: SUN <br />
Your keystore contains 1 entry <br />
Alias name: myssl <br />
Creation date: Nov 24 , 2006 <br />
Entry type: keyEntry <br />
Certificate chain length: 1 <br />
Certificate[1]: <br />
Owner: CN=www.myssl.cn, OU=fatcom, O=fastcom, L=Shanghai, ST=Shanghai, C=CN <br />
Issuer: CN=www.myssl.cn, OU=fastcom, O=fastcom, L=Shanghai, ST=Shanghai, C=CN <br />
Serial number: 3c22adc1 <br />
Valid from: Thu Nov 24 19:34:25 PST 2006 until: Thu Nov 24 19:34:25 PST 2007 <br />
Certificate fingerprints: <br />
MD5: F1:5B:9B:A1:F7:16:CF:25:CF:F4:FF:35:3F:4C:9C:F0 <br />
SHA1: B2:00:50:DD:B6:CC:35:66:21:45:0F:96:AA:AF:6A:3D:E4:03:7C:74 </p>
<p><font class="header2">3.输出keystore到一个文件:testkey:</font> </p>
<p>keytool -export -alias myssl -keystore myssl.jks -rfc -file testkey </p>
<p>系统输出: </p>
<p><font class="header2">Enter keystore password:</font>your password(输入密码) </p>
<p>Certificate stored in file </p>
<p><font class="header2">4.输入证书到一个新的truststore: </font></p>
<p>keytool -import -alias myssl -file testkey -keystore truststore </p>
<p><font class="header2">Enter keystore password:</font>your new password.(输入truststore新密码) </p>
<p><font class="header2">5.检查truststore: </font></p>
<p>keytool -list -v -keystore truststore </p>
<p>系统将显示truststore的信息. </p>
<p>&nbsp;</p>
<table cellspacing="0" cellpadding="0" width="360">
    <tbody>
        <tr>
            <td width="360" background="/images/dotted_bg.gif" height="1"></td>
        </tr>
    </tbody>
</table>
<p><font class="header1">Keytool命令行参数说明:</font> </p>
<table class="bg" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td class="lg_titile" valign="top" align="center" width="80">参数</td>
            <td class="lg_titile" valign="top" align="center">说明</td>
        </tr>
        <tr>
            <td class="lg_text" valign="top" align="center">-genkey</td>
            <td class="lg_text" valign="top">在用户主目录中创建一个默认文件".keystore",还会产生一个mykey的别名，mykey中包含用户的公钥、私钥和证书 </td>
        </tr>
        <tr>
            <td class="lg_text_b" valign="top" align="center">-alias </td>
            <td class="lg_text_b" valign="top">别名 </td>
        </tr>
        <tr>
            <td class="lg_text" valign="top" align="center">-keystore </td>
            <td class="lg_text" valign="top">指定密钥库的名称(产生的各类信息将不在.keystore文件中 </td>
        </tr>
        <tr>
            <td class="lg_text_b" valign="top" align="center">-keyalg </td>
            <td class="lg_text_b" valign="top">指定密钥的算法 </td>
        </tr>
        <tr>
            <td class="lg_text" valign="top" align="center">-validity </td>
            <td class="lg_text" valign="top">指定创建的证书有效期多少天 </td>
        </tr>
        <tr>
            <td class="lg_text_b" valign="top" align="center">-keysize </td>
            <td class="lg_text_b" valign="top">指定密钥长度</td>
        </tr>
        <tr>
            <td class="lg_text" valign="top" align="center">-storepass </td>
            <td class="lg_text" valign="top">指定密钥库的密码 </td>
        </tr>
        <tr>
            <td class="lg_text_b" valign="top" align="center">-keypass </td>
            <td class="lg_text_b" valign="top">指定别名条目的密码 </td>
        </tr>
        <tr>
            <td class="lg_text" valign="top" align="center">-dname </td>
            <td class="lg_text" valign="top">指定证书拥有者信息 例如： "CN=sagely,OU=atr,O=szu,L=sz,ST=gd,C=cn" </td>
        </tr>
        <tr>
            <td class="lg_text_b" valign="top" align="center">-list </td>
            <td class="lg_text_b" valign="top">显示密钥库中的证书详细信息 </td>
        </tr>
        <tr>
            <td class="lg_text" valign="top" align="center">-export </td>
            <td class="lg_text" valign="top">将别名指定的证书导出到文件 keytool -export -alias caroot -file caroot.crt </td>
        </tr>
        <tr>
            <td class="lg_text_b" valign="top" align="center">-file </td>
            <td class="lg_text_b" valign="top">参数指定导出到文件的文件名 </td>
        </tr>
        <tr>
            <td class="lg_text" valign="top" align="center">-delete </td>
            <td class="lg_text" valign="top">删除密钥库中某条目 </td>
        </tr>
        <tr>
            <td class="lg_text_b" valign="top" align="center">-keypasswd </td>
            <td class="lg_text_b" valign="top">修改密钥库中指定条目口令 keytool -keypasswd -alias sage -keypass .... -new .... -storepass ... -keystore sage</td>
        </tr>
        <tr>
            <td class="lg_text" valign="top" align="center">-import </td>
            <td class="lg_text" valign="top">将已签名数字证书导入密钥库 keytool -import -alias sage -keystore sagely -file sagely.crt<br />
            导入已签名数字证书用keytool -list -v 以后可以明显发现多了认证链长度，并且把整个CA链全部打印出来 </td>
        </tr>
    </tbody>
</table> <img src ="http://www.blogjava.net/xinwuhen/aggbug/185958.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2008-03-13 11:02 <a href="http://www.blogjava.net/xinwuhen/archive/2008/03/13/185958.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>OO 设计原则--转载</title><link>http://www.blogjava.net/xinwuhen/archive/2008/03/12/185710.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Wed, 12 Mar 2008 07:31:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2008/03/12/185710.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/185710.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2008/03/12/185710.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/185710.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/185710.html</trackback:ping><description><![CDATA[<strong>关键字</strong>: oo 原则 设计
<div class="blog_content">最近在审查(review)代码时,常常发现一大堆代码充满了各种bad smell.即使工作了三五年的同事,也不会例外.沟通时往往发现他们对OO的理解只是表现出简单的概念理解.对OO的一些原则不甚了解,或者写代码也是跟着感觉走. <br />
<br />
我最初做开发的时候也是跟着感觉走,初次听到OCP如天外来物.使用Java或C#不代表你就是在做OO开发,熟练使用OO语言不代表已经对OO非常了解.感谢Uncle Bob的经典巨著&lt;Agile Software Development&gt;,坚持阅读的习惯让我接触并努力理解OO原则.一旦对这些原则有了深入的认识,写代码时就已经从更高的角度来分析问题,解决问题,力争写出优雅的代码. <br />
<br />
我对OO的了解也不算多深刻,只在这里抛砖引玉.因为原则比较多,用一个系列来介绍会让大家更容易沟通. <br />
<br />
同时,原则是死的,人是活的,不要被这些原则束缚,有一些原则在特定的情况下才会有效. <br />
<br />
<span style="font-size: large">Single Choice Principle(SCP)</span> <br />
所有的判断只在一处进行.违反此原则的典型情况是不同的方法中充斥着相同的if ... else ...或类似的语句. <br />
<br />
<span style="font-size: large">Linguistic Modular Units</span> <br />
<br />
<span style="font-size: large">Few Interfaces</span> <br />
<br />
<span style="font-size: large">Small Interfaces</span> <br />
<br />
<span style="font-size: large">Explicit Interfaces</span> <br />
<br />
<span style="font-size: large">Behavioral Completeness</span> <br />
一个完整的类必须包含完整的方法.如果类没有完成它的职责,或者没有完成其父类需要完成的工作,那么它就是不完整的类. <br />
<br />
<span style="font-size: large">Law Of Demeter</span> <br />
只与直接协作的类交互. <br />
<br />
<span style="font-size: large">The Principle of Essential Representation(PER)</span> <br />
类应该包含而且只包含其本质的定义和表现,与SRP比较接近. <br />
<br />
<span style="font-size: large">Single Responsibility Principle(SRP)</span> <br />
一个类只承担一项职责,只能有一个发生变化的理由,那就是它的职责变化了. <br />
<br />
<span style="font-size: large">Open-Colse Principle(OCP)</span> <br />
类应该对扩展是开放的,对修改是封闭的. <br />
<br />
<span style="font-size: large">Liskov Substitution (LSP)</span> <br />
子类必须可以替换父类. <br />
<br />
<span style="font-size: large">Dependency-Inversion Principles(DIP)</span> <br />
高层应该不依赖于低层,双方都应该依赖于抽象.抽象不依赖于细节,细节应该依赖于抽象. <br />
<br />
<span style="font-size: large">Interface Segregation Principles(ISP)</span> <br />
接口属于客户程序. <br />
<br />
--------------------------------- <br />
<span style="font-size: large">Reuse Release Equivalence Principle(REP)</span> <br />
重用的粒度等于发布的粒度. <br />
<br />
<span style="font-size: large">Common Reuse Principle(CRP)</span> <br />
包中的类应该是共同重用的. <br />
<br />
<span style="font-size: large">Common Closure Principle(CCP)</span> <br />
包中的类对同一类变化共同封闭的,一个类发生变化,可能所有的类都要发生变化. <br />
<br />
--------------------------------- <br />
<span style="font-size: large">Acyclic Dependencies Principle(ADP)</span> <br />
包之间的依赖结构不应该存在环依赖. <br />
<br />
<span style="font-size: large">Stable Dependencies Principle (SDP)</span> <br />
包应该依赖于比它更稳定的包. <br />
<br />
<span style="font-size: large">Stable Abstractions Principle(SAP)</span> <br />
包的稳定程度与抽象程度成正比,越抽象的包越稳定. <br />
<br />
--------------------------------- <br />
开发时应该避免的bad design smell: <br />
僵化(Rigidity) 一处变化会影响系统中的很多地方. <br />
脆弱(Fragility) 一处变化会影响系统中不应该被影响的地方. <br />
牢固(Immobility) 很难被重用. <br />
<br />
还有一些原则可能被遗漏掉,如果你发现了,请及时提醒我. </div>
<img src ="http://www.blogjava.net/xinwuhen/aggbug/185710.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2008-03-12 15:31 <a href="http://www.blogjava.net/xinwuhen/archive/2008/03/12/185710.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>项目研发中用到的一个对JAR进行数字签名的ANT构建文件(备忘录)</title><link>http://www.blogjava.net/xinwuhen/archive/2008/03/12/185703.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Wed, 12 Mar 2008 06:58:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2008/03/12/185703.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/185703.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2008/03/12/185703.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/185703.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/185703.html</trackback:ping><description><![CDATA[<p>&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />
&lt;project name="MakeTopoJar" default="deployTopoJar" basedir="."&gt;<br />
&nbsp;&lt;!-- 设定系统环境变量名为env,以备下边使用 --&gt;<br />
&nbsp;&lt;property environment="env"/&gt;<br />
&nbsp;<br />
&nbsp;&lt;!-- 设定构建JAR时的路径与文件名参数,注意:下边的属性设定时,如果属性代表路径,则为了适应相应操作系统可用location代替value; <br />
&nbsp;&nbsp; 如果属性代表文件名,则必须用value. --&gt;<br />
&nbsp;&lt;property name="src" value="./src" /&gt;<br />
&nbsp;&lt;property name="webRoot" location="WebRoot"/&gt;<br />
&nbsp;&lt;property name="webInf" location="${webRoot}/WEB-INF"/&gt;<br />
&nbsp;&lt;property name="destDir" location="${webInf}/classes"/&gt;<br />
&nbsp;&lt;property name="classPath" location="${webInf}/lib"/&gt;<br />
&nbsp;&lt;property name="topoJarPath" location="${webRoot}/topo/lib"/&gt;<br />
&nbsp;&lt;property name="jarName" value="topo.jar"/&gt;<br />
&nbsp;<br />
&nbsp;&lt;!-- 数字签名用的密钥信息参数 --&gt;<br />
&nbsp;&lt;property name="keystoreName" value="esmkeystore"/&gt;</p>
<p>&nbsp;&lt;property name="storepass" value="esmsystem"/&gt;<br />
&nbsp;&lt;property name="keystore" location="${topoJarPath}/${keystoreName}"/&gt;<br />
&nbsp;&lt;property name="keypass" value="esmsystem"/&gt;<br />
&nbsp;&lt;property name="keysize" value="1024"/&gt;<br />
&nbsp;&lt;property name="alias" value="esmkey"/&gt;<br />
&nbsp;&lt;property name="validity" value="365"/&gt;</p>
<p>&nbsp;&lt;property name="jarsigner" value="${env.JAVA_HOME}/bin/jarsigner.exe"/&gt;<br />
&nbsp;<br />
&nbsp;&lt;!-- 部署数字签名后的JAR到TOMCAT相应目录 --&gt;<br />
&nbsp;&lt;property name="deployJarPath" location="${env.TOMCAT_HOME}/webapps/QT_ESM/topo/lib"/&gt;</p>
<p>&nbsp;&lt;target name="build"&gt;<br />
&nbsp;&nbsp;&lt;mkdir dir="${destDir}" /&gt;<br />
&nbsp;&nbsp;&lt;javac failonerror="false" encoding="utf-8" nowarn="true" debug="true" optimize="on" srcdir="${src}" <br />
&nbsp;&nbsp;&nbsp;&nbsp;destdir="${destDir}" includes="com/quantanetwork/esm/**/*.java, org/acegisecurity/ui/webapp/**/*.java"&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;classpath&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;fileset dir="${classPath}"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="**/*.jar" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/fileset&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;/classpath&gt;<br />
&nbsp;&nbsp;&lt;/javac&gt;<br />
&nbsp;&lt;/target&gt;<br />
&nbsp;<br />
&nbsp;&lt;!-- 构建JAR文件 --&gt;<br />
&nbsp;&lt;target name="makeJar" depends="build"&gt;<br />
&nbsp;&nbsp;&lt;copy todir="${destDir}/classes"&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;fileset dir="${src}"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="com/quantanetwork/esm/ui/topo/show/icons/*.*" /&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;/fileset&gt;<br />
&nbsp;&nbsp;&lt;/copy&gt;<br />
&nbsp;&nbsp;&lt;jar jarfile="${topoJarPath}/${jarName}" basedir="${destDir}" <br />
&nbsp;&nbsp;&nbsp; includes="com/quantanetwork/esm/logic/topo/**, com/quantanetwork/esm/ui/topo/**"&gt;<br />
&nbsp;&nbsp;&lt;/jar&gt;<br />
&nbsp;&lt;/target&gt;</p>
<p>&nbsp;&lt;!-- 创建证书 --&gt;<br />
&nbsp;&lt;target name="genericKey"&gt;<br />
&nbsp;&nbsp;&lt;echo message="genkey..."/&gt;<br />
&nbsp;&nbsp;&lt;delete&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;fileset dir="${topoJarPath}"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;include name="${keystoreName}"/&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;/fileset&gt;<br />
&nbsp;&nbsp;&lt;/delete&gt;</p>
<p>&nbsp;&nbsp;&lt;genkey keystore="${keystore}" storepass="${storepass}" alias="${alias}" keypass="${keypass}" keysize="${keysize}"<br />
&nbsp;&nbsp;&nbsp;&nbsp;verbose="true" validity="${validity}" dname="CN=Ant Group, OU=Jakarta Division, O=Apache.org, C=ZH"&gt;<br />
&nbsp;&nbsp;&lt;/genkey&gt;<br />
&nbsp;&nbsp;&lt;echo message="genkey... done"/&gt;<br />
&nbsp;&lt;/target&gt;<br />
&nbsp;<br />
&nbsp;&lt;!-- 对JAR进行数字签名 --&gt;<br />
&nbsp;&lt;target name="signJar" depends="makeJar, genericKey"&gt;<br />
&nbsp;&nbsp;&lt;echo message="jarsigner..." /&gt;<br />
&nbsp;&nbsp;&lt;exec executable="${jarsigner}" dir="${topoJarPath}"&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;arg line="-keystore"/&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;arg value="${keystore}"/&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;arg line="-storepass"/&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;arg value="${storepass}"/&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;arg line="${jarName}"/&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;arg line="${alias}"/&gt;<br />
&nbsp;&nbsp;&lt;/exec&gt;<br />
&nbsp;&nbsp;&lt;!-- 下边这种方式也可以 --&gt;<br />
&nbsp;&nbsp;&lt;!--signjar keystore="${keystore}" storepass="esmsystem" jar="${jarName}" alias="${alias}"&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;fileset dir="${topoJarPath}"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="${jarName}" /&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;/fileset&gt;<br />
&nbsp;&nbsp;&lt;/signjar--&gt;<br />
&nbsp;&nbsp;&lt;echo message="jarsigner... done." /&gt;<br />
&nbsp;&lt;/target&gt;<br />
&nbsp;<br />
&nbsp;&lt;!-- 部署JAR文件 --&gt;<br />
&nbsp;&lt;target name="deployTopoJar" depends="signJar"&gt;<br />
&nbsp;&nbsp;&lt;copy todir="${deployJarPath}" file="${topoJarPath}/${jarName}"&gt;<br />
&nbsp;&nbsp;&lt;/copy&gt;<br />
&nbsp;&lt;/target&gt;<br />
&lt;/project&gt;</p>
<img src ="http://www.blogjava.net/xinwuhen/aggbug/185703.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2008-03-12 14:58 <a href="http://www.blogjava.net/xinwuhen/archive/2008/03/12/185703.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hashtable和HashMap的区别</title><link>http://www.blogjava.net/xinwuhen/archive/2008/03/09/184896.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Sun, 09 Mar 2008 13:41:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2008/03/09/184896.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/184896.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2008/03/09/184896.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/184896.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/184896.html</trackback:ping><description><![CDATA[Hashtable和HashMap的区别：<br />
1.Hashtable是Dictionary的子类，HashMap是Map接口的一个实现类；<br />
2.Hashtable中的方法是同步的，而HashMap中的方法在缺省情况下是非同步的。即是说，在多线程应用程序中，不用专门的操作就安全地可以使用Hashtable了；而对于HashMap，则需要额外的同步机制。但HashMap的同步问题可通过Collections的一个静态方法得到解决：<br />
Map Collections.synchronizedMap(Map m)<br />
这个方法返回一个同步的Map，这个Map封装了底层的HashMap的所有方法，使得底层的HashMap即使是在多线程的环境中也是安全的。<br />
3.在HashMap中，null可以作为键，这样的键只有一个；可以有一个或多个键所对应的值为null。当get()方法返回null值时，即可以表示HashMap中没有该键，也可以表示该键所对应的值为null。因此，在HashMap中不能由get()方法来判断HashMap中是否存在某个键，而应该用containsKey()方法来判断。<br />
<br />
4.HashTable使用Enumeration，HashMap使用Iterator。<br />
<br />
<br />
以上只是表面的不同，它们的实现也有很大的不同。<br />
<br />
<br />
<br />
5.HashTable中hash数组默认大小是11，增加的方式是 old*2+1。HashMap中hash数组的默认大小是16，而且一定是2的指数。<br />
<br />
<br />
<br />
6.哈希值的使用不同，HashTable直接使用对象的hashCode，代码是这样的：<br />
int hash = key.hashCode();<br />
int index = (hash &amp; 0x7FFFFFFF) % tab.length;<br />
而HashMap重新计算hash值，而且用与代替求模：<br />
int hash = hash(k);<br />
int i = indexFor(hash, table.length);<br />
<br />
static int hash(Object x) {<br />
　　int h = x.hashCode();<br />
<br />
<br />
<br />
　　h += ~(h &lt;&lt; 9);<br />
　　h ^= (h &gt;&gt;&gt; 14);<br />
　　h += (h &lt;&lt; 4);<br />
　　h ^= (h &gt;&gt;&gt; 10);<br />
　　return h;<br />
}<br />
static int indexFor(int h, int length) {<br />
　　return h &amp; (length-1);<br />
}<br /> <img src ="http://www.blogjava.net/xinwuhen/aggbug/184896.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2008-03-09 21:41 <a href="http://www.blogjava.net/xinwuhen/archive/2008/03/09/184896.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Tomcat或Resin使用security-manager的问题--转载</title><link>http://www.blogjava.net/xinwuhen/archive/2008/03/08/184657.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Sat, 08 Mar 2008 03:46:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2008/03/08/184657.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/184657.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2008/03/08/184657.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/184657.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/184657.html</trackback:ping><description><![CDATA[我们打算为用户架设单独的虚拟主机服务器，可以让企业自主上传jsp、htm、php等程序。其中resin用来做jsp的容器。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 由于是用户自主通过FTP上传程序，我们必须控制这些程序可以执行的权限，不能让用户随便浏览硬盘上的文件，但又要能让resin可以正常运行。比如：/data/user_a目录中的程序，只能在/data/user_a目录及其子目录中读写，如果想要访问其他目录，就没有权限。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 通过研究resin的文档以及JAVA的机制，我认为要实现以上构想，可以通过使用java权限管理器来构建一个resin的沙箱来对java的具体操作进行授权。<br />
参考文档：<a href="http://www.caucho.com/resin-3.0/security/securitymanager.xtp">http://www.caucho.com/resin-3.0/security/securitymanager.xtp</a> ，<a href="http://www.jscud.com/srun/news/viewhtml/3_2005_10/148.htm">http://www.jscud.com/srun/news/viewhtml/3_2005_10/148.htm</a>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 当我认为胜利在望的时候，发现resin好像不支持grant codeBase "file:xxxx 。<br />
<br />
grant codeBase "file:/data/ftpdata/user01.test.com/-" {<br />
&nbsp;permission java.io.FilePermission "/data/ftpdata/user01.test.com/-", "read,write,delete";<br />
};<br />
&nbsp;&nbsp;&nbsp;&nbsp; 上面的语句，语法上没有问题，但就是不起作用。那个codebase目录下的文件，对本目录没有任何权限。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; resin的官方论坛里面，有人在2001年，针对resin1.2.5就提出了和我一摸一样的疑问（<a href="http://www.caucho.com/support/resin-interest/0105/0106.html">http://www.caucho.com/support/resin-interest/0105/0106.html</a>），作者发现问题是由于resin的classloader是非安全的，因此改了resin原文件后解决了问题（<a href="http://www.caucho.com/support/resin-interest/0105/0112.html">http://www.caucho.com/support/resin-interest/0105/0112.html</a>），但是我看resin3的源代码，里面已经基于java.security.SecureClassLoader，因此应该不是这个原因了。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 以下是我的resin.policy文件：</p>
<p>grant codeBase "file:${java.home}/lib/-" {<br />
&nbsp;permission java.security.AllPermission;<br />
};</p>
<p>grant codeBase "file:${java.home}/jre/lib/-" {<br />
&nbsp;permission java.security.AllPermission;<br />
};</p>
<p>grant codeBase "file:${resin.home}/lib/-" {<br />
&nbsp;permission java.security.AllPermission;<br />
};</p>
<p>grant {<br />
&nbsp;permission java.util.PropertyPermission "*", "read";<br />
&nbsp;permission java.io.SerializablePermission "enableSubstitution";<br />
&nbsp;permission java.lang.reflect.ReflectPermission "suppressAccessChecks";&nbsp; <br />
&nbsp;permission java.lang.RuntimePermission "accessClassInPackage.*";<br />
&nbsp;permission java.lang.RuntimePermission "getClassLoader";<br />
&nbsp;permission java.lang.RuntimePermission "accessDeclaredMembers";<br />
&nbsp;permission java.lang.RuntimePermission "modifyThreadGroup";<br />
&nbsp;permission java.lang.RuntimePermission "setContextClassLoader"; <br />
&nbsp;permission java.lang.RuntimePermission "setIO";<br />
&nbsp;permission java.lang.RuntimePermission "stopThread";<br />
&nbsp;permission java.lang.RuntimePermission "createClassLoader";<br />
&nbsp;permission java.lang.RuntimePermission "getProtectionDomain";<br />
&nbsp;permission java.lang.RuntimePermission "defineClassInPackage";<br />
&nbsp;permission java.security.SecurityPermission "putProviderProperty.SunJCE";<br />
&nbsp;permission java.security.SecurityPermission "insertProvider.SunJCE";<br />
&nbsp;permission java.util.logging.LoggingPermission "control";<br />
&nbsp;permission java.lang.RuntimePermission "getAttribute";<br />
&nbsp;permission java.util.PropertyPermission "jaxp.debug", "read";<br />
&nbsp;permission ognl.OgnlInvokePermission "invoke.*";<br />
&nbsp;permission java.net.SocketPermission "localhost:3306","connect";<br />
&nbsp;permission java.io.FilePermission "${resin.home}/-", "read";<br />
&nbsp;permission java.io.FilePermission "${java.home}/-", "read";<br />
&nbsp;permission java.io.FilePermission "/tmp/-","read,write,delete";<br />
&nbsp;permission java.io.FilePermission "/tmp","read,write,delete";<br />
&nbsp;permission java.io.FilePermission ".","read";<br />
&nbsp;permission java.io.FilePermission "/home/apps/java/jdk/lib/tools.jar","read";<br />
&nbsp;permission java.io.FilePermission "/bin/sh", "read,execute";<br />
};</p>
<p>//以下语句没有任何作用，/data/ftpdata/user01.test.com/下的jsp对这个目录没有读的权限<br />
grant codeBase "file:/data/ftpdata/user01.test.com/-" {<br />
&nbsp;permission java.io.FilePermission "/data/ftpdata/user01.test.com/-", "read,write,delete";<br />
};<br />
</p><img src ="http://www.blogjava.net/xinwuhen/aggbug/184657.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2008-03-08 11:46 <a href="http://www.blogjava.net/xinwuhen/archive/2008/03/08/184657.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAR文件揭密--转载</title><link>http://www.blogjava.net/xinwuhen/archive/2008/03/08/184645.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Sat, 08 Mar 2008 02:47:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2008/03/08/184645.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/184645.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2008/03/08/184645.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/184645.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/184645.html</trackback:ping><description><![CDATA[<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr valign="top">
            <td width="100%">
            <h1>JAR 文件揭密</h1>
            <p id="subtitle"><em>探索 JAR 文件格式的强大功能</em></p>
            <img class="display-img" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="1" /></td>
            <td class="no-print" width="192"><img height="18" alt="developerWorks" src="http://www.ibm.com/developerworks/i/dw.gif" width="192" /></td>
        </tr>
    </tbody>
</table>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr valign="top">
            <td width="10"><img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /></td>
            <td width="100%">
            <table class="no-print" cellspacing="0" cellpadding="0" width="160" align="right" border="0">
                <tbody>
                    <tr>
                        <td width="10"><img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /></td>
                        <td>
                        <table cellspacing="0" cellpadding="0" width="150" border="0">
                            <tbody>
                                <tr>
                                    <td class="v14-header-1-small">文档选项</td>
                                </tr>
                            </tbody>
                        </table>
                        <table class="v14-gray-table-border" cellspacing="0" cellpadding="0" border="0">
                            <tbody>
                                <tr>
                                    <td class="no-padding" width="150">
                                    <table cellspacing="0" cellpadding="0" width="143" border="0">
                                        <script language="JavaScript" type="text/javascript">
<!-- document.write('<tr valign="top"><td width="8"><img src="//www.ibm.com/i/c.gif" width="8" height="1" alt="" /></td><td width="16"><img alt="将打印机的版面设置成横向打印模式" height="16" src="//www.ibm.com/i/v14/icons/printer.gif" width="16" vspace="3"  /></td><td width="122"><p><strong><a class="smallplainlink" href="javascript:print()">打印本页</a></strong></p></td></tr>');
//-->
</script>
                                        <tbody>
                                            <tr valign="top">
                                                <td width="8"><img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" /></td>
                                                <td width="16"><img height="16" alt="将打印机的版面设置成横向打印模式" src="http://www.ibm.com/i/v14/icons/printer.gif" width="16" vspace="3" /></td>
                                                <td width="122">
                                                <p><strong><a class="smallplainlink" href="javascript:print()" cmimpressionsent="1">打印本页</a></strong></p>
                                                </td>
                                            </tr>
                                            <noscript></noscript>
                                            <form name="email" action="https://www.ibm.com/developerworks/secure/email-it.jsp" cm1="1">
                                                <input type="hidden" value="大多数 Java 程序员都熟悉对 JAR 文件的基本操作。但是只有少数程序员了解 JAR 文件格式的强大功能。在本文中，作者探讨了JAR 格式的许多功能和优势，包括打包、可执行的 JAR 文件、安全性和索引。" name="body" cM3 cm1="1" cm2="0" /><input type="hidden" value="JAR 文件揭密" name="subject" cM3 cm1="1" cm2="1" /><input type="hidden" value="cn" name="lang" cM3 cm1="1" cm2="2" /> <script language="JavaScript" type="text/javascript">
<!-- document.write('<tr valign="top"><td width="8"><img src="//www.ibm.com/i/c.gif" width="8" height="1" alt="" /></td><td width="16"><img src="//www.ibm.com/i/v14/icons/em.gif" height="16" width="16" vspace="3" alt="将此页作为电子邮件发送"  /></td><td width="122"><p><a class="smallplainlink" href="javascript:document.email.submit();"><strong>将此页作为电子邮件发送</strong></a></p></td></tr>');
//-->
</script>
                                                <tr valign="top">
                                                    <td width="8"><img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" /></td>
                                                    <td width="16"><img height="16" alt="将此页作为电子邮件发送" src="http://www.ibm.com/i/v14/icons/em.gif" width="16" vspace="3" /></td>
                                                    <td width="122">
                                                    <p><a class="smallplainlink" href="javascript:document.email.submit();" cmimpressionsent="1"><strong>将此页作为电子邮件发送</strong></a></p>
                                                    </td>
                                                </tr>
                                                <noscript></noscript>
                                            </form>
                                        </tbody>
                                    </table>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        <!--start RESERVED FOR FUTURE USE INCLUDE FILES--><!-- this content will be automatically generated across all content areas --><!--end RESERVED FOR FUTURE USE INCLUDE FILES--><br />
                        </td>
                    </tr>
                </tbody>
            </table>
            <p>级别： 初级</p>
            <p><a href="http://www.ibm.com/developerworks/cn/java/j-jar/index.html#author" cmimpressionsent="1">Pagadala J. Suresh</a> (<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#112;&#106;&#115;&#117;&#114;&#101;&#115;&#104;&#64;&#105;&#110;&#46;&#105;&#98;&#109;&#46;&#99;&#111;&#109;&#63;&#115;&#117;&#98;&#106;&#101;&#99;&#116;&#61;&#74;&#65;&#82;&#32;&#25991;&#20214;&#25581;&#23494;&#38;&#97;&#109;&#112;&#59;&#99;&#99;&#61;&#112;&#106;&#115;&#117;&#114;&#101;&#115;&#104;&#64;&#105;&#110;&#46;&#105;&#98;&#109;&#46;&#99;&#111;&#109;" cmimpressionsent="1">pjsuresh@in.ibm.com</a>), 软件工程师, IBM Global Services India<br />
            <a href="http://www.ibm.com/developerworks/cn/java/j-jar/index.html#author" cmimpressionsent="1">Palaniyappan Thiagarajan</a> (<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#116;&#112;&#97;&#108;&#97;&#110;&#105;&#121;&#64;&#105;&#110;&#46;&#105;&#98;&#109;&#46;&#99;&#111;&#109;&#63;&#115;&#117;&#98;&#106;&#101;&#99;&#116;&#61;&#74;&#65;&#82;&#32;&#25991;&#20214;&#25581;&#23494;&#38;&#97;&#109;&#112;&#59;&#99;&#99;&#61;&#116;&#112;&#97;&#108;&#97;&#110;&#105;&#121;&#64;&#105;&#110;&#46;&#105;&#98;&#109;&#46;&#99;&#111;&#109;" cmimpressionsent="1">tpalaniy@in.ibm.com</a>), 软件工程师, IBM Global Services India<br />
            </p>
            <p>2003 年 11 月 15 日</p>
            <blockquote>大多数 Java 程序员都熟悉对 JAR 文件的基本操作。但是只有少数程序员了解 JAR 文件格式的 <em>强大功能</em>。在本文中，作者探讨了JAR 格式的许多功能和优势，包括打包、可执行的 JAR 文件、安全性和索引。 </blockquote><!--start RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--end RESERVED FOR FUTURE USE INCLUDE FILES-->
            <p><a name="1"><span class="atitle">JAR 文件是什么？</span></a></p>
            <p>JAR 文件格式以流行的 ZIP 文件格式为基础，用于将许多个文件聚集为一个文件。与 ZIP 文件不同的是，JAR 文件不仅用于压缩和发布，而且还用于部署和封装库、组件和插件程序，并可被像编译器和 JVM 这样的工具直接使用。在 JAR 中包含特殊的文件，如 manifests 和部署描述符，用来指示工具如何处理特定的 JAR。</p>
            <p>一个 JAR 文件可以用于：</p>
            <ul>
                <li>用于发布和使用类库
                <li>作为应用程序和扩展的构建单元
                <li>作为组件、applet 或者插件程序的部署单位
                <li>用于打包与组件相关联的辅助资源 </li>
            </ul>
            <p>JAR 文件格式提供了许多优势和功能，其中很多是传统的压缩格式如 ZIP 或者 TAR 所没有提供的。它们包括：</p>
            <ul>
                <li><strong>安全性。</strong>可以对 JAR 文件内容加上数字化签名。这样，能够识别签名的工具就可以有选择地为您授予软件安全特权，这是其他文件做不到的，它还可以检测代码是否被篡改过。 <br />
                <li><strong>减少下载时间。</strong> 如果一个 applet 捆绑到一个 JAR 文件中，那么浏览器就可以在一个 HTTP 事务中下载这个 applet 的类文件和相关的资源，而不是对每一个文件打开一个新连接。 <br />
                <li><strong>压缩。</strong>JAR 格式允许您压缩文件以提高存储效率。 <br />
                <li><strong>传输平台扩展。</strong> Java 扩展框架(Java Extensions Framework)提供了向 Java 核心平台添加功能的方法，这些扩展是用 JAR 文件打包的(Java 3D 和 JavaMail 就是由 Sun 开发的扩展例子)。 <br />
                <li><strong>包密封。</strong>存储在 JAR 文件中的包可以选择进行 <em>密封</em>，以增强版本一致性和安全性。密封一个包意味着包中的所有类都必须在同一 JAR 文件中找到。 <br />
                <li><strong>包版本控制。</strong>一个 JAR 文件可以包含有关它所包含的文件的数据，如厂商和版本信息。 <br />
                <li><strong>可移植性。</strong>处理 JAR 文件的机制是 Java 平台核心 API 的标准部分。 </li>
            </ul>
            <p><a name="N100C4"><span class="smalltitle">压缩的和未压缩的 JAR</span></a></p>
            <p><code>jar</code> 工具(有关细节参阅 <a href="http://www.ibm.com/developerworks/cn/java/j-jar/index.html#jartool" cmimpressionsent="1"><code>jar</code> 工具 </a>)在默认情况下压缩文件。未压缩的 JAR 文件一般可以比压缩过的 JAR 文件更快地装载，因为在装载过程中要解压缩文件，但是未压缩的文件在网络上的下载时间可能更长。 </p>
            <p><a name="N100D9"><span class="smalltitle">META-INF 目录</span></a></p>
            <p>大多数 JAR 文件包含一个 META-INF 目录，它用于存储包和扩展的配置数据，如安全性和版本信息。Java 2 平台识别并解释 META-INF 目录中的下述文件和目录，以便配置应用程序、扩展和类装载器：</p>
            <ul>
                <li><strong>MANIFEST.MF。</strong>这个 <em>manifest 文件</em>定义了与扩展和包相关的数据。 <br />
                <li><strong>INDEX.LIST。</strong> 这个文件由 <code>jar</code> 工具的新选项 <code>-i</code> 生成，它包含在应用程序或者扩展中定义的包的位置信息。它是 JarIndex 实现的一部分，并由类装载器用于加速类装载过程。 <br />
                <li><strong><em>xxx</em>.SF。 </strong>这是 JAR 文件的签名文件。占位符 <em>xxx</em>标识了签名者。 <br />
                <li><strong><em>xxx</em>.DSA。 </strong>与签名文件相关联的签名程序块文件，它存储了用于签名 JAR 文件的公共签名。 </li>
            </ul>
            <p><a name="N10117"><span class="smalltitle">jar 工具</span></a></p>
            <p>为了用 JAR 文件执行基本的任务，要使用作为Java Development Kit 的一部分提供的 Java Archive Tool ( <code>jar</code> 工具)。用 <code>jar</code> 命令调用 <code>jar</code> 工具。表 1 显示了一些常见的应用： </p>
            <p><a name="N1012C"><span class="smalltitle">表 1. 常见的 <code>jar</code> 工具用法 </span></a></p>
            <p>
            <table cellspacing="0" cellpadding="3" width="100%" border="1">
                <tbody>
                    <tr>
                        <td><strong>功能</strong> </td>
                        <td><strong>命令</strong> </td>
                    </tr>
                    <tr>
                        <td>用一个单独的文件创建一个 JAR 文件</td>
                        <td>jar cf jar-file input-file...</td>
                    </tr>
                    <tr>
                        <td>用一个目录创建一个 JAR 文件</td>
                        <td>jar cf jar-file dir-name</td>
                    </tr>
                    <tr>
                        <td>创建一个未压缩的 JAR 文件</td>
                        <td>jar cf0 jar-file dir-name</td>
                    </tr>
                    <tr>
                        <td>更新一个 JAR 文件</td>
                        <td>jar uf jar-file input-file...</td>
                    </tr>
                    <tr>
                        <td>查看一个 JAR 文件的内容</td>
                        <td>jar tf jar-file</td>
                    </tr>
                    <tr>
                        <td>提取一个 JAR 文件的内容</td>
                        <td>jar xf jar-file</td>
                    </tr>
                    <tr>
                        <td>从一个 JAR 文件中提取特定的文件</td>
                        <td>jar xf jar-file archived-file...</td>
                    </tr>
                    <tr>
                        <td>运行一个打包为可执行 JAR 文件的应用程序</td>
                        <td>java -jar app.jar</td>
                    </tr>
                </tbody>
            </table>
            </p>
            <br />
            <table cellspacing="0" cellpadding="0" width="100%" border="0">
                <tbody>
                    <tr>
                        <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
                        <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
                    </tr>
                </tbody>
            </table>
            <table class="no-print" cellspacing="0" cellpadding="0" align="right">
                <tbody>
                    <tr align="right">
                        <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
                        <table cellspacing="0" cellpadding="0" border="0">
                            <tbody>
                                <tr>
                                    <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                                    </td>
                                    <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-jar/index.html#main" cmimpressionsent="1"><strong>回页首</strong></a></td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <br />
            <p><a name="2"><span class="atitle">可执行的 JAR</span></a></p>
            <p>一个 <em>可执行的 jar</em> 文件是一个自包含的 Java 应用程序，它存储在特别配置的JAR 文件中，可以由 JVM 直接执行它而无需事先提取文件或者设置类路径。要运行存储在非可执行的 JAR 中的应用程序，必须将它加入到您的类路径中，并用名字调用应用程序的主类。但是使用可执行的 JAR 文件，我们可以不用提取它或者知道主要入口点就可以运行一个应用程序。可执行 JAR 有助于方便发布和执行 Java 应用程序。 </p>
            <p><a name="N101A3"><span class="smalltitle">创建可执行 JAR</span></a></p>
            <p>创建一个可执行 JAR 很容易。首先将所有应用程序代码放到一个目录中。假设应用程序中的主类是 <code>com.mycompany.myapp.Sample</code> 。您要创建一个包含应用程序代码的 JAR 文件并标识出主类。为此，在某个位置(不是在应用程序目录中)创建一个名为 <code>manifest</code> 的文件，并在其中加入以下一行： </p>
            <table cellspacing="0" cellpadding="0" width="100%" border="0">
                <tbody>
                    <tr>
                        <td class="code-outline">
                        <pre class="displaycode">Main-Class: com.mycompany.myapp.Sample
                        </pre>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <p>然后，像这样创建 JAR 文件：</p>
            <table cellspacing="0" cellpadding="0" width="100%" border="0">
                <tbody>
                    <tr>
                        <td class="code-outline">
                        <pre class="displaycode">jar cmf manifest ExecutableJar.jar application-dir
                        </pre>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <p>所要做的就是这些了 -- 现在可以用 <code>java -jar</code> 执行这个 JAR 文件 ExecutableJar.jar。 </p>
            <p>一个可执行的 JAR 必须通过 menifest 文件的头引用它所需要的所有其他从属 JAR。如果使用了 <code>-jar</code> 选项，那么环境变量 CLASSPATH 和在命令行中指定的所有类路径都被 JVM 所忽略。 </p>
            <p><a name="N101CD"><span class="smalltitle">启动可执行 JAR</span></a></p>
            <p>既然我们已经将自己的应用程序打包到了一个名为 ExecutableJar.jar 的可执行 JAR 中了，那么我们就可以用下面的命令直接从文件启动这个应用程序：</p>
            <table cellspacing="0" cellpadding="0" width="100%" border="0">
                <tbody>
                    <tr>
                        <td class="code-outline">
                        <pre class="displaycode">java -jar ExecutableJar.jar
                        </pre>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <br />
            <table cellspacing="0" cellpadding="0" width="100%" border="0">
                <tbody>
                    <tr>
                        <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
                        <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
                    </tr>
                </tbody>
            </table>
            <table class="no-print" cellspacing="0" cellpadding="0" align="right">
                <tbody>
                    <tr align="right">
                        <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
                        <table cellspacing="0" cellpadding="0" border="0">
                            <tbody>
                                <tr>
                                    <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                                    </td>
                                    <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-jar/index.html#main" cmimpressionsent="1"><strong>回页首</strong></a></td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <br />
            <p><a name="3"><span class="atitle">包密封</span></a></p>
            <p>密封 JAR 文件中的一个包意味着在这个包中定义的所有类都必须在同一个 JAR 文件中找到。这使包的作者可以增强打包类之间的版本一致性。密封还提供了防止代码篡改的手段。</p>
            <p>要密封包，需要在 JAR 的 manifest 文件中为包添加一个 <code>Name</code> 头，然后加上值为&#8220;true&#8221;的 <code>Sealed</code> 头。与可执行的 JAR 一样，可以在创建 JAR 时，通过指定一个具有适当头元素的 manifest 文件密封一个 JAR，如下所示： </p>
            <table cellspacing="0" cellpadding="0" width="100%" border="0">
                <tbody>
                    <tr>
                        <td class="code-outline">
                        <pre class="displaycode">Name: com/samplePackage/
                        Sealed: true
                        </pre>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <p><code>Name</code> 头标识出包的相对路径名。它以一个&#8220;/&#8221;结束以与文件名区别。在 <code>Name</code> 头后面第一个空行之前的所有头都作用于在 <code>Name</code> 头中指定的文件或者包。在上述例子中，因为 <code>Sealed</code> 头出现在 <code>Name</code> 头后并且中间没有空行，所以 <code>Sealed</code> 头将被解释为只应用到包 <code>com/samplePackage</code> 上。 </p>
            <p>如果试图从密封包所在的 JAR 文件以外的其他地方装载密封包中的一个类，那么 JVM 将抛出一个 <code>SecurityException</code> 。 </p>
            <p><a name="IDAM1WVB">扩展打包 <br />
            扩展为 Java 平台增加了功能，在 JAR 文件格式中已经加入了扩展机制。扩展机制使得 JAR 文件可以通过 manifest 文件中的 <code>Class-Path</code> 头指定所需要的其他 JAR 文件。 </p>
            <p>假设 extension1.jar 和 extension2.jar 是同一个目录中的两个 JAR 文件，extension1.jar 的 manifest 文件包含以下头：</p>
            <table cellspacing="0" cellpadding="0" width="100%" border="0">
                <tbody>
                    <tr>
                        <td class="code-outline">
                        <pre class="displaycode">Class-Path: extension2.jar
                        </pre>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <p>这个头表明 extension2.jar 中的类是 extension1.jar 中的类的 <em>扩展类</em>。extension1.jar 中的类可以调用 extension2.jar 中的类，并且不要求 extension2.jar 处在类路径中。 </p>
            <p>在装载使用扩展机制的 JAR 时，JVM 会高效而自动地将在 <code>Class-Path</code> 头中引用的 JAR 添加到类路径中。不过，扩展 JAR 路径被解释为相对路径，所以一般来说，扩展 JAR 必须存储在引用它的 JAR 所在的同一目录中。 </p>
            <p>例如，假设类 <code>ExtensionClient</code> 引用了类 <code>ExtensionDemo</code> ,它捆绑在一个名为 ExtensionClient.jar 的 JAR 文件中，而类 <code>ExtensionDemo</code> 则捆绑在 ExtensionDemo.jar 中。为了使 ExtensionDemo.jar 可以成为扩展，必须将 ExtensionDemo.jar 列在 ExtensionClient.jar 的 manifest 的 <code>Class-Path</code> 头中，如下所示： </p>
            <table cellspacing="0" cellpadding="0" width="100%" border="0">
                <tbody>
                    <tr>
                        <td class="code-outline">
                        <pre class="displaycode">Manifest-Version: 1.0
                        Class-Path: ExtensionDemo.jar
                        </pre>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <p>在这个 manifest 中 <code>Class-Path</code> 头的值是没有指定路径的 ExtensionDemo.jar，表明 ExtensionDemo.jar 与 ExtensionClient JAR 文件处在同一目录中。 </p>
            <br />
            <table cellspacing="0" cellpadding="0" width="100%" border="0">
                <tbody>
                    <tr>
                        <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
                        <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
                    </tr>
                </tbody>
            </table>
            <table class="no-print" cellspacing="0" cellpadding="0" align="right">
                <tbody>
                    <tr align="right">
                        <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
                        <table cellspacing="0" cellpadding="0" border="0">
                            <tbody>
                                <tr>
                                    <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                                    </td>
                                    <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-jar/index.html#main" cmimpressionsent="1"><strong>回页首</strong></a></td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <br />
            <p><a name="4"><span class="atitle">JAR 文件中的安全性</span></a></p>
            <p>JAR 文件可以用 <code>jarsigner</code> 工具或者直接通过 <code>java.security</code> API 签名。一个签名的 JAR 文件与原来的 JAR 文件完全相同，只是更新了它的 manifest，并在 META-INF 目录中增加了两个文件，一个签名文件和一个签名块文件。 </p>
            <p>JAR 文件是用一个存储在 <em>Keystore</em> 数据库中的证书签名的。存储在 keystore 中的证书有密码保护，必须向 <code>jarsigner</code> 工具提供这个密码才能对 JAR 文件签名。 </p>
            <br />
            <a name="IDAV3WVB"><strong>图 1. Keystore 数据库 </strong></a><br />
            <img height="117" alt="Keystore 数据库" src="http://www.ibm.com/developerworks/cn/java/j-jar/images/keystoredatabase.gif" width="324" /> <br />
            <p>JAR 的每一位签名者都由在 JAR 文件的 META-INF 目录中的一个具有 .SF 扩展名的签名文件表示。这个文件的格式类似于 manifest 文件 -- 一组 RFC-822 头。如下所示，它的组成包括一个主要部分，它包括了由签名者提供的信息、但是不特别针对任何特定的 JAR 文件项，还有一系列的单独的项，这些项也必须包含在 menifest 文件中。在验证一个签名的 JAR 时，将签名文件的摘要值与对 JAR 文件中的相应项计算的摘要值进行比较。</p>
            <br />
            <a name="IDAA4WVB"><strong>清单 1. 签名 JAR 中的 Manifest 和 signature 文件</strong></a><br />
            <table cellspacing="0" cellpadding="0" width="100%" border="0">
                <tbody>
                    <tr>
                        <td class="code-outline">
                        <pre class="displaycode">Contents of signature file META-INF/MANIFEST.MF
                        Manifest-Version: 1.0
                        Created-By: 1.3.0 (Sun Microsystems Inc.)
                        Name: Sample.java
                        SHA1-Digest: 3+DdYW8INICtyG8ZarHlFxX0W6g=
                        Name: Sample.class
                        SHA1-Digest: YJ5yQHBZBJ3SsTNcHJFqUkfWEmI=
                        Contents of signature file META-INF/JAMES.SF
                        Signature-Version: 1.0
                        SHA1-Digest-Manifest: HBstZOJBuuTJ6QMIdB90T8sjaOM=
                        Created-By: 1.3.0 (Sun Microsystems Inc.)
                        Name: Sample.java
                        SHA1-Digest: qipMDrkurQcKwnyIlI3Jtrnia8Q=
                        Name: Sample.class
                        SHA1-Digest: pT2DYby8QXPcCzv2NwpLxd8p4G4=
                        </pre>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <p><a name="N1028D"><span class="smalltitle">数字签名</span></a></p>
            <p>一个数字签名是.SF 签名文件的已签名版本。数字签名文件是二进制文件，并且与 .SF 文件有相同的文件名，但是扩展名不同。根据数字签名的类型 -- RSA、DSA 或者 PGP -- 以及用于签名 JAR 的证书类型而有不同的扩展名。</p>
            <p><a name="N10296"><span class="smalltitle">Keystore</span></a></p>
            <p>要签名一个 JAR 文件，必须首先有一个私钥。私钥及其相关的公钥证书存储在名为 <code>keystores</code> 的、有密码保护的数据库中。JDK 包含创建和修改 keystores 的工具。keystore 中的每一个密钥都可以用一个别名标识，它通常是拥有这个密钥的签名者的名字。 </p>
            <p>所有 keystore 项(密钥和信任的证书项)都是用唯一别名访问的。别名是在用 <code>keytool -genkey</code> 命令生成密钥对(公钥和私钥)并在 keystore 中添加项时指定的。之后的 <code>keytool</code> 命令必须使用同样的别名引用这一项。 </p>
            <p>例如，要用别名&#8220;james&#8221;生成一个新的公钥/私钥对并将公钥包装到自签名的证书中，要使用下述命令：</p>
            <table cellspacing="0" cellpadding="0" width="100%" border="0">
                <tbody>
                    <tr>
                        <td class="code-outline">
                        <pre class="displaycode">keytool -genkey -alias james -keypass jamespass
                        -validity 80 -keystore jamesKeyStore
                        -storepass jamesKeyStorePass
                        </pre>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <p>这个命令序列指定了一个初始密码&#8220;jamespass&#8221;，后续的命令在访问 keystore &#8220;jamesKeyStore&#8221;中与别名&#8220;james&#8221;相关联的私钥时，就需要这个密码。如果 keystore&#8220;jamesKeyStore&#8221;不存在，则 <code>keytool</code> 会自动创建它。 </p>
            <p><a name="N102BC"><span class="smalltitle">jarsigner 工具</span></a></p>
            <p><code>jarsigner</code> 工具使用 keystore 生成或者验证 JAR 文件的数字签名。 </p>
            <p>假设像上述例子那样创建了 keystore &#8220;jamesKeyStore&#8221;，并且它包含一个别名为&#8220;james&#8221;的密钥，可以用下面的命令签名一个 JAR 文件：</p>
            <table cellspacing="0" cellpadding="0" width="100%" border="0">
                <tbody>
                    <tr>
                        <td class="code-outline">
                        <pre class="displaycode">jarsigner -keystore jamesKeyStore -storepass jamesKeyStorePass
                        -keypass jamespass -signedjar SSample.jar Sample.jar james
                        </pre>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <p>这个命令用密码&#8220;jamesKeyStorePass&#8221;从名为&#8220;jamesKeyStore&#8221;的 keystore 中提出别名为&#8220;james&#8221;、密码为&#8220;jamespass&#8221;的密钥，并对 Sample.jar 文件签名、创建一个签名的 JAR -- SSample.jar。</p>
            <p><code>jarsigner</code> 工具还可以验证一个签名的 JAR 文件，这种操作比签名 JAR 文件要简单得多，只需执行以下命令： </p>
            <table cellspacing="0" cellpadding="0" width="100%" border="0">
                <tbody>
                    <tr>
                        <td class="code-outline">
                        <pre class="displaycode">jarsigner -verify SSample.jar
                        </pre>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <p>如果签名的 JAR 文件没有被篡改过，那么 <code>jarsigner</code> 工具就会告诉您 JAR 通过验证了。否则，它会抛出一个 <code>SecurityException</code> ， 表明哪些文件没有通过验证。 </p>
            <p>还可以用 <code>java.util.jar</code> 和 <code>java.security</code> API 以编程方式签名 JAR(有关细节参阅 <a href="http://www.ibm.com/developerworks/cn/java/j-jar/index.html#resources" cmimpressionsent="1">参考资料</a>)。也可以使用像 Netscape Object Signing Tool 这样的工具。 </p>
            <br />
            <table cellspacing="0" cellpadding="0" width="100%" border="0">
                <tbody>
                    <tr>
                        <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
                        <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
                    </tr>
                </tbody>
            </table>
            <table class="no-print" cellspacing="0" cellpadding="0" align="right">
                <tbody>
                    <tr align="right">
                        <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
                        <table cellspacing="0" cellpadding="0" border="0">
                            <tbody>
                                <tr>
                                    <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                                    </td>
                                    <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-jar/index.html#main" cmimpressionsent="1"><strong>回页首</strong></a></td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <br />
            <p><a name="5"><span class="atitle">JAR 索引</span></a></p>
            <p>如果一个应用程序或者 applet 捆绑到多个 JAR 文件中，那么类装载器就使用一个简单的线性搜索算法搜索类路径中的每一个元素，这使类装载器可能要下载并打开许多个 JAR 文件，直到找到所要的类或者资源。如果类装载器试图寻找一个不存在的资源，那么在应用程序或者 applet 中的所有 JAR 文件都会下载。对于大型的网络应用程序和 applet，这会导致启动缓慢、响应迟缓并浪费带宽。</p>
            <p>从 JDK 1.3 以后，JAR 文件格式开始支持索引以优化网络应用程序中类的搜索过程，特别是 applet。JarIndex 机制收集在 applet 或者应用程序中定义的所有 JAR 文件的内容，并将这些信息存储到第一个 JAR 文件中的索引文件中。下载了第一个 JAR 文件后，applet 类装载器将使用收集的内容信息高效地装载 JAR 文件。这个目录信息存储在根 JAR 文件的 META-INF 目录中的一个名为 INDEX.LIST 的简单文本文件中。</p>
            <p><a name="IDA3BXVB">创建一个 JarIndex <br />
            可以通过在 <code>jar</code> 命令中指定 <code>-i</code> 选项创建一个 JarIndex。假设我们的目录结构如下图所示： </p>
            <br />
            <a name="IDAOCXVB"><strong>图 2. JarIndex </strong></a><br />
            <img height="163" alt="JarIndex Demo" src="http://www.ibm.com/developerworks/cn/java/j-jar/images/jarindex.gif" width="329" /> <br />
            <p>您将使用下述命令为 JarIndex_Main.jar、JarIndex_test.jar 和 JarIndex_test1.jar 创建一个索引文件：</p>
            <table cellspacing="0" cellpadding="0" width="100%" border="0">
                <tbody>
                    <tr>
                        <td class="code-outline">
                        <pre class="displaycode">jar -i JarIndex_Main.jar JarIndex_test.jar SampleDir/JarIndex_test1.jar
                        </pre>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <p>INDEX.LIST 文件的格式很简单，包含每个已索引的 JAR 文件中包含的包或者类的名字，如清单 2 所示：</p>
            <br />
            <a name="IDA3CXVB"><strong>清单 2. JarIndex INDEX.LIST 文件示例</strong></a><br />
            <table cellspacing="0" cellpadding="0" width="100%" border="0">
                <tbody>
                    <tr>
                        <td class="code-outline">
                        <pre class="displaycode">JarIndex-Version: 1.0
                        JarIndex_Main.jar
                        sp
                        JarIndex_test.jar
                        Sample
                        SampleDir/JarIndex_test1.jar
                        org
                        org/apache
                        org/apache/xerces
                        org/apache/xerces/framework
                        org/apache/xerces/framework/xml4j
                        </pre>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <br />
            <table cellspacing="0" cellpadding="0" width="100%" border="0">
                <tbody>
                    <tr>
                        <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
                        <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
                    </tr>
                </tbody>
            </table>
            <table class="no-print" cellspacing="0" cellpadding="0" align="right">
                <tbody>
                    <tr align="right">
                        <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
                        <table cellspacing="0" cellpadding="0" border="0">
                            <tbody>
                                <tr>
                                    <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                                    </td>
                                    <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-jar/index.html#main" cmimpressionsent="1"><strong>回页首</strong></a></td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            <br />
            <br />
            <p><a name="6"><span class="atitle">结束语</span></a></p>
            <p>JAR 格式远远超出了一种压缩格式，它有许多可以改进效率、安全性和组织 Java 应用程序的功能。因为这些功能已经建立在核心平台 -- 包括编译器和类装载器 -- 中了，所以开发人员可以利用 JAR 文件格式的能力简化和改进开发和部署过程。.</p>
            <br />
            <br />
            <p><a name="resources"><span class="atitle">参考资料 </span></a></p>
            <ul>
                <li>您可以参阅本文在 developerWorks 全球站点上的 <a href="http://www.ibm.com/developerworks/library/j-jar/index.html?S_TACT=105AGX52&amp;S_CMP=cn-a-j" cmimpressionsent="1">英文原文</a>. <br />
                <br />
                <li>参阅 <a href="http://java.sun.com/docs/books/tutorial/jar/basics/index.html" cmimpressionsent="1">jar</a> 实用程序的命令行选项的文档。 <br />
                <br />
                <br />
                <li>Raffi Krikorian 在 ONJava 上发表的文章提供了有关 <a href="http://www.onjava.com/pub/a/onjava/2001/04/12/signing_jar.html?page=1" cmimpressionsent="1">programmatically signing a JAR file</a>的帮助。 <br />
                <br />
                <br />
                <li>文章&#8220; <a href="http://www.ibm.com/developerworks/cn/java/j-webstart/" cmimpressionsent="1">Java Web Start</a>&#8221;( <em>developerWorks</em>，2001 年 9 月)描述了如何使用这种技术，以便允许应用程序可以指定所需的 JAR 文件并动态下载它们。 <br />
                <br />
                <br />
                <li>在 <a href="http://www.ibm.com/developerworks/cn/java/" cmimpressionsent="1"><em>developerWorks</em> Java 技术专区 </a>上可以找到数百篇关于 Java 编程的各个方面的文章。 </li>
            </ul>
            </td>
        </tr>
    </tbody>
</table><img src ="http://www.blogjava.net/xinwuhen/aggbug/184645.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2008-03-08 10:47 <a href="http://www.blogjava.net/xinwuhen/archive/2008/03/08/184645.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入研究Servlet线程安全性问题--转载</title><link>http://www.blogjava.net/xinwuhen/archive/2008/03/08/184633.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Sat, 08 Mar 2008 01:36:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2008/03/08/184633.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/184633.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2008/03/08/184633.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/184633.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/184633.html</trackback:ping><description><![CDATA[Servlet/JSP技术和ASP、PHP等相比，由于其多线程运行而具有很高的执行效率。由于Servlet/JSP默认是以多线程模式执行的，所以，在编写代码时需要非常细致地考虑多线程的<a class="channel_keylink" href="http://security.chinaitlab.com/" target="_blank">安全</a>性问题。然而，很多人编写Servlet/JSP程序时并没有注意到多线程<a class="channel_keylink" href="http://security.chinaitlab.com/" target="_blank">安全</a>性的问题，这往往造成编写的程序在少量用户访问时没有任何问题，而在并发用户上升到一定值时，就会经常出现一些莫明其妙的问题。<br />
　　<br />
　　<strong>Servlet的多线程机制</strong><br />
　　<br />
　　Servlet体系结构是建立在<a class="channel_keylink" href="http://java.chinaitlab.com/" target="_blank">Java</a>多线程机制之上的，它的生命周期是由Web容器负责的。当客户端第一次请求某个Servlet时，Servlet容器将会根据web.xml配置文件实例化这个Servlet类。当有新的客户端请求该Servlet时，一般不会再实例化该Servlet类，也就是有多个线程在使用这个实例。Servlet容器会自动使用线程池等技术来支持系统的运行，如图1所示。<br />
　　
<center>　<img alt="" src="http://java.chinaitlab.com/imgfiles/2005.5.23.9.53.47.1.jpg" /></center><br />
　　
<center>图1 Servlet线程池</center><br />
　　<br />
　　这样，当两个或多个线程同时访问同一个Servlet时，可能会发生多个线程同时访问同一资源的情况，数据可能会变得不一致。所以在用Servlet构建的Web应用时如果不注意线程安全的问题，会使所写的Servlet程序有难以发现的错误。<br />
　　<br />
　　<strong>Servlet的线程安全问题</strong><br />
　　<br />
　　Servlet的线程安全问题主要是由于实例变量使用不当而引起的，这里以一个现实的例子来说明。<br />
　　<br />
　　Import javax.servlet. *;<br />
　　Import javax.servlet.http. *;<br />
　　Import java.io. *;<br />
　　Public class Concurrent Test extends HttpServlet {PrintWriter output;<br />
　　Public void service (HttpServletRequest request,<br />
　　HttpServletResponse response) throws ServletException, IOException {String username;<br />
　　Response.setContentType ("text/html; charset=gb2312");<br />
　　Username = request.getParameter ("username");<br />
　　Output = response.getWriter ();<br />
　　Try {Thread. sleep (5000); //为了突出并发问题，在这设置一个延时<br />
　　} Catch (Interrupted Exception e){}<br />
　　output.println("用户名:"+Username+"&lt;BR&gt;");<br />
　　}<br />
　　}<br />
　　<br />
　　该Servlet中定义了一个实例变量output，在service方法将其赋值为用户的输出。当一个用户访问该Servlet时，程序会正常的运行，但当多个用户并发访问时，就可能会出现其它用户的信息显示在另外一些用户的浏览器上的问题。这是一个严重的问题。为了突出并发问题，便于测试、观察，我们在回显用户信息时执行了一个延时的操作。假设已在web.xml配置文件中注册了该Servlet，现有两个用户a和b同时访问该Servlet（可以启动两个IE浏览器，或者在两台机器上同时访问）,即同时在浏览器中输入：<br />
　　<br />
　　a： http://localhost: 8080/servlet/ConcurrentTest? Username=a<br />
　　<br />
　　b： http://localhost: 8080/servlet/ConcurrentTest? Username=b<br />
　　<br />
　　如果用户b比用户a回车的时间稍慢一点，将得到如图2所示的输出：<br />
　　
<center>　<img alt="" src="http://java.chinaitlab.com/imgfiles/2005.5.23.9.53.56.2.jpg" /></center><br />
　　
<center>图2 a用户和b用户的浏览器输出</center><br />
　　<br />
　　从图2中可以看到，Web<a class="channel_keylink" href="http://server.chinaitlab.com/" target="_blank">服务器</a>启动了两个线程分别处理来自用户a和用户b的请求，但是在用户a的浏览器上却得到一个空白的屏幕，用户a的信息显示在用户b的浏览器上。该Servlet存在线程不安全问题。下面我们就从分析该实例的内存模型入手,观察不同时刻实例变量output的值来分析使该Servlet线程不安全的原因。<br />
　　<br />
　　<a class="channel_keylink" href="http://java.chinaitlab.com/" target="_blank">Java</a>的内存模型JMM（Java Memory Model）JMM主要是为了规定了线程和内存之间的一些关系。根据JMM的设计，系统存在一个主内存(Main Memory)，Java中所有实例变量都储存在主存中，对于所有线程都是共享的。每条线程都有自己的工作内存(Working Memory)，工作内存由缓存和堆栈两部分组成，缓存中保存的是主存中变量的拷贝，缓存可能并不总和主存同步，也就是缓存中变量的修改可能没有立刻写到主存中；堆栈中保存的是线程的局部变量，线程之间无法相互直接访问堆栈中的变量。根据JMM，我们可以将论文中所讨论的Servlet实例的内存模型抽象为图3所示的模型。<br />
　　
<center>　<img alt="" src="http://java.chinaitlab.com/imgfiles/2005.5.23.9.54.4.3.jpg" /></center><br />
　　
<center>图3 Servlet实例的JMM模型</center><br />
　　<br />
　　下面根据图3所示的内存模型，来分析当用户a和b的线程（简称为a线程、b线程）并发执行时，Servlet实例中所涉及变量的变化情况及线程的执行情况，如图4所示。<br />
　　
<center><img alt="" src="http://java.chinaitlab.com/imgfiles/2005.5.23.9.54.11.4.GIF" /></center><br />
　　
<center>图4 Servlet实例的线程调度情况</center><br />
　　<br />
　　从图4中可以清楚的看到，由于b线程对实例变量output的修改覆盖了a线程对实例变量output的修改，从而导致了用户a的信息显示在了用户b的浏览器上。如果在a线程执行输出语句时，b线程对output的修改还没有刷新到主存，那么将不会出现图2所示的输出结果，因此这只是一种偶然现象，但这更增加了程序潜在的危险性。 <br />
<br />
<img src ="http://www.blogjava.net/xinwuhen/aggbug/184633.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2008-03-08 09:36 <a href="http://www.blogjava.net/xinwuhen/archive/2008/03/08/184633.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用JDK中提供的java.util.logging.*包创建Logger对象----原创</title><link>http://www.blogjava.net/xinwuhen/archive/2008/03/07/184591.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Fri, 07 Mar 2008 13:00:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2008/03/07/184591.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/184591.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2008/03/07/184591.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/184591.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/184591.html</trackback:ping><description><![CDATA[<p>由于项目中用到了Applet与Servlet之间(客户端用Applet、Server端用Servlet)的通信，要求：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1:&gt;客户端与服务端必须出Log.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2:&gt;浏览器在加载Applet时已有好多个JAR文件需要加载，故不想再附加Log4J对应的JAR包。<br />
基于上面的要求，便想到了使用JDK自带的LOG输出功能，具体Logger对象的工厂类如下：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<p>package com.quantanetwork.esm.logic.topo;</p>
<p>import java.io.IOException;<br />
import java.text.SimpleDateFormat;<br />
import java.util.Date;<br />
import java.util.HashMap;<br />
import java.util.Locale;<br />
import java.util.logging.FileHandler;<br />
import java.util.logging.Formatter;<br />
import java.util.logging.Level;<br />
import java.util.logging.LogRecord;<br />
import java.util.logging.Logger;</p>
<p>/**<br />
&nbsp;* 拓扑Logger。<br />
&nbsp;* @author xinwuhen<br />
&nbsp;*<br />
&nbsp;*/<br />
public class TopoLogger {<br />
&nbsp;// Log文件的路径及格式：%h 代表用户主目录 %g 代表自动编号<br />
&nbsp;private static final String logFile = "%h/topo%g.log";<br />
&nbsp;// 写入到任何一个文件的最大字节数<br />
&nbsp;private static final int limit = 5 * 1024;<br />
&nbsp;// 要使用的文件数<br />
&nbsp;private static final int count = 20;<br />
&nbsp;// 指定 append 模式<br />
&nbsp;private static final boolean append = true;<br />
&nbsp;// 默认LOG级别<br />
&nbsp;private static final Level defaultLevel = Level.INFO;<br />
&nbsp;<br />
&nbsp;// Logger存储器<br />
&nbsp;private static final HashMap&lt;String, Logger&gt; hmLogger = new HashMap&lt;String, Logger&gt;();<br />
&nbsp;<br />
&nbsp;// 为对Logger存储器访问提供的同步锁对象<br />
&nbsp;private static final Object syncLock = new Object();<br />
&nbsp;<br />
/**<br />
*&nbsp;&nbsp; 此处是测试方法。<br />
**/<br />
public static void main(String[] args) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;Logger logger = getLogger(null);&nbsp;// 此处用Null代表用本类（TopoLogger）的类名作为Logger的名称<br />
&nbsp;&nbsp;&nbsp;&nbsp;try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(Long.parseLong(null));<br />
&nbsp;&nbsp;&nbsp;&nbsp;} catch(Exception ex) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TopoLogger.getLogger(null).log(Level.SEVERE, "很严重哟", ex);<br />
&nbsp; }<br />
}<br />
&nbsp;<br />
&nbsp;/**<br />
&nbsp; * 从Logger存储器取得Logger对象。<br />
&nbsp; * @param strClassName<br />
&nbsp; * @return<br />
&nbsp; */<br />
&nbsp;public static Logger getLogger(String strClassName) {<br />
&nbsp;&nbsp;Logger logger = null;<br />
&nbsp;&nbsp;synchronized (syncLock) {<br />
&nbsp;&nbsp;&nbsp;if (strClassName == null) {&nbsp;&nbsp;// 取当前Logger类默认的Logger对象<br />
&nbsp;&nbsp;&nbsp;&nbsp;String strDefaultClassName = TopoLogger.class.getName();<br />
&nbsp;&nbsp;&nbsp;&nbsp;logger = hmLogger.get(strDefaultClassName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (logger == null) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger = Logger.getLogger(strDefaultClassName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hmLogger.put(strDefaultClassName, logger);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;} else {&nbsp;// 新生成一个指定名称的Logger对象<br />
&nbsp;&nbsp;&nbsp;&nbsp;logger = hmLogger.get(strClassName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (logger == null) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger = Logger.getLogger(strClassName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hmLogger.put(strClassName, logger);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;// 添加默认的文件处理句柄<br />
&nbsp;&nbsp;logger.addHandler(getFileHandler());<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;return logger;<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;/**<br />
&nbsp; * 取默认的文件处理句柄。<br />
&nbsp; * @return<br />
&nbsp; */<br />
&nbsp;private static FileHandler getFileHandler() {<br />
&nbsp;&nbsp;FileHandler fileHandler = null;<br />
&nbsp;&nbsp;try {<br />
&nbsp;&nbsp;&nbsp;fileHandler = new FileHandler(logFile, limit, count, append);<br />
&nbsp;&nbsp;} catch (SecurityException e) {<br />
&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />
&nbsp;&nbsp;} catch (IOException e) {<br />
&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;if (fileHandler != null) {<br />
&nbsp;&nbsp;&nbsp;fileHandler.setLevel(defaultLevel);<br />
&nbsp;&nbsp;&nbsp;fileHandler.setFormatter(new TopoLoggerFormatter());<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;return fileHandler;<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;/**<br />
&nbsp; * Logger格式化处理器。<br />
&nbsp; * <br />
&nbsp; * @author xinwuhen<br />
&nbsp; */<br />
&nbsp;final static class TopoLoggerFormatter extends Formatter {<br />
&nbsp;&nbsp;@Override<br />
&nbsp;&nbsp;public String format(LogRecord record) {<br />
&nbsp;&nbsp;&nbsp;StringBuffer strOutput = new StringBuffer();<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;strOutput.append("[");<br />
&nbsp;&nbsp;&nbsp;strOutput.append(getFormattedTime(record.getMillis(), "yyyy-MM-dd HH:mm:SS, sss"));<br />
&nbsp;&nbsp;&nbsp;strOutput.append("], ");<br />
&nbsp;&nbsp;&nbsp;strOutput.append(record.getLevel());<br />
&nbsp;&nbsp;&nbsp;strOutput.append(", ");<br />
&nbsp;&nbsp;&nbsp;strOutput.append(record.getSourceClassName());<br />
&nbsp;&nbsp;&nbsp;strOutput.append(",");<br />
&nbsp;&nbsp;&nbsp;strOutput.append(record.getSourceMethodName());<br />
&nbsp;&nbsp;&nbsp;strOutput.append(" ");<br />
&nbsp;&nbsp;&nbsp;strOutput.append(record.getMessage());<br />
&nbsp;&nbsp;&nbsp;strOutput.append(":");<br />
&nbsp;&nbsp;&nbsp;strOutput.append(System.getProperty("line.separator"));<br />
&nbsp;&nbsp;&nbsp;Throwable throwAble = record.getThrown();<br />
&nbsp;&nbsp;&nbsp;if (throwAble != null) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;strOutput.append(getThrowAbleInfo(throwAble));<br />
&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;return strOutput.toString();<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;/**<br />
&nbsp;&nbsp; * 根据指定格式转换时间。<br />
&nbsp;&nbsp; * @param lngMillTimes<br />
&nbsp;&nbsp; * @param strTimeFormat<br />
&nbsp;&nbsp; * @return<br />
&nbsp;&nbsp; */<br />
&nbsp;&nbsp;private String getFormattedTime(long lngMillTimes, String strTimeFormat) {<br />
&nbsp;&nbsp;&nbsp;Date lvDate = new Date();<br />
&nbsp;&nbsp;&nbsp;lvDate.setTime(lngMillTimes);<br />
&nbsp;&nbsp;&nbsp;SimpleDateFormat lvFormat = new SimpleDateFormat(strTimeFormat, Locale.CHINA); <br />
&nbsp;&nbsp;&nbsp;return lvFormat.format(lvDate);<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;/**<br />
&nbsp;&nbsp; * 取例外对象的信息。<br />
&nbsp;&nbsp; * @param throwAble<br />
&nbsp;&nbsp; * @return<br />
&nbsp;&nbsp; */<br />
&nbsp;&nbsp;private String getThrowAbleInfo(Throwable throwAble) {<br />
&nbsp;&nbsp;&nbsp;String throwAbleInfo = "";<br />
&nbsp;&nbsp;&nbsp;StackTraceElement[] ste = throwAble.getStackTrace();<br />
&nbsp;&nbsp;&nbsp;if (ste != null) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;final String strLineSeparator = System.getProperty("line.separator");<br />
&nbsp;&nbsp;&nbsp;&nbsp;StringBuffer sbStackTraceEle = new StringBuffer();<br />
&nbsp;&nbsp;&nbsp;&nbsp;for (StackTraceElement stackTraceElement : ste) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sbStackTraceEle.append("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at ");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sbStackTraceEle.append(stackTraceElement.toString());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sbStackTraceEle.append(strLineSeparator);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;throwAbleInfo = throwAble.toString() + strLineSeparator + sbStackTraceEle;<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;return throwAbleInfo;<br />
&nbsp;&nbsp;}<br />
&nbsp;}<br />
}<br />
<br />
++++ 输出结果如下（注意内容是通过程序中定义的文件来存储的，在$USER_HOME/topo0.log中）：++++<br />
[2008-03-07 21:01:328, 000], SEVERE, com.quantanetwork.esm.logic.topo.TopoLogger,main 很严重哟:<br />
java.lang.NumberFormatException: null<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at java.lang.Long.parseLong(Long.java:372)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at java.lang.Long.parseLong(Long.java:461)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at com.quantanetwork.esm.logic.topo.TopoLogger.main(TopoLogger.java:40)<br />
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<br />
以上内容抛砖引玉，望大家有其它输出方式的更好实现。。。。。。另外，本人博客中的&#8220;JAVA技术文档&#8221;链接分类也有对JDK的Logger的描述，可以参见该文档互相学习。。。。。谢谢！！！</p><img src ="http://www.blogjava.net/xinwuhen/aggbug/184591.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2008-03-07 21:00 <a href="http://www.blogjava.net/xinwuhen/archive/2008/03/07/184591.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>学习使用java.util.logging.Logger类--转载</title><link>http://www.blogjava.net/xinwuhen/archive/2008/03/07/184583.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Fri, 07 Mar 2008 11:27:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2008/03/07/184583.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/184583.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2008/03/07/184583.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/184583.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/184583.html</trackback:ping><description><![CDATA[<p>1.在程序里面写死需要哪些log级别,使用哪些subscribe</p>
<p>import java.util.logging.*;<br />
public class LoggingProgramSetPubSubpro <br />
{<br />
&nbsp;public static void main(String[] args) <br />
&nbsp;{ <br />
&nbsp;&nbsp;Logger logger = Logger.getLogger("loggingTest");<br />
&nbsp;&nbsp;logger.setLevel(Level.INFO);//这个设定最重要<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;ConsoleHandler consoleHandler = new ConsoleHandler();<br />
&nbsp;&nbsp;consoleHandler.setLevel(Level.OFF);//这个好像不起作用<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;logger.addHandler(consoleHandler);<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;logger.severe("嚴重訊息");<br />
&nbsp;&nbsp;logger.warning("警示訊息");<br />
&nbsp;&nbsp;logger.info("一般訊息");<br />
&nbsp;&nbsp;logger.config("設定方面的訊息");<br />
&nbsp;&nbsp;logger.fine("細微的訊息");<br />
&nbsp;&nbsp;logger.finer("更細微的訊息");<br />
&nbsp;&nbsp;logger.finest("最細微的訊息");<br />
&nbsp;}<br />
} </p>
<p>2.如何在配置文件里面改,好处是不用重新编译原文件</p>
<p>import java.util.logging.*;<br />
/**</p>
<p>说明:我们可以在C:\Documents and Settings\yay目录下面找到java0.log文件<br />
&nbsp;它是一个xml格式的,<br />
&nbsp;我们可以在${jdk}\jar\lib下面找到logging.properties文件,你可以在这里面修改</p>
<p>&nbsp;</p>
<p>*/<br />
public class LoggingPropertiesFile <br />
&nbsp;{<br />
&nbsp;&nbsp;public static void main(String[] args) <br />
&nbsp;&nbsp;&nbsp;{</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;Logger logger = Logger.getLogger("loggingTest");<br />
&nbsp;&nbsp;&nbsp;&nbsp;logger.severe("严重的信息");<br />
&nbsp;&nbsp;&nbsp;&nbsp;logger.warning("警告信息");<br />
&nbsp;&nbsp;&nbsp;&nbsp;logger.info("一般信息");<br />
&nbsp;&nbsp;&nbsp;&nbsp;logger.config("设定方面的信息");<br />
&nbsp;&nbsp;&nbsp;&nbsp;logger.fine("细微的信息");<br />
&nbsp;&nbsp;&nbsp;&nbsp;logger.finer("更细微的信息");<br />
&nbsp;&nbsp;&nbsp;&nbsp;logger.finest("最细微的信息");<br />
&nbsp;&nbsp;&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;}<br />
&nbsp;} <br />
</p>
<p>3.使用log方法,使用自定义的Formatter</p>
<p>import java.util.logging.*;<br />
/**</p>
<p>輸出格式是由java.util.logging.Formatter决定的<br />
注意这里说得这个Formatter是属于哪里包里面的,不要搞混了</p>
<p>*/<br />
public class LoggingLogMethod<br />
{ <br />
&nbsp;public static void main(String[] args) <br />
&nbsp;{ <br />
&nbsp;&nbsp;Logger logger = Logger.getLogger("loggingTest");<br />
&nbsp;&nbsp;logger.setLevel(Level.ALL);<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;ConsoleHandler consoleHandler = new ConsoleHandler();<br />
&nbsp;&nbsp;consoleHandler.setLevel(Level.ALL);<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;logger.addHandler(consoleHandler);<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;try<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;//%h代表用户主目录<br />
&nbsp;&nbsp;&nbsp;//%g代表自动编号<br />
&nbsp;&nbsp;&nbsp;FileHandler&nbsp; fileHandler=new FileHandler("%h/loggingHome%g.log");<br />
&nbsp;&nbsp;&nbsp;fileHandler.setLevel(Level.ALL);<br />
&nbsp;&nbsp;&nbsp;fileHandler.setFormatter(new YAYFormatter());<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;logger.addHandler(fileHandler);<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;catch (Exception e)<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;logger.log(Level.SEVERE, "嚴重訊息");<br />
&nbsp;&nbsp;logger.log(Level.WARNING, "警示訊息");<br />
&nbsp;&nbsp;logger.log(Level.CONFIG, "一般訊息");<br />
&nbsp;&nbsp;logger.log(Level.CONFIG, "設定方面的訊息");<br />
&nbsp;&nbsp;logger.log(Level.FINE, "細微的訊息");<br />
&nbsp;&nbsp;logger.log(Level.FINER, "更細微的訊息");<br />
&nbsp;&nbsp;logger.log(Level.FINEST, "最細微的訊息");<br />
&nbsp;}<br />
}</p>
<p>4.如何自定义java.util.logging.Formatter</p>
<p>import java.util.logging.*;<br />
public class YAYFormatter extends Formatter<br />
{ <br />
&nbsp;public String format(LogRecord logRecord) <br />
&nbsp;{<br />
&nbsp;&nbsp;return&nbsp; "LogRecord info: " + logRecord.getSourceClassName() +//就是哪个类里面用的了你<br />
&nbsp;&nbsp;&nbsp;"\n" +"Level\t|\tLoggerName\t|\tMessage\t|\n" +<br />
&nbsp;&nbsp;logRecord.getLevel() + //是SEVERE还是WARNING还是别的<br />
&nbsp;&nbsp;&nbsp;&nbsp;"\t|\t" + <br />
&nbsp;&nbsp;&nbsp;logRecord.getLoggerName() +//这个logger发布者<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"\t|\t" + <br />
&nbsp;&nbsp;&nbsp;logRecord.getMessage() + //消息内容<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"\t|\n\n";&nbsp;&nbsp;&nbsp; <br />
&nbsp;}<br />
} </p><img src ="http://www.blogjava.net/xinwuhen/aggbug/184583.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2008-03-07 19:27 <a href="http://www.blogjava.net/xinwuhen/archive/2008/03/07/184583.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>探讨JAR文件无限可能性--转载</title><link>http://www.blogjava.net/xinwuhen/archive/2008/03/07/184422.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Fri, 07 Mar 2008 02:36:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2008/03/07/184422.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/184422.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2008/03/07/184422.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/184422.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/184422.html</trackback:ping><description><![CDATA[<p>所有Java开发者都知道JAR文件只是包含Java类树的压缩（ZIP）文件。但是，不是人人（包括一些经验丰富的开发者）了解这种文件格式的其它优点。在本文中，我将简单介绍JAR文件格式，并说明利用它可以实现的各种可能性。</p>
<p><strong>JAR</strong><strong>文件简介</strong></p>
<p>JAR文件以流行的二进制ZIP文件格式为基础，用以把许多文件合并成一个文件。它还包含一个名为META-INF的可选目录，这个目录位于文件根目录下。</p>
<p>有两种方法可以建立JAR文件：应用<a href="http://java.sun.com/j2se/1.5.0/docs/tooldocs/windows/jar.html" target="_blank">命令行工具jar</a>，或使用Java中的java.util.jar API编程。如果JAR文件包含在Java类路径中，使JVM可看到它，则JAR文件包含Java类和/或可由<a href="http://articles.techrepublic.com.com/5100-3513_11-6080883.html" target="_blank">类加载器</a>运行、使用及加载的资源。</p>
<p>在许多情况下，JAR文件不仅仅是简单的Java类档案文件和/或资源；它们还可用来为应用程序和扩展建立语句块。META-INF目录（如存在）用于存储数据包和扩展配置数据，包括安全、版本、扩展和服务。</p>
<p><strong>META-INF</strong><strong>目录的作用</strong></p>
<p>META-INF目录中的下列文件和目录获得Java 2平台的认可与解释，用来配置应用程序、扩展程序、类加载器和服务：</p>
<ul>
    <li><strong>MANIFEST.MF</strong>：清单文件，用来定义与扩展和数据包相关的数据。
    <li><strong>INDEX.LIST</strong>：这个文件由JAR工具的新&#8220;-i&#8221;选项生成，其中包含在一个应用程序或扩展中定义的数据包的地址信息。它是JarIndex的一部分，被类加载器用来加速类加载过程。
    <li><strong>x.SF</strong>：JAR文件的签名文件。x代表基础文件名。
    <li><strong>x.DSA</strong>：这个签名块文件与同名基础签名文件有关。此文件存储对应签名文件的数字签名。
    <li><strong>services/</strong>：这个目录存储所有服务提供程序配置文件。 </li>
</ul>
<p>下面我们来了解一下每种组合。</p>
<p><strong>清单文件</strong></p>
<p>清单文件由&#8220;AttributeName: Value&#8221;对构成，一个换行符将其划分成两个部分：主要部分和单独部分，这两个被另外一个换行符分开。</p>
<ul>
    <li><strong>主要部分</strong>：这个部分包含JAR文件本身的安全和配置信息，以及此JAR文件构成的应用程序或扩展。它还定义适用于每个单独清单项的主要属性。这个部分没有名为&#8220;Name&#8221;的属性。本部分以一个空行结束。
    <li><strong>单独部分</strong>：这个部分为此JAR文件中包含的数据包或文件定义各种属性。并非所有的JAR文件都必须列举在清单文件中，但必须列出所有签名文件。清单文件本身不得列出。每个部分必须以一个名为&#8220;Name&#8221;的属性开始，它的值必须是一个文件相对路径，或档案文件外的一个绝对URL参考数据。（我将在本文后部分讨论JAR签名。） </li>
</ul>
<p>下面是清单文件最重要的属性：</p>
<ul>
    <li><strong>Manifest-Version</strong>：定义清单文件版本。它的值是一个上面规范描述的合法版本号。
    <li><strong>Created-By</strong>：详细说明生成这个清单文件的Java程序的版本和生产商。这个属性由JAR工具生成。
    <li><strong>Signature-Version</strong>：定义JAR文件的签名版本。该值应为一个有效的版本号字符串。
    <li><strong>Class-Path</strong>：这个属性值指定这个应用程序或扩展需要的扩展或库的相对URL。URL由一个或几个空格分隔。应用程序或扩展类加载器使用这个属性值建立它的内部搜索路径。
    <li><strong>Main-Class</strong>：这个属性用于单机应用程序。这个属性值定义主要应用程序类的相对路径，发射器在启动时会加载这些类。这个属性值不能在类名称后附加.class扩展名。如果你已经指定这个属性，JAR文件即变成可执行文件，应用程序将通过java &#8211;jar x.jar命令自动启动。
    <li><strong>Sealed</strong>：这个属性定义此JAR文件是否被密封。该值可为真或假，且忽略大小写。当JAR文件被密封时，一个可选的数据包可在某个特殊的版本中执行一贯性。在JAR中密封的数据包规定所有在那个数据包中定义的类必须源自相同的JAR；否则，就会产生一个SecurityException。例如，这段代码： </li>
</ul>
<p>Name: javax/servlet/internal/</p>
<p>Sealed: true</p>
<p>说明javax.servlet.internal数据包被密封，且这个数据包中的所有类必须从相同的JAR文件加载。要了解可选数据包的详细内容，请查看<a href="http://java.sun.com/j2se/1.5.0/docs/guide/extensions/spec.html#mechanism" target="_blank">扩展机制</a>。</p>
<p><strong>JAR</strong><strong>签名文件</strong></p>
<p>任何JAR文件都可以通过java.security API，使用命令行<a href="http://java.sun.com/j2se/1.5.0/docs/guide/security/SecurityToolsSummary.html" target="_blank">jarsigner工具</a>或目录进行签名。通过文件签名，你可以保证没人能够改变一个文件的内容，以及你正在使用一个知名厂商的JAR文件。如果JAR文件用jarsigner工具签名，那么每个文件，包括META-INF目录中的相关非签名文件，都将被签名。下面是与签名有关的文件：</p>
<ul>
    <li>META-INF/MANIFEST.MF
    <li>META-INF/*.SF
    <li>META-INF/*.DSA
    <li>META-INF/*.RSA
    <li>META-INF/SIG-* </li>
</ul>
<p>每个签名器由一个扩展名为.SF的签名文件说明，这个文件的主要内容与清单文件相似。它由一个主要部分构成，其中包含由签名器提供的信息，但并不特别针对某个特定的JAR文件。主要部分的项目x-Digest-Manifest-Main-Attributes（这里的x是一个摘要算法）包含清单主要属性的摘要值。</p>
<p>要使一个文件生效，首先将签名文件的一个摘要值与根据清单文件中对应的项目计算的摘要进行比较；然后，再将清单文件中的一个摘要值与根据&#8220;Name：&#8221;属性中的实际引用数据计算的摘要比较。&#8220;Name：&#8221;属性指定一个相对文件路径或RUL。</p>
<p>例如，下面是一个签名JAR的清单文件：</p>
<p>Manifest-Version: 1.0</p>
<p>Created-By: 1.3 (Sun Microsystems, Inc)?br&gt;</p>
<p>Name: common/class1.class</p>
<p>MD5-Digest: (base64 representation of MD5 digest)?br&gt;</p>
<p>Name: common/class2.class</p>
<p>MD5-Digest: (base64 representation of MD5 digest)</p>
<p>SHA-Digest: (base64 representation of SHA digest)</p>
<p>下面是对应的签名：</p>
<p>Signature-Version: 1.0</p>
<p>MD5-Digest-Manifest-Main-Attributes: (base64 representation of MD5 digest)?br&gt;</p>
<p>Name: common/class1.class</p>
<p>MD5-Digest: (base64 representation of MD5 digest)?br&gt;</p>
<p>Name: common/class2.class</p>
<p>MD5-Digest: (base64 representation of MD5 digest)</p>
<p>数字签名是.SF签名文件的一个签名版本。这些是人类无法解译的二进制文件。数字签名文件和.SF文件的名称相同，但扩展名不同。数字签名的类型不同，其扩展名也各不相同，通常为RSA或DSA。</p>
<p><strong>JAR</strong><strong>目录</strong></p>
<p>为优化类加载器在网络应用程序，特别是applet中的类搜索过程，因此引入了JAR目录（一般称作JarIndex机制）。JarIndex机制收集在一个applet中定义的所有JAR文件，并将信息存储在applet的类路径的第一个JAR文件的一个目录文件中。下载第一个JAR文件后，applet类加载器将收集内容信息，这样可提高JAR文件的下载效率。</p>
<p>系统对现有的JAR工具进行强化，使其能够检查一个JAR文件列表，并生成目录信息，说明哪些类和资源位于哪个JAR文件中。这些目录信息存储在根JAR文件META-INF目录中的一个名为INDEX.LIST的简单文本文件中。当类加载器加载根JAR文件时，它阅读INDEX.LIST文件，并用它建立一个由文件和数据包名称到JAR文件名列表的映射散列表。为了找到一个类或资源，类加载器查询散列表找到正确的JAR文件，如有必要，再下载这个文件。</p>
<p><strong>提供服务</strong></p>
<p>META-INF/services目录中的文件为服务提供程序配置文件。一个服务通常是一组著名的界面和（一般是抽象的）类。一个服务提供程序是一项服务的特殊执行过程。提供程序中的类往往执行上述界面并继承服务本身定义的类。</p>
<p>服务提供程序通过把一个提供程序配置文件放在META-INF/services源目录中来识别自己。这个文件名应由完全合格的抽象服务类名称构成。</p>
<p><strong>应用这些特性</strong></p>
<p>了解JAR文件的这些特性后，你就可以在实际开发工作中创造性的应用它们。如果你已经有了一些有趣的使用方法，请在文章的讨论部分分享你的经验。</p>
<hr />
<p>Peter V. Mikhalenko是一名通过Sun认证的专家，现在任德意志银行商业顾问。<em>&nbsp;</em></p>
<hr />
<p>责任编辑：德东</p>
<img src ="http://www.blogjava.net/xinwuhen/aggbug/184422.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2008-03-07 10:36 <a href="http://www.blogjava.net/xinwuhen/archive/2008/03/07/184422.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>揭密J2EE项目开发的70个问题---转载</title><link>http://www.blogjava.net/xinwuhen/archive/2008/03/02/183320.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Sun, 02 Mar 2008 14:56:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2008/03/02/183320.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/183320.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2008/03/02/183320.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/183320.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/183320.html</trackback:ping><description><![CDATA[今天看了人民邮电出版社的《揭密J2EE项目开发的70个问题》，感觉讲解的非常好。把其中的问题都抄下来，看看大家对这些问题都是否特别清楚。<br />
呵呵～就算给大家一个考试的机会～呵呵。<br />
<br />
问题：选择怎样的开发模式<br />
问题：B/S还是C/S<br />
问题：如何谈需求<br />
问题：如何设计用例<br />
问题：分析师如何看用例<br />
问题：如何管理软件需求<br />
问题：需求管理和开发<br />
问题：软件需求之验证和评审<br />
问题：软件需求之风险管理<br />
问题：软件需求之变更和需求跟踪<br />
问题：软件需求之软件过程改进<br />
问题：找谁来调研<br />
问题：获取需求的沟通途径<br />
问题：需求获取的注意事项<br />
问题：沟通的基本技巧<br />
问题：UML模型图各有什么意义<br />
问题：什么是分析建模<br />
问题：如何搭建业务对象模型<br />
问题：如何搭建分析模型<br />
问题：分析的经验之谈<br />
问题：解决问题的基本方法<br />
问题：Business Analysis 的存在<br />
问题：如何寻找参与者<br />
问题：文档化参与者<br />
问题：如何寻找用例<br />
问题：文档化用例<br />
问题：用例设计技巧与注意事项<br />
问题：类图与关系<br />
问题：什么是设计模型<br />
问题：UML建模技巧之通用篇<br />
问题：UML建模技巧之具体篇<br />
问题：如何定义方法调用双方的义务和权利<br />
问题：抛出Checked Exception还是Runtime Exception<br />
问题：如何及时释放资源<br />
问题：怎样使用正则表达式验证数据有效性<br />
问题：Struts的ActionForm与类型<br />
问题：Struts如何工作<br />
问题：ActionForm与Struts标签库<br />
问题：如何使用Struts标签之选择框<br />
问题：如何使用Struts标签之下拉框<br />
问题：JSTL和Struts标签的整合<br />
问题：页面输入乱码的解决方案<br />
问题：如何使用AJAX构建响应快速的动态Web页面<br />
问题：如何使用AJAX构建响应快速的动态Web页面（续）<br />
问题：如何响应AJAX请求<br />
问题：AJAX的常见应用场景<br />
问题：可否使用Serializable实现持久化<br />
问题：选择怎样的方式来实现持久层<br />
问题：连接表的困惑<br />
问题：如何使用临时表<br />
问题：DAO模式是否需要接口<br />
问题：选择最好的分页方式<br />
问题：可以使用存储过程吗<br />
问题：怎样解决大批量数据的条件<br />
问题：Hibernate中的实体状态<br />
问题：Hibernate单、双向关联与inverse属性<br />
问题：在Hibernate中配置连接表<br />
问题：Spring如何支持JDBC<br />
问题：Spring如何支持IBatis<br />
问题：Spring如何支持Hibernate<br />
问题：Spring发布包的基本构成元素有哪些<br />
问题：怎么理解控制反转<br />
问题：怎么理解依赖注入<br />
问题：如何使用Bean Factory<br />
问题：如何装配各种Bean并使它们协作<br />
问题：如何使用ApplicationContext<br />
问题：如何使用Spring验证器<br />
问题：如何使用Spring发送E-mail<br />
问题：如何使用Spring Web MVC框架<br />
问题：Spring如何集成Struts<img src ="http://www.blogjava.net/xinwuhen/aggbug/183320.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2008-03-02 22:56 <a href="http://www.blogjava.net/xinwuhen/archive/2008/03/02/183320.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDK中的URLConnection使用总结--原创</title><link>http://www.blogjava.net/xinwuhen/archive/2008/03/01/183159.html</link><dc:creator>心无痕</dc:creator><author>心无痕</author><pubDate>Sat, 01 Mar 2008 09:37:00 GMT</pubDate><guid>http://www.blogjava.net/xinwuhen/archive/2008/03/01/183159.html</guid><wfw:comment>http://www.blogjava.net/xinwuhen/comments/183159.html</wfw:comment><comments>http://www.blogjava.net/xinwuhen/archive/2008/03/01/183159.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.blogjava.net/xinwuhen/comments/commentRss/183159.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xinwuhen/services/trackbacks/183159.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/xinwuhen/archive/2008/03/01/183159.html'>阅读全文</a><img src ="http://www.blogjava.net/xinwuhen/aggbug/183159.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xinwuhen/" target="_blank">心无痕</a> 2008-03-01 17:37 <a href="http://www.blogjava.net/xinwuhen/archive/2008/03/01/183159.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>