﻿<?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-semovy-文章分类-J2EE综合</title><link>http://www.blogjava.net/WshmAndLily/category/16311.html</link><description /><language>zh-cn</language><lastBuildDate>Thu, 14 Feb 2008 17:19:41 GMT</lastBuildDate><pubDate>Thu, 14 Feb 2008 17:19:41 GMT</pubDate><ttl>60</ttl><item><title>Log4j简介</title><link>http://www.blogjava.net/WshmAndLily/articles/179612.html</link><dc:creator>semovy</dc:creator><author>semovy</author><pubDate>Mon, 11 Feb 2008 08:22:00 GMT</pubDate><guid>http://www.blogjava.net/WshmAndLily/articles/179612.html</guid><wfw:comment>http://www.blogjava.net/WshmAndLily/comments/179612.html</wfw:comment><comments>http://www.blogjava.net/WshmAndLily/articles/179612.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/WshmAndLily/comments/commentRss/179612.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/WshmAndLily/services/trackbacks/179612.html</trackback:ping><description><![CDATA[<h1><font color="#008000"><font size="+0"><font size="+0">第1章.</font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font size="+0">Log4j </font></font><font size="+0">的优点</font></font></h1>
<br />
<font size="+0">Log4j</font>是<font size="+0">Apache</font>的一个开放源代码项目，通过使用<font size="+0">Log4j</font>，我们可以控制日志信息输送的；我们也可以控制每一条日志的输出格式；通过定义每一条日志信息的级别，我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是，这些可以通过一个配置文件来灵活地进行配置，而不需要修改应用的代码。 <br />
<font size="+0">log4j</font>的好处在于： <br />
<font size="+0">1)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>通过修改配置文件，就可以决定<font size="+0">log</font>信息的目的地——控制台、文件、<font size="+0">GUI</font>组件、甚至是套接口服务器、<font size="+0">NT</font>的事件记录器、<font size="+0">UNIX Syslog</font>守护进程等 <br />
<font size="+0">2)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>通过修改配置文件，可以定义每一条日志信息的级别，从而控制是否输出。在系统开发阶段可以打印详细的<font size="+0">log</font>信息以跟踪系统运行情况<font size="+0">,</font>而在系统稳定后可以关闭<font size="+0">log</font>输出<font size="+0">,</font>从而在能跟踪系统运行情况的同时<font size="+0">,</font>又减少了垃圾代码（<font size="+0">System.out.println(</font>......<font size="+0">)</font>等<font size="+0">)</font>。 <br />
<font size="+0">3)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>使用<font size="+0">log4j</font>，需要整个系统有一个统一的<font size="+0">log</font>机制，有利于系统的规划。 <br />
<h1><font color="#008000"><font size="+0"><font size="+0">第2章.</font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font size="+0">配置文件</font></font></h1>
<br />
<font size="+0">Log4j</font>由三个重要的组件构成：日志信息的优先级，日志信息的输出目的地，日志信息的输出格式。日志信息的优先级从高到低有<font size="+0">FATAL</font>、<font size="+0">ERROR</font>、<font size="+0">WARN</font>、<font size="+0">INFO</font>、<font size="+0">DEBUG</font>，分别用来指定这条日志信息的重要程度；日志信息的输出目的地指定了日志将打印到控制台还是文件中；而输出格式则控制了日志信息的显示内容。
<h2><font size="+0">2.1.</font>&nbsp;&nbsp;&nbsp; 日志信息的优先级</h2>
<br />
分为<font size="+0">OFF</font>、<font size="+0">FATAL</font>、<font size="+0">ERROR</font>、<font size="+0">WARN</font>、<font size="+0">INFO</font>、<font size="+0">DEBUG</font>、<font size="+0">ALL</font>或者您定义的级别。 <br />
<font size="+0">Log4j</font>建议只使用四个级别，优先级从高到低分别是<font size="+0">ERROR</font>、<font size="+0">WARN</font>、<font size="+0">INFO</font>、<font size="+0">DEBUG</font>。通过在这里定义的级别，您可以控制到应用程序中相应级别的日志信息的开关。 <br />
假如在一个级别为<font size="+0">q</font>的<font size="+0">Logger</font>中发生一个级别为<font size="+0">p</font>的日志请求，如果<font size="+0">p&gt;=q,</font>那么请求将被启用。这是<font size="+0">Log4j</font>的核心原则。 <br />
比如在这里定义了<font size="+0">INFO</font>级别，则应用程序中所有<font size="+0">DEBUG</font>级别的日志信息将不被打印出来； <br />
<h2><font size="+0">2.2.</font>&nbsp;&nbsp;&nbsp; 输出源的使用</h2>
<br />
有选择的能用或者禁用日志请求仅仅是<font size="+0">Log4j</font>的一部分功能。<font size="+0">Log4j</font>允许日志请求被输出到多个输出源。用<font size="+0">Log4j</font>的话说，一个输出源被称做一个<font size="+0">Appender</font>。 <br />
<font size="+0">Appender</font>包括<font size="+0">console</font>（控制台）<font size="+0">, files</font>（文件）<font size="+0">, GUI components</font>（图形的组件）<font size="+0">, remote socket servers</font>（<font size="+0">socket </font>服务）<font size="+0">, JMS</font>（<font size="+0">java</font>信息服务）<font size="+0">, NT Event Loggers</font>（<font size="+0">NT</font>的事件日志）<font size="+0">, and remote UNIX Syslog daemons</font>（远程<font size="+0">UNIX</font>的后台日志服务）。它也可以做到异步记录。 <br />
一个<font size="+0">logger</font>可以设置超过一个的<font size="+0">appender</font>。 <br />
用<font size="+0">addAppender </font>方法添加一个<font size="+0">appender</font>到一个给定的<font size="+0">logger</font>。对于一个给定的<font size="+0">logger</font>它每个生效的日志请求都被转发到该<font size="+0">logger</font>所有的<font size="+0">appender</font>上和该<font size="+0">logger</font>的父辈<font size="+0">logger</font>的<font size="+0">appender</font>上。
<h3><font size="+0"><font size="+0">2.2.1.</font>&nbsp;&nbsp;<font size="+0">ConsoleAppender</font></font></h3>
<br />
如果使用<font size="+0">ConsoleAppender</font>，那么<font size="+0">log</font>信息将写到<font size="+0">Console</font>。效果等同于直接把信息打印到<font size="+0">System.out</font>上了。
<h3><font size="+0"><font size="+0">2.2.2.</font>&nbsp;&nbsp;<font size="+0">FileAppender</font></font></h3>
<br />
使用<font size="+0">FileAppender</font>，那么<font size="+0">log</font>信息将写到指定的文件中。这应该是比较经常使用到的情况。 <br />
相应地，在配置文件中应该指定<font size="+0">log</font>输出的文件名。如下配置指定了<font size="+0">log</font>文件名为dglog.<font size="+0">txt</font> <br />
<font size="+0">log4j.appender.A2.File=dglog.txt</font> <br />
注意将<font size="+0">A2</font>替换为具体配置中<font size="+0">Appender</font>的别名。
<h3><font size="+0"><font size="+0">2.2.3.</font>&nbsp;&nbsp;<font size="+0">DailyRollingAppender</font></font></h3>
<br />
使用<font size="+0">FileAppender</font>可以将<font size="+0">log</font>信息输出到文件中，但是如果文件太大了读起来就不方便了。这时就可以使用<font size="+0">DailyRollingAppender</font>。<font size="+0">DailyRollingAppender</font>可以把<font size="+0">Log</font>信息输出到按照日期来区分的文件中。配置文件就会每天产生一个<font size="+0">log</font>文件，每个<font size="+0">log</font>文件只记录当天的<font size="+0">log</font>信息： <br />
<font size="+0">log4j.appender.A2=org.apache.log4j.DailyRollingFileAppender</font> <br />
<font size="+0">log4j.appender.A2.file=dglog</font> <br />
<font size="+0">log4j.appender.A2.DatePattern='.'yyyy-MM-dd</font> <br />
<font size="+0">log4j.appender.A2.layout=org.apache.log4j.PatternLayout</font> <br />
<font size="+0">log4j.appender.A2.layout.ConversionPattern= %5r %-5p %c{2} - %m%n</font>
<h3><font size="+0"><font size="+0">2.2.4.</font>&nbsp;&nbsp;<font size="+0">org.apache.log4j.RollingFileAppender</font></font></h3>
<br />
文件大小到达指定尺寸的时候产生一个新的文件。 <br />
<font size="+0">log4j.appender.R=org.apache.log4j.RollingFileAppender</font> <br />
<font size="+0">log4j.appender.R.File= ../logs/dglog.log</font> <br />
<font size="+0"># Control the maximum log file size</font> <br />
<font size="+0">log4j.appender.R.MaxFileSize=100KB</font> <br />
<font size="+0"># Archive log files (one backup file here)</font> <br />
<font size="+0">log4j.appender.R.MaxBackupIndex=1</font> <br />
<font size="+0">log4j.appender.R.layout=org.apache.log4j.PatternLayout</font> <br />
<font size="+0">log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n</font> <font size="+0"><font size="+0"><br />
这个配置文件指定了输出源<font size="+0">R</font>，是一个轮转日志文件。最大的文件是<font size="+0">100KB</font>，当一个日志文件达到最大尺寸时，<font size="+0">Log4J</font>会自动把<font size="+0">example.log</font>重命名为dglog<font size="+0">.log.1</font>，然后重建一个新的<font size="+0">dglog.log</font>文件，依次轮转。 <br />
<h3><font size="+0"><font size="+0">2.2.5.</font>&nbsp;&nbsp;<font size="+0">org.apache.log4j.WriterAppender</font></font></h3>
<br />
将日志信息以流格式发送到任意指定的地方。 <br />
<font size="+0">
<h2><font size="+0">2.3.</font>&nbsp;&nbsp;<font size="+0">Layout</font>的配置</h2>
<br />
<font size="+0">Layout</font>指定了<font size="+0">log</font>信息输出的样式。
<h3><font size="+0"><font size="+0">2.3.1.</font>&nbsp;&nbsp;</font><font size="+0">布局样式</font></h3>
<br />
<font size="+0">org.apache.log4j.HTMLLayout</font>（以<font size="+0">HTML</font>表格形式布局）， <br />
<font size="+0">org.apache.log4j.PatternLayout</font>（可以灵活地指定布局模式）， <br />
<font size="+0">org.apache.log4j.SimpleLayout</font>（包含日志信息的级别和信息字符串）， <br />
<font size="+0">org.apache.log4j.TTCCLayout</font>（包含日志产生的时间、线程、类别等等信息）
<h3><font size="+0"><font size="+0">2.3.2.</font>&nbsp;&nbsp;</font><font size="+0">格式</font></h3>
<br />
<font size="+0">%m </font>输出代码中指定的消息<font size="+0"> </font><br />
<font size="+0">%p </font>输出优先级，即<font size="+0">DEBUG</font>，<font size="+0">INFO</font>，<font size="+0">WARN</font>，<font size="+0">ERROR</font>，<font size="+0">FATAL </font><br />
<font size="+0">%r </font>输出自应用启动到输出该<font size="+0">log</font>信息耗费的毫秒数<font size="+0"> </font><br />
<font size="+0">%c </font>输出所属的类目，通常就是所在类的全名<font size="+0"> </font><br />
<font size="+0">%t </font>输出产生该日志事件的线程名<font size="+0"> </font><br />
<font size="+0">%n </font>输出一个回车换行符，<font size="+0">Windows</font>平台为"<font size="+0">rn</font>"，<font size="+0">Unix</font>平台为"<font size="+0">n</font>"<font size="+0"> </font><br />
<font size="+0">%d </font>输出日志时间点的日期或时间，默认格式为<font size="+0">ISO8601</font>，也可以在其后指定格式，比如：<font size="+0">%d{yyy MMM dd HH:mm:ss,SSS}</font>，输出类似：<font size="+0">2002</font>年<font size="+0">10</font>月<font size="+0">18</font>日<font size="+0"> 22</font>：<font size="+0">10</font>：<font size="+0">28</font>，<font size="+0">921 </font><br />
<font size="+0">%l </font>输出日志事件的发生位置，包括类目名、发生的线程，以及在代码中的行数。举例：<font size="+0">Testlog4.main(Test Log4.java:10)</font> <br />
<h3><font size="+0"><font size="+0">2.3.3.</font>&nbsp;&nbsp;</font><font size="+0">例子</font></h3>
<br />
例子<font size="+0">1</font>：显示日期和<font size="+0">log</font>信息 <br />
<font size="+0">log4j.appender.A2.layout=org.apache.log4j.PatternLayout</font> <br />
<font size="+0">log4j.appender.A2.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %m%n</font> <br />
打印的信息是： <br />
<font size="+0">2002-11-12 11:49:42,866 SELECT * FROM Role WHERE 1=1 order by createDate desc</font> <br />
<br />
例子<font size="+0">2</font>：显示日期，<font size="+0">log</font>发生地方和<font size="+0">log</font>信息 <br />
<font size="+0">log4j.appender.A2.layout=org.apache.log4j.PatternLayout</font> <br />
<font size="+0">log4j.appender.A2.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %l "#" %m%n</font> <br />
<font size="+0">2002-11-12 11:51:46,313 cn.net.unet.weboa.system.dao.RoleDAO.select(RoleDAO.java:409) "#" </font><br />
<font size="+0">SELECT * FROM Role WHERE 1=1 order by createDate desc </font><br />
&nbsp;&nbsp;<br />
例子<font size="+0">3</font>：显示<font size="+0">log</font>级别<font size="+0">,</font>时间<font size="+0">,</font>调用方法<font size="+0">,log</font>信息 <br />
<font size="+0">log4j.appender.A2.layout=org.apache.log4j.PatternLayout</font> <br />
<font size="+0">log4j.appender.A2.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} </font><br />
<font size="+0">method:%l%n%m%n</font> <br />
<font size="+0">log</font>信息<font size="+0">:</font> <br />
<font size="+0">[DEBUG] 2002-11-12 12:00:57,376 </font><br />
<font size="+0">method:cn.net.unet.weboa.system.dao.RoleDAO.select(RoleDAO.java:409)</font> <br />
<font size="+0">SELECT * FROM Role WHERE 1=1 order by createDate desc</font> <br />
<h2><font size="+0">2.4.</font>&nbsp;&nbsp;&nbsp; 配置文件的例子<font size="+0">:</font></h2>
<br />
<font size="+0">log4j.rootLogger=DEBUG</font> <br />
<font size="+0">#</font>将<font size="+0">DAO</font>层<font size="+0">log</font>记录到<font size="+0">DAOLog,allLog</font>中 <br />
<font size="+0">log4j.logger.DAO=DEBUG,A2,A4</font> <br />
<font size="+0">#</font>将逻辑层<font size="+0">log</font>记录到<font size="+0">BusinessLog,allLog</font>中 <br />
<font size="+0">log4j.logger.Businesslog=DEBUG,A3,A4</font> <br />
<br />
<font size="+0">#A1--</font>打印到屏幕上 <br />
<font size="+0">log4j.appender.A1=org.apache.log4j.ConsoleAppender</font> <br />
<font size="+0">log4j.appender.A1.layout=org.apache.log4j.PatternLayout</font> <br />
<font size="+0">log4j.appender.A1.layout.ConversionPattern=%-5p [%t] %37c %3x - %m%n</font> <br />
<br />
<font size="+0">#A2--</font>打印到文件<font size="+0">DAOLog</font>中<font size="+0">--</font>专门为<font size="+0">DAO</font>层服务 <br />
<font size="+0">log4j.appender.A2=org.apache.log4j.DailyRollingFileAppender</font> <br />
<font size="+0">log4j.appender.A2.file=DAOLog</font> <br />
<font size="+0">log4j.appender.A2.DatePattern='.'yyyy-MM-dd</font> <br />
<font size="+0">log4j.appender.A2.layout=org.apache.log4j.PatternLayout</font> <br />
<font size="+0">log4j.appender.A2.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} </font><br />
<font size="+0">method:%l%n%m%n</font> <br />
<br />
<font size="+0">#A3--</font>打印到文件<font size="+0">BusinessLog</font>中<font size="+0">--</font>专门记录逻辑处理层服务<font size="+0">log</font>信息 <br />
<font size="+0">log4j.appender.A3=org.apache.log4j.DailyRollingFileAppender</font> <br />
<font size="+0">log4j.appender.A3.file=BusinessLog</font> <br />
<font size="+0">log4j.appender.A3.DatePattern='.'yyyy-MM-dd</font> <br />
<font size="+0">log4j.appender.A3.layout=org.apache.log4j.PatternLayout</font> <br />
<font size="+0">log4j.appender.A3.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} </font><br />
<font size="+0">method:%l%n%m%n</font> <br />
<br />
<font size="+0">#A4--</font>打印到文件<font size="+0">alllog</font>中<font size="+0">--</font>记录所有<font size="+0">log</font>信息 <br />
<font size="+0">log4j.appender.A4=org.apache.log4j.DailyRollingFileAppender</font> <br />
<font size="+0">log4j.appender.A4.file=alllog</font> <br />
<font size="+0">log4j.appender.A4.DatePattern='.'yyyy-MM-dd</font> <br />
<font size="+0">log4j.appender.A4.layout=org.apache.log4j.PatternLayout</font> <br />
<font size="+0">log4j.appender.A4.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} </font><br />
<font size="+0">method:%l%n%m%n</font> <br />
<br />
<h1><font color="#008000"><font size="+0"><font size="+0">第3章.</font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font size="+0">API</font></font><font size="+0">使用</font></font></h1>
<br />
<font size="+0">log4j</font>使用步骤有<font size="+0">3</font>个：
<h2><font size="+0">3.1.</font>&nbsp;&nbsp;&nbsp; 初始化</h2>
<h3><font size="+0"><font size="+0">3.1.1.</font>&nbsp;&nbsp;<font size="+0">Tomcat</font></font><font size="+0">下的初始化</font></h3>
<br />
默认的<font size="+0">Log4j initialization</font>典型的应用是在<font size="+0">web-server </font>环境下。在<font size="+0">tomcat3.x</font>和<font size="+0">tomcat4.x</font>下，你应该将配置文件<font size="+0">Log4j.properties</font>放在你的<font size="+0">web</font>应用程序的<font size="+0">WEB-INF/classes </font>目录下。 <br />
<font size="+0">Log4j</font>将发现属性文件，并且以此初始化。这是使它工作的最容易的方法。 <br />
你也可以选择在运行<font size="+0">tomcat</font>前设置系统属性<font size="+0">Log4j.configuration </font>。对于<font size="+0">tomcat 3.x</font>，<font size="+0">TOMCAT_OPTS </font>系统变量是用来设置命令行的选项。对于<font size="+0">tomcat4.0</font>，用系统环境变量<font size="+0">CATALINA_OPTS </font>代替了<font size="+0">TOMCAT_OPTS</font>。 <br />
<font size="+0">UNIX </font>命令行 <br />
<font size="+0">export TOMCAT_OPTS="-DLog4j.configuration=foobar.txt"</font> <br />
告诉<font size="+0">Log4j</font>用文件<font size="+0">foobar.txt</font>作为默认的配置文件。这个文件应该放在<font size="+0">WEB-INF/classes </font>目录下。这个文件将被<font size="+0">PropertyConfigurator</font>所读。每个<font size="+0">web-application</font>将用不同的默认配置文件，因为每个文件是和它的<font size="+0">web-application </font>相关的。 <br />
1. <font size="+0">export TOMCAT_OPTS="-DLog4j.debug -DLog4j.configuration=foobar.xml"</font> <font size="+0">export TOMCAT_OPTS="-DLog4j.debug -DLog4j.configuration=foobar.xml"</font> <br />
告诉<font size="+0">Log4j</font>输出<font size="+0">Log4j-internal</font>的调试信息，并且用<font size="+0">foobar.xml</font>作为默认的配置文件。这个文件应该放在你的<font size="+0">web-application</font>的<font size="+0">WEB-INF/classes </font>目录下。因为有<font size="+0">.xml</font>的扩展名，它将被<font size="+0">DOMConfigurator</font>所读。每个<font size="+0">web-application</font>将用不同的默认配置文件。因为每个文件都和它所在的<font size="+0">web-application </font>相关的。 <br />
<font size="+0">2. set TOMCAT_OPTS=-DLog4j.configuration=foobar.lcf </font><br />
<font size="+0">-DLog4j.configuratorClass=com.foo.BarConfigurator</font> <br />
告诉<font size="+0">Log4j</font>用文件<font size="+0">foobar.lcf</font>作为默认的配置文件。这个文件应该放在你的<font size="+0">web-application</font>的<font size="+0">WEB-INF/classes </font>目录下。因为定义了<font size="+0">Log4j.configuratorClass </font>系统属性，文件将用自定义的<font size="+0">com.foo.barconfigurator</font>类来解析。每个<font size="+0">web-application</font>将用不同的默认配置文件。因为每个文件都和它所在的<font size="+0">web-application </font>相关的。 <br />
<font size="+0">3. </font><font size="+0">set TOMCAT_OPTS=-DLog4j.configuration=file:/c:/foobar.lcf</font> <font size="+0">set TOMCAT_OPTS=-DLog4j.configuration=file:/c:/foobar.lcf</font> <br />
告诉<font size="+0">Log4j</font>用文件<font size="+0">foobar.lcf</font>作为默认的配置文件。这个配置文件用<font size="+0">URL file:/c:/foobar.lcf</font>定义了全路径名。这样同样的配置文件将被所有的<font size="+0">web-application</font>所用。 <br />
不同的<font size="+0">web-application</font>将通过它们自己的类装载器来装载<font size="+0">Log4j</font>。这样，每个<font size="+0">Log4j</font>的环境将独立的运作，而没有任何的相互同步。例如：在多个<font size="+0">web-application</font>中定义了完全相同的输出源的<font size="+0">FileAppenders</font>将尝试写同样的文件。结果好象是缺乏安全性的。你必须确保每个不同的<font size="+0">web-application</font>的<font size="+0">Log4j</font>配置没有用到同样的系统资源。
<h3><font size="+0"><font size="+0">3.1.2.</font>&nbsp;&nbsp;<font size="+0">Servlet </font></font><font size="+0">的初始化</font></h3>
<br />
用一个特别的<font size="+0">servlet</font>来做<font size="+0">Log4j</font>的初始化也是可以的。如下是一个例子： <br />
<font size="+0">public class Log4jInit extends HttpServlet {</font> <br />
<font size="+0">public void init() {</font> <br />
<font size="+0">String prefix = getServletContext().getRealPath("/");</font> <br />
<font size="+0">String file = getInitParameter("Log4j-init-file");</font> <br />
<font size="+0">if(file != null) {</font> <br />
<font size="+0">PropertyConfigurator.configure(prefix+file);</font> <br />
<font size="+0">}</font> <br />
<font size="+0">}</font> <br />
<font size="+0">public void doGet(HttpServletRequest req, HttpServletResponse res) {</font> <br />
<font size="+0">}</font> <br />
<font size="+0">}</font> <br />
<br />
在<font size="+0">web.xml</font>中定义随后的<font size="+0">servlet</font>为你的<font size="+0">web-application</font>。 <br />
<font size="+0">&lt;servlet&gt;</font> <br />
<font size="+0">&lt;servlet-name&gt;Log4j-init&lt;/servlet-name&gt;</font> <br />
<font size="+0">&lt;servlet-class&gt;xx.xx.Log4jInit&lt;/servlet-class&gt;</font> <br />
<font size="+0">&lt;init-param&gt;</font> <br />
<font size="+0">&lt;param-name&gt;Log4j-init-file&lt;/param-name&gt;</font> <br />
<font size="+0">&lt;param-value&gt;WEB-INF/classes/Log4j.properties&lt;/param-value&gt;</font> <br />
<font size="+0">&lt;/init-param&gt;</font> <br />
<font size="+0">&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;</font> <br />
<font size="+0">&lt;/servlet&gt;</font> <br />
写一个初始化的<font size="+0">servlet</font>是最有弹性的初始化<font size="+0">Log4j</font>的方法。代码中没有任何限制，你可以在<font size="+0">servlet</font>的<font size="+0">init</font>方法中定义它。
<h2><font size="+0">3.2.</font>&nbsp;&nbsp;&nbsp; 根据配置文件初始化<font size="+0">log4j</font></h2>
<br />
<font size="+0">log4j</font>可以使用<font size="+0">3</font>中配置器来初始化：<font size="+0">BasicConfigurator,DOMConfigurator,PropertyConfigurator</font> <br />
其语法为： <br />
<font size="+0">BasicConfigurator.configure ()</font>：<font size="+0"> </font>自动快速地使用缺省<font size="+0">Log4j</font>环境。 <br />
<font size="+0">PropertyConfigurator.configure ( String configFilename) </font>：读取使用<font size="+0">Java</font>的特性文件编写的配置文件。 <br />
<font size="+0">DOMConfigurator.configure ( String filename ) </font>：读取<font size="+0">XML</font>形式的配置文件。 <br />
这里用的是<font size="+0">PropertyConfigurator</font>。使用<font size="+0">PropertyConfigurator</font>适用于所有的系统。如下的语句： <br />
<font size="+0">PropertyConfigurator.configure("log4j.properties");</font> <br />
就以<font size="+0">log4j.properties</font>为配置文件初始化好了<font size="+0">log4j</font>环境。 <br />
注意一点：这个语句只需要在系统启动的时候执行一次。例如，在<font size="+0">ActionServlet</font>的<font size="+0">init()</font>方法中调用一次。 <br />
<font size="+0">public class ActionServlet extends HttpServlet{</font> <br />
<font size="+0">...</font> <br />
<font size="+0">/**</font> <br />
<font size="+0">* Initialize global variables</font> <br />
<font size="+0">*/</font> <br />
<font size="+0">public void init() throws ServletException {</font> <br />
<font size="+0">// </font>初始化<font size="+0">Action</font>资源 <br />
<font size="+0">try{</font> <br />
<font size="+0">initLog4j();</font> <br />
<font size="+0">...</font> <br />
<font size="+0">}catch(IOException e){</font> <br />
<font size="+0">throw new ServletException("Load ActionRes is Error");</font> <br />
<font size="+0">}</font> <br />
<font size="+0">}</font> <br />
<font size="+0">...</font> <br />
<font size="+0">protected void initLog4j(){</font> <br />
<font size="+0">PropertyConfigurator.configure("log4j.properties");</font> <br />
<font size="+0">}</font> <br />
<font size="+0">...</font> <br />
<font size="+0">}//end class ActionServlet</font> <br />
<h2><font size="+0">3.3.</font>&nbsp;&nbsp;&nbsp; 在需要使用<font size="+0">log4j</font>的地方获取<font size="+0">Logger</font>实例</h2>
<br />
使用<font size="+0">Log4j</font>，首先就是获取日志记录器，这个记录器将负责控制日志信息。其语法为： <br />
<font size="+0">public static Logger getLogger( String name)</font>， <br />
通过指定的名字获得记录器，如果必要的话，则为这个名字创建一个新的记录器。<font size="+0">Name</font>一般取本类的名字，比如： <br />
<font size="+0">static Logger logger = Logger.getLogger ( ServerWithLog4j.class.getName () ) ;</font> <br />
<font size="+0">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Log4j</font>使得通过软件组件命名<font size="+0">logger</font>很容易。我们可以通过<font size="+0">Logger</font>的静态的初始化方法在每一个类里定义一个<font size="+0">logger</font>，令<font size="+0">logger</font>的名字等于类名的全局名，而实现<font size="+0">logger</font>的命名。这是一个实效的简单的定义一个<font size="+0">logger</font>的方法。因为日志输出带有产生日志的类的名字，这个命名策略使得我们更容易定位到一个日志信息的来源。虽然普通，但却是命名<font size="+0">logger</font>的常用策略之一。 <br />
<font size="+0">Log4j</font>没有限制定义<font size="+0">logger</font>的可能。开发员可以自由的按照它们的意愿定义<font size="+0">logger</font>的名称。 <br />
然而，以类的所在位置来命名<font size="+0">Logger</font>好象是目前已知的最好方法。 <br />
<h2><font size="+0">3.4.</font>&nbsp;&nbsp;&nbsp; 使用<font size="+0">Logger</font>对象的<font size="+0">debug,info,fatal...</font>方法</h2>
<br />
<font size="+0">log.debug("it is the debug info");</font> <br />
<h1><font color="#008000"><font size="+0"><font size="+0">第4章.</font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font size="+0">优化</font></font></h1>
<br />
一个经常引用的依靠于<font size="+0">logging</font>的参数是可以计算的花费。这是一个合理的概念，一个适度的应用程序可能产生成千上万个日志请求。许多努力花在测量和调试<font size="+0">logging</font>的优化上。<font size="+0">Log4j</font>要求快速和弹性：速度最重要，弹性是其次。
<h2><font size="+0">4.1.</font>&nbsp;&nbsp;&nbsp; 日志为禁用时，日志的优化。</h2>
<br />
当日志被彻底的关闭，一个日志请求的花费等于一个方法的调用加上整数的比较时间。在<font size="+0">233mhz</font>的<font size="+0">Pentium II </font>机器上这个花费通常在<font size="+0">5-50</font>纳秒之间。 <br />
然而，方法调用包括参数构建的隐藏花费。 <br />
例如，对于<font size="+0">logger cat</font>，<font size="+0">logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));</font> <br />
引起了构建信息参数的花费，例如，转化整数<font size="+0">i</font>和<font size="+0">entry[i]</font>到一个<font size="+0">string</font>，并且连接中间字符串，不管信息是否被输出。这个参数的构建花费可能是很高，它主要决定于被调用的参数的大小。 <br />
避免参数构建的花费应如下，
<div twffan="done"><br />
<font color="#000080">if(logger.isDebugEnabled())</font> <br />
<font color="#000080">{</font> <br />
<font size="+0"><font color="#000080"><font size="+0">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.debug("result is" + result );</font></font></font> <br />
<font color="#000080">}</font> </div>
<br />
如果<font size="+0">logger</font>的<font size="+0">debug</font>被关闭这将不会招致参数构建的花费。另一方面，如果<font size="+0">logger</font>是<font size="+0">debug</font>的话，它将产生两次判断<font size="+0"> logger</font>是否能用的花费。一次是在<font size="+0">debugenabled</font>，一次是<font size="+0">debug</font>。这是无关紧要的，因为判断日志的能用<font size="+0"> </font>只占日志实际花费时间的约<font size="+0">1%</font>。 <br />
在<font size="+0">Log4j</font>里，日志请求在<font size="+0">Logger </font>类的实例里。<font size="+0">Logger </font>是一个类，而不是一个接口。这大量的减少了在方法调用上的弹性化的花费。 <br />
当然用户采用预处理或编译时间技术去编译出所有的日志声明。这将导致完美的执行成效。然而因为二进制应用程序不包括任何的日志声明的结果，日志不可能对那个二进制程序开启。以我的观点，以这种较大的代价来换取较小的性能优化是不值得的。 <br />
<h2><font size="+0">4.2.</font>&nbsp;&nbsp;&nbsp; 当日志状态为启用时，日志的优化。</h2>
<br />
这是本质上的优化<font size="+0">logger</font>的层次。当日志状态为开，<font size="+0">Log4j</font>依然需要比较请求的级别与<font size="+0">logger</font>的级别。然而，<font size="+0"> logger</font>可能没有被安排一个级别；它们将从它们的<font size="+0">father</font>继承。这样，在继承之前，<font size="+0">logger</font>可能需要搜索它的<font size="+0">ancestor</font>。 <br />
这里有一个认真的努力使层次的搜索尽可能的快。例如，子<font size="+0">logger</font>仅仅连接到它的存在的<font size="+0">father logger</font>。 <br />
在先前展示的<font size="+0">BasicConfigurator </font>例子中，名为<font size="+0">com.foo.bar </font>的<font size="+0">logger</font>是连接到跟根<font size="+0">logger</font>，因此绕过<font size="+0"> </font>了不存在的<font size="+0">logger com</font>和<font size="+0">com.foo</font>。这将显著的改善执行的速度，特别是解析<font size="+0">logger</font>的层结构时。 <br />
典型的层次结构的解析的花费是<font size="+0">logger</font>彻底关闭时的三倍。 <br />
<h2><font size="+0">4.3.</font>&nbsp;&nbsp;&nbsp; 日志信息的输出时，日志的优化。</h2>
<br />
这是主要花费在日志输出的格式化和发送它到它的输出源上。这里我们再一次的付出努力以使格式化执行的尽可能快。同<font size="+0">appender</font>一样。实际上典型的花费大约是<font size="+0">100-300</font>毫秒。 <br />
详情看<font size="+0">org.apache.log4.performance.Logging</font>。 <br />
虽然<font size="+0">Log4j</font>有许多特点，但是它的第一个设计目标还是速度。一些<font size="+0">Log4j</font>的组件已经被重写过很多次以改善性能。不过，投稿者经常提出了新的优化。你应该满意的知道，以<font size="+0">SimpleLayout</font>的配置执行测试已经展示了<font size="+0">Log4j</font>的输出同<font size="+0">System.out.println</font>一样快。<br />
</font></font></font>&nbsp;
<img src ="http://www.blogjava.net/WshmAndLily/aggbug/179612.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/WshmAndLily/" target="_blank">semovy</a> 2008-02-11 16:22 <a href="http://www.blogjava.net/WshmAndLily/articles/179612.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>随机数字验证码的生成 </title><link>http://www.blogjava.net/WshmAndLily/articles/148701.html</link><dc:creator>semovy</dc:creator><author>semovy</author><pubDate>Thu, 27 Sep 2007 06:29:00 GMT</pubDate><guid>http://www.blogjava.net/WshmAndLily/articles/148701.html</guid><wfw:comment>http://www.blogjava.net/WshmAndLily/comments/148701.html</wfw:comment><comments>http://www.blogjava.net/WshmAndLily/articles/148701.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/WshmAndLily/comments/commentRss/148701.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/WshmAndLily/services/trackbacks/148701.html</trackback:ping><description><![CDATA[<p>有时候在我们的网络应用中，防止程序自动登录搞破坏，我们一般都会加上验证码，这些验证码一般来说都是由人来识别的，当然，如果验证码很有规律，或者说很清楚，漂亮，那么也是可能被程序识别的，我以前就识别过某网站的验证码，因为比较有规律，所以被识别了，并且识别率达到99%左右，其实我们可以制作很复杂一点的验证码，添加一些干扰的线条或者字体变形，使程序识别的难度加大，这样，我们的目的也就达到了.<br />
<br />
下面是生成的图片：<br />
<img height="57" alt="" src="http://www.blogjava.net/images/blogjava_net/hadeslee/ss.jpg" width="202" border="0" /><br />
<br />
代码如下，JSP代码<br />
</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="color: #000000">&lt;%</span><span style="color: #000000">@page&nbsp;contentType</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">image/jpeg</span><span style="color: #000000">"</span><span style="color: #000000">%&gt;</span><span style="color: #000000"><br />
</span><span style="color: #000000">&lt;%</span><span style="color: #000000">@page&nbsp;pageEncoding</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">UTF-8</span><span style="color: #000000">"</span><span style="color: #000000">%&gt;</span><span style="color: #000000"><br />
</span><span style="color: #000000">&lt;%</span><span style="color: #000000">@&nbsp;page&nbsp;</span><span style="color: #0000ff">import</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">java.awt.*,javax.imageio.*,java.io.*,java.util.*,java.awt.image.*</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">%&gt;</span><span style="color: #000000"><br />
</span><span style="color: #000000">&lt;%--</span><span style="color: #000000"><br />
The&nbsp;taglib&nbsp;directive&nbsp;below&nbsp;imports&nbsp;the&nbsp;JSTL&nbsp;library.&nbsp;If&nbsp;you&nbsp;uncomment&nbsp;it,<br />
you&nbsp;must&nbsp;also&nbsp;add&nbsp;the&nbsp;JSTL&nbsp;library&nbsp;to&nbsp;the&nbsp;project.&nbsp;The&nbsp;Add&nbsp;Library<img alt="" src="http://www.blogjava.net/Images/dot.gif" />&nbsp;action<br />
on&nbsp;Libraries&nbsp;node&nbsp;in&nbsp;Projects&nbsp;view&nbsp;can&nbsp;be&nbsp;used&nbsp;to&nbsp;add&nbsp;the&nbsp;JSTL&nbsp;</span><span style="color: #000000">1.1</span><span style="color: #000000">&nbsp;library.<br />
</span><span style="color: #000000">--%&gt;</span><span style="color: #000000"><br />
</span><span style="color: #000000">&lt;%--</span><span style="color: #000000"><br />
</span><span style="color: #000000">&lt;%</span><span style="color: #000000">@taglib&nbsp;uri</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">http://java.sun.com/jsp/jstl/core</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;prefix</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">c</span><span style="color: #000000">"</span><span style="color: #000000">%&gt;</span><span style="color: #000000">&nbsp;<br />
</span><span style="color: #000000">--%&gt;</span><span style="color: #000000"><br />
<br />
</span><span style="color: #000000">&lt;!</span><span style="color: #000000">DOCTYPE&nbsp;HTML&nbsp;PUBLIC&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">-//W3C//DTD&nbsp;HTML&nbsp;4.01&nbsp;Transitional//EN</span><span style="color: #000000">"</span><span style="color: #000000"><br />
</span><span style="color: #000000">"</span><span style="color: #000000">http://www.w3.org/TR/html4/loose.dtd</span><span style="color: #000000">"</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />
</span><span style="color: #000000">&lt;%!</span><span style="color: #000000">String&nbsp;s</span><span style="color: #000000">=</span><span style="color: #000000">""</span><span style="color: #000000">;</span><span style="color: #000000">%&gt;</span><span style="color: #000000"><br />
</span><span style="color: #000000">&lt;%</span><span style="color: #000000"><br />
java.util.List</span><span style="color: #000000">&lt;</span><span style="color: #000000">String</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;fonts</span><span style="color: #000000">=</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;ArrayList</span><span style="color: #000000">&lt;</span><span style="color: #000000">String</span><span style="color: #000000">&gt;</span><span style="color: #000000">();<br />
GraphicsEnvironment.getLocalGraphicsEnvironment().preferLocaleFonts();<br />
String[]&nbsp;names</span><span style="color: #000000">=</span><span style="color: #000000">GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(Locale.CHINA);<br />
</span><span style="color: #0000ff">for</span><span style="color: #000000">(String&nbsp;s:names){<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;c</span><span style="color: #000000">=</span><span style="color: #000000">s.charAt(</span><span style="color: #000000">0</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">(Character.isLowerCase(c)</span><span style="color: #000000">||</span><span style="color: #000000">Character.isUpperCase(c)){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</span><span style="color: #0000ff">else</span><span style="color: #000000">{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fonts.add(s);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
BufferedImage&nbsp;bi</span><span style="color: #000000">=</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;BufferedImage(</span><span style="color: #000000">200</span><span style="color: #000000">,</span><span style="color: #000000">50</span><span style="color: #000000">,BufferedImage.TYPE_INT_RGB);<br />
Graphics2D&nbsp;g</span><span style="color: #000000">=</span><span style="color: #000000">bi.createGraphics();<br />
</span><span style="color: #0000ff">char</span><span style="color: #000000">[]&nbsp;cs</span><span style="color: #000000">=</span><span style="color: #000000">{</span><span style="color: #000000">'</span><span style="color: #000000">0</span><span style="color: #000000">'</span><span style="color: #000000">,</span><span style="color: #000000">'</span><span style="color: #000000">1</span><span style="color: #000000">'</span><span style="color: #000000">,</span><span style="color: #000000">'</span><span style="color: #000000">2</span><span style="color: #000000">'</span><span style="color: #000000">,</span><span style="color: #000000">'</span><span style="color: #000000">3</span><span style="color: #000000">'</span><span style="color: #000000">,</span><span style="color: #000000">'</span><span style="color: #000000">4</span><span style="color: #000000">'</span><span style="color: #000000">,</span><span style="color: #000000">'</span><span style="color: #000000">5</span><span style="color: #000000">'</span><span style="color: #000000">,</span><span style="color: #000000">'</span><span style="color: #000000">6</span><span style="color: #000000">'</span><span style="color: #000000">,</span><span style="color: #000000">'</span><span style="color: #000000">7</span><span style="color: #000000">'</span><span style="color: #000000">,</span><span style="color: #000000">'</span><span style="color: #000000">8</span><span style="color: #000000">'</span><span style="color: #000000">,</span><span style="color: #000000">'</span><span style="color: #000000">9</span><span style="color: #000000">'</span><span style="color: #000000">};<br />
</span><span style="color: #0000ff">char</span><span style="color: #000000">[]&nbsp;use</span><span style="color: #000000">=</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">char</span><span style="color: #000000">[</span><span style="color: #000000">4</span><span style="color: #000000">];<br />
g.setColor(</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Color(</span><span style="color: #000000">240</span><span style="color: #000000">,</span><span style="color: #000000">240</span><span style="color: #000000">,</span><span style="color: #000000">240</span><span style="color: #000000">));<br />
g.fillRect(</span><span style="color: #000000">0</span><span style="color: #000000">,</span><span style="color: #000000">0</span><span style="color: #000000">,</span><span style="color: #000000">200</span><span style="color: #000000">,</span><span style="color: #000000">50</span><span style="color: #000000">);<br />
</span><span style="color: #0000ff">for</span><span style="color: #000000">(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;i</span><span style="color: #000000">=</span><span style="color: #000000">0</span><span style="color: #000000">;i</span><span style="color: #000000">&lt;</span><span style="color: #000000">4</span><span style="color: #000000">;i</span><span style="color: #000000">++</span><span style="color: #000000">){<br />
&nbsp;&nbsp;&nbsp;&nbsp;Point&nbsp;p</span><span style="color: #000000">=</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Point(</span><span style="color: #000000">5</span><span style="color: #000000">+</span><span style="color: #000000">(i</span><span style="color: #000000">*</span><span style="color: #000000">((</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">10</span><span style="color: #000000">)</span><span style="color: #000000">+</span><span style="color: #000000">40</span><span style="color: #000000">)),</span><span style="color: #000000">40</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;size</span><span style="color: #000000">=</span><span style="color: #000000">0</span><span style="color: #000000">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">[]&nbsp;sizes</span><span style="color: #000000">=</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">[</span><span style="color: #000000">20</span><span style="color: #000000">];<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">for</span><span style="color: #000000">(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;j</span><span style="color: #000000">=</span><span style="color: #000000">0</span><span style="color: #000000">;j</span><span style="color: #000000">&lt;</span><span style="color: #000000">20</span><span style="color: #000000">;j</span><span style="color: #000000">++</span><span style="color: #000000">){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sizes[j]</span><span style="color: #000000">=</span><span style="color: #000000">30</span><span style="color: #000000">+</span><span style="color: #000000">j;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;size</span><span style="color: #000000">=</span><span style="color: #000000">sizes[(</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">sizes.length)];<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;face</span><span style="color: #000000">=</span><span style="color: #000000">0</span><span style="color: #000000">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">10</span><span style="color: #000000">&gt;</span><span style="color: #000000">5</span><span style="color: #000000">){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;face</span><span style="color: #000000">=</span><span style="color: #000000">Font.BOLD;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</span><span style="color: #0000ff">else</span><span style="color: #000000">{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;face</span><span style="color: #000000">=</span><span style="color: #000000">Font.ITALIC;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;use[i]</span><span style="color: #000000">=</span><span style="color: #000000">cs[(</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">cs.length)];<br />
&nbsp;&nbsp;&nbsp;&nbsp;g.setPaint(</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;GradientPaint(p.x,p.y,</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Color((</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">256</span><span style="color: #000000">),</span><span style="color: #000000">0</span><span style="color: #000000">,(</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">256</span><span style="color: #000000">)),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p.x,p.y</span><span style="color: #000000">-</span><span style="color: #000000">size,</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Color((</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">256</span><span style="color: #000000">),(</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">256</span><span style="color: #000000">),(</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">256</span><span style="color: #000000">))));<br />
&nbsp;&nbsp;&nbsp;&nbsp;g.setFont(</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Font(fonts.get((</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">fonts.size())),face,size));<br />
&nbsp;&nbsp;&nbsp;&nbsp;g.drawString(</span><span style="color: #000000">""</span><span style="color: #000000">+</span><span style="color: #000000">use[i],p.x,p.y);<br />
}<br />
s</span><span style="color: #000000">=</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;String(use);<br />
session.setAttribute(</span><span style="color: #000000">"</span><span style="color: #000000">code</span><span style="color: #000000">"</span><span style="color: #000000">,&nbsp;s);<br />
g.setPaint(</span><span style="color: #0000ff">null</span><span style="color: #000000">);<br />
</span><span style="color: #0000ff">for</span><span style="color: #000000">(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;i</span><span style="color: #000000">=</span><span style="color: #000000">0</span><span style="color: #000000">;i</span><span style="color: #000000">&lt;</span><span style="color: #000000">4</span><span style="color: #000000">;i</span><span style="color: #000000">++</span><span style="color: #000000">){<br />
&nbsp;&nbsp;&nbsp;&nbsp;g.setColor(</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Color((</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">0x00FFFFFFF</span><span style="color: #000000">)));<br />
&nbsp;&nbsp;&nbsp;&nbsp;g.drawLine((</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">200</span><span style="color: #000000">),(</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">50</span><span style="color: #000000">),(</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">200</span><span style="color: #000000">),(</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">50</span><span style="color: #000000">));<br />
}<br />
Random&nbsp;random&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Random();<br />
</span><span style="color: #0000ff">for</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;i</span><span style="color: #000000">=</span><span style="color: #000000">0</span><span style="color: #000000">;i</span><span style="color: #000000">&lt;</span><span style="color: #000000">88</span><span style="color: #000000">;i</span><span style="color: #000000">++</span><span style="color: #000000">)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;x&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;random.nextInt(</span><span style="color: #000000">200</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;y&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;random.nextInt(</span><span style="color: #000000">50</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;g.setColor(</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Color((</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">0x00FFFFFFF</span><span style="color: #000000">)));<br />
&nbsp;&nbsp;&nbsp;&nbsp;g.setStroke(</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;BasicStroke((</span><span style="color: #0000ff">float</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">3</span><span style="color: #000000">)));<br />
&nbsp;&nbsp;&nbsp;&nbsp;g.drawLine(x,y,x,y);<br />
}<br />
OutputStream&nbsp;ot</span><span style="color: #000000">=</span><span style="color: #000000">response.getOutputStream();<br />
ImageIO.write(bi,</span><span style="color: #000000">"</span><span style="color: #000000">JPEG</span><span style="color: #000000">"</span><span style="color: #000000">,ot);<br />
g.dispose();<br />
ot.close();<br />
</span><span style="color: #000000">%&gt;</span><span style="color: #000000"><br />
<br />
</span></div>
以下是Servlet代码<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="color: #008000">/*</span><span style="color: #008000"><br />
&nbsp;*&nbsp;Code.java<br />
&nbsp;*<br />
&nbsp;*&nbsp;Created&nbsp;on&nbsp;2007年9月21日,&nbsp;下午12:08<br />
&nbsp;</span><span style="color: #008000">*/</span><span style="color: #000000"><br />
<br />
</span><span style="color: #0000ff">package</span><span style="color: #000000">&nbsp;com.hadeslee;<br />
<br />
</span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;java.awt.BasicStroke;<br />
</span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;java.awt.Color;<br />
</span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;java.awt.Font;<br />
</span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;java.awt.GradientPaint;<br />
</span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;java.awt.Graphics2D;<br />
</span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;java.awt.GraphicsEnvironment;<br />
</span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;java.awt.Paint;<br />
</span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;java.awt.Point;<br />
</span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;java.awt.Stroke;<br />
</span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;java.awt.image.BufferedImage;<br />
</span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;java.io.</span><span style="color: #000000">*</span><span style="color: #000000">;<br />
</span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;java.util.ArrayList;<br />
</span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;java.util.List;<br />
</span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;java.util.Locale;<br />
</span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;java.util.Random;<br />
</span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;javax.imageio.ImageIO;<br />
<br />
</span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;javax.servlet.</span><span style="color: #000000">*</span><span style="color: #000000">;<br />
</span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;javax.servlet.http.</span><span style="color: #000000">*</span><span style="color: #000000">;<br />
<br />
</span><span style="color: #008000">/**</span><span style="color: #008000"><br />
&nbsp;*<br />
&nbsp;*&nbsp;</span><span style="color: #808080">@author</span><span style="color: #008000">&nbsp;lbf<br />
&nbsp;*&nbsp;</span><span style="color: #808080">@version</span><span style="color: #008000"><br />
&nbsp;</span><span style="color: #008000">*/</span><span style="color: #000000"><br />
</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;Code&nbsp;</span><span style="color: #0000ff">extends</span><span style="color: #000000">&nbsp;HttpServlet&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">/**</span><span style="color: #008000">&nbsp;Processes&nbsp;requests&nbsp;for&nbsp;both&nbsp;HTTP&nbsp;&lt;code&gt;GET&lt;/code&gt;&nbsp;and&nbsp;&lt;code&gt;POST&lt;/code&gt;&nbsp;methods.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080">@param</span><span style="color: #008000">&nbsp;request&nbsp;servlet&nbsp;request<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080">@param</span><span style="color: #008000">&nbsp;response&nbsp;servlet&nbsp;response<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">*/</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;List</span><span style="color: #000000">&lt;</span><span style="color: #000000">String</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;fonts</span><span style="color: #000000">=</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;ArrayList</span><span style="color: #000000">&lt;</span><span style="color: #000000">String</span><span style="color: #000000">&gt;</span><span style="color: #000000">();<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;Code(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;initFonts();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;initFonts(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GraphicsEnvironment.getLocalGraphicsEnvironment().preferLocaleFonts();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String[]&nbsp;names</span><span style="color: #000000">=</span><span style="color: #000000">GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(Locale.CHINA);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">for</span><span style="color: #000000">(String&nbsp;s:names){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;c</span><span style="color: #000000">=</span><span style="color: #000000">s.charAt(</span><span style="color: #000000">0</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">(Character.isLowerCase(c)</span><span style="color: #000000">||</span><span style="color: #000000">Character.isUpperCase(c)){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><span style="color: #0000ff">else</span><span style="color: #000000">{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fonts.add(s);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">protected</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;processRequest(HttpServletRequest&nbsp;request,&nbsp;HttpServletResponse&nbsp;response)<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">throws</span><span style="color: #000000">&nbsp;ServletException,&nbsp;IOException&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.setContentType(</span><span style="color: #000000">"</span><span style="color: #000000">image/jpeg;charset=UTF-8</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OutputStream&nbsp;out</span><span style="color: #000000">=</span><span style="color: #000000">response.getOutputStream();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BufferedImage&nbsp;bi</span><span style="color: #000000">=</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;BufferedImage(</span><span style="color: #000000">200</span><span style="color: #000000">,</span><span style="color: #000000">50</span><span style="color: #000000">,BufferedImage.TYPE_INT_RGB);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Graphics2D&nbsp;g</span><span style="color: #000000">=</span><span style="color: #000000">bi.createGraphics();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">char</span><span style="color: #000000">[]&nbsp;cs</span><span style="color: #000000">=</span><span style="color: #000000">{</span><span style="color: #000000">'</span><span style="color: #000000">0</span><span style="color: #000000">'</span><span style="color: #000000">,</span><span style="color: #000000">'</span><span style="color: #000000">1</span><span style="color: #000000">'</span><span style="color: #000000">,</span><span style="color: #000000">'</span><span style="color: #000000">2</span><span style="color: #000000">'</span><span style="color: #000000">,</span><span style="color: #000000">'</span><span style="color: #000000">3</span><span style="color: #000000">'</span><span style="color: #000000">,</span><span style="color: #000000">'</span><span style="color: #000000">4</span><span style="color: #000000">'</span><span style="color: #000000">,</span><span style="color: #000000">'</span><span style="color: #000000">5</span><span style="color: #000000">'</span><span style="color: #000000">,</span><span style="color: #000000">'</span><span style="color: #000000">6</span><span style="color: #000000">'</span><span style="color: #000000">,</span><span style="color: #000000">'</span><span style="color: #000000">7</span><span style="color: #000000">'</span><span style="color: #000000">,</span><span style="color: #000000">'</span><span style="color: #000000">8</span><span style="color: #000000">'</span><span style="color: #000000">,</span><span style="color: #000000">'</span><span style="color: #000000">9</span><span style="color: #000000">'</span><span style="color: #000000">};<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">char</span><span style="color: #000000">[]&nbsp;use</span><span style="color: #000000">=</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">char</span><span style="color: #000000">[</span><span style="color: #000000">4</span><span style="color: #000000">];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g.setColor(</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Color(</span><span style="color: #000000">240</span><span style="color: #000000">,</span><span style="color: #000000">240</span><span style="color: #000000">,</span><span style="color: #000000">240</span><span style="color: #000000">));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g.fillRect(</span><span style="color: #000000">0</span><span style="color: #000000">,</span><span style="color: #000000">0</span><span style="color: #000000">,</span><span style="color: #000000">200</span><span style="color: #000000">,</span><span style="color: #000000">50</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">for</span><span style="color: #000000">(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;i</span><span style="color: #000000">=</span><span style="color: #000000">0</span><span style="color: #000000">;i</span><span style="color: #000000">&lt;</span><span style="color: #000000">4</span><span style="color: #000000">;i</span><span style="color: #000000">++</span><span style="color: #000000">){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Point&nbsp;p</span><span style="color: #000000">=</span><span style="color: #000000">getPoint(i);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;size</span><span style="color: #000000">=</span><span style="color: #000000">getSize();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;use[i]</span><span style="color: #000000">=</span><span style="color: #000000">cs[(</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">cs.length)];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;g.setColor(new&nbsp;Color((int)(Math.random()*256),0,(int)(Math.random()*256)));</span><span style="color: #008000"><br />
</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g.setPaint(getPaint(p,size));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g.setFont(</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Font(fonts.get((</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">fonts.size())),getFace(),size));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g.drawString(</span><span style="color: #000000">""</span><span style="color: #000000">+</span><span style="color: #000000">use[i],p.x,p.y);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g.setStroke(</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;BasicStroke(</span><span style="color: #000000">1.0f</span><span style="color: #000000">));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g.setPaint(</span><span style="color: #0000ff">null</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">for</span><span style="color: #000000">(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;i</span><span style="color: #000000">=</span><span style="color: #000000">0</span><span style="color: #000000">;i</span><span style="color: #000000">&lt;</span><span style="color: #000000">4</span><span style="color: #000000">;i</span><span style="color: #000000">++</span><span style="color: #000000">){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g.setColor(</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Color((</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">0x00FFFFFFF</span><span style="color: #000000">)));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g.drawLine((</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">200</span><span style="color: #000000">),(</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">50</span><span style="color: #000000">),(</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">200</span><span style="color: #000000">),(</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">50</span><span style="color: #000000">));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Random&nbsp;random&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Random();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">for</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;i</span><span style="color: #000000">=</span><span style="color: #000000">0</span><span style="color: #000000">;i</span><span style="color: #000000">&lt;</span><span style="color: #000000">88</span><span style="color: #000000">;i</span><span style="color: #000000">++</span><span style="color: #000000">)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;x&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;random.nextInt(</span><span style="color: #000000">200</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;y&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;random.nextInt(</span><span style="color: #000000">50</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g.setColor(</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Color((</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">0x00FFFFFFF</span><span style="color: #000000">)));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g.setStroke(getStroke());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g.drawLine(x,y,x,y);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ImageIO.write(bi,</span><span style="color: #000000">"</span><span style="color: #000000">JPEG</span><span style="color: #000000">"</span><span style="color: #000000">,out);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g.dispose();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;Stroke&nbsp;getStroke(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BasicStroke&nbsp;bs</span><span style="color: #000000">=</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;BasicStroke((</span><span style="color: #0000ff">float</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">3</span><span style="color: #000000">));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;bs;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;Point&nbsp;getPoint(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;index){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Point(</span><span style="color: #000000">5</span><span style="color: #000000">+</span><span style="color: #000000">(index</span><span style="color: #000000">*</span><span style="color: #000000">((</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">10</span><span style="color: #000000">)</span><span style="color: #000000">+</span><span style="color: #000000">40</span><span style="color: #000000">)),</span><span style="color: #000000">40</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;Paint&nbsp;getPaint(Point&nbsp;p,</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;size){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GradientPaint&nbsp;gp</span><span style="color: #000000">=</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;GradientPaint(p.x,p.y,</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Color((</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">256</span><span style="color: #000000">),</span><span style="color: #000000">0</span><span style="color: #000000">,(</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">256</span><span style="color: #000000">)),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p.x,p.y</span><span style="color: #000000">-</span><span style="color: #000000">size,</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Color((</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">256</span><span style="color: #000000">),(</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">256</span><span style="color: #000000">),(</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">256</span><span style="color: #000000">)));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;gp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;getFace(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">10</span><span style="color: #000000">&gt;</span><span style="color: #000000">5</span><span style="color: #000000">){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;Font.BOLD;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><span style="color: #0000ff">else</span><span style="color: #000000">{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;Font.ITALIC;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;getSize(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">[]&nbsp;sizes</span><span style="color: #000000">=</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">[</span><span style="color: #000000">20</span><span style="color: #000000">];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">for</span><span style="color: #000000">(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;i</span><span style="color: #000000">=</span><span style="color: #000000">0</span><span style="color: #000000">;i</span><span style="color: #000000">&lt;</span><span style="color: #000000">20</span><span style="color: #000000">;i</span><span style="color: #000000">++</span><span style="color: #000000">){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sizes[i]</span><span style="color: #000000">=</span><span style="color: #000000">30</span><span style="color: #000000">+</span><span style="color: #000000">i;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;sizes[(</span><span style="color: #0000ff">int</span><span style="color: #000000">)(Math.random()</span><span style="color: #000000">*</span><span style="color: #000000">sizes.length)];<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;&lt;editor-fold&nbsp;defaultstate="collapsed"&nbsp;desc="HttpServlet&nbsp;methods.&nbsp;Click&nbsp;on&nbsp;the&nbsp;+&nbsp;sign&nbsp;on&nbsp;the&nbsp;left&nbsp;to&nbsp;edit&nbsp;the&nbsp;code."&gt;</span><span style="color: #008000"><br />
</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">/**</span><span style="color: #008000">&nbsp;Handles&nbsp;the&nbsp;HTTP&nbsp;&lt;code&gt;GET&lt;/code&gt;&nbsp;method.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080">@param</span><span style="color: #008000">&nbsp;request&nbsp;servlet&nbsp;request<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080">@param</span><span style="color: #008000">&nbsp;response&nbsp;servlet&nbsp;response<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">*/</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">protected</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;doGet(HttpServletRequest&nbsp;request,&nbsp;HttpServletResponse&nbsp;response)<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">throws</span><span style="color: #000000">&nbsp;ServletException,&nbsp;IOException&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;processRequest(request,&nbsp;response);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">/**</span><span style="color: #008000">&nbsp;Handles&nbsp;the&nbsp;HTTP&nbsp;&lt;code&gt;POST&lt;/code&gt;&nbsp;method.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080">@param</span><span style="color: #008000">&nbsp;request&nbsp;servlet&nbsp;request<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080">@param</span><span style="color: #008000">&nbsp;response&nbsp;servlet&nbsp;response<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">*/</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">protected</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;doPost(HttpServletRequest&nbsp;request,&nbsp;HttpServletResponse&nbsp;response)<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">throws</span><span style="color: #000000">&nbsp;ServletException,&nbsp;IOException&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;processRequest(request,&nbsp;response);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">/**</span><span style="color: #008000">&nbsp;Returns&nbsp;a&nbsp;short&nbsp;description&nbsp;of&nbsp;the&nbsp;servlet.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">*/</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;String&nbsp;getServletInfo()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">Short&nbsp;description</span><span style="color: #000000">"</span><span style="color: #000000">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;&lt;/editor-fold&gt;</span><span style="color: #008000"><br />
</span><span style="color: #000000">}<br />
</span></div>
<br />
<br />
在这里我们先得到了服务器所在的系统的字体，并用这些字体生成不同的字符，然后再随机设大小，随机变形，然后为字体加上渐变，并给整个图片添加干扰线条以及干扰点.让程序识别的难度加大.<br />
<br />
呵呵，我们可以把它改成字母或者中文的验证，道理都是一样的，只不过在生成的时候，不一定用数字了，而是用所有可以输入的文字.这样，被程序识别的可能又小了. <br />
<img src ="http://www.blogjava.net/WshmAndLily/aggbug/148701.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/WshmAndLily/" target="_blank">semovy</a> 2007-09-27 14:29 <a href="http://www.blogjava.net/WshmAndLily/articles/148701.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>当前Java软件开发中几种认识误区</title><link>http://www.blogjava.net/WshmAndLily/articles/143469.html</link><dc:creator>semovy</dc:creator><author>semovy</author><pubDate>Fri, 07 Sep 2007 08:30:00 GMT</pubDate><guid>http://www.blogjava.net/WshmAndLily/articles/143469.html</guid><wfw:comment>http://www.blogjava.net/WshmAndLily/comments/143469.html</wfw:comment><comments>http://www.blogjava.net/WshmAndLily/articles/143469.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/WshmAndLily/comments/commentRss/143469.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/WshmAndLily/services/trackbacks/143469.html</trackback:ping><description><![CDATA[越来越多人开始使用Java，但是他们大多数人没有做好足够的思想准备(没有接受OO思想体系<a href="http://www.jdon.com/trainning.htm" target="_blank">相关培训</a>)，以致不能很好驾驭Java项目，甚至 导致开发后的Java系统性能缓慢甚至经常当机。很多人觉得这是Java复杂导致，其实根本原因在于：我们原先掌握的关于软件知识(OO方面)不是太贫乏就是不恰当，存在认识上和方法上的误区。
<p><strong>软件的生命性</strong></p>
<p>　　软件是有生命的，这可能是老调重弹了，但是因为它事关分层架构的原由，反复强调都不过分。</p>
<p>　　一个有生命的软件首先必须有一个灵活可扩展的基础架构，其次才是完整的功能。</p>
<p>　　目前很多人对软件的思想还是焦点落在后者：完整的功能，觉得一个软件功能越完整越好，其实关键还是架构的灵活性，就是前者，基础架构好，功能添加只是时间和工作量问题，但是如果架构不好，功能再完整，也不可能包括未来所有功能，软件是有生命的，在未来成长时，更多功能需要加入，但是因为基础架构不灵活不能方便加入，死路一条。<br />
<br />
　　正因为普通人对软件存在短视误区，对功能追求高于基础架构，很多吃了亏的老程序员就此离开软件行业，带走宝贵的失败经验，新的盲目的年轻程序员还是使用老的思维往前冲。其实很多国外免费开源框架如ofbiz compiere和slide也存在这方面陷阱，貌似非常符合胃口，其实类似国内那些几百元的盗版软件，扩展性以及持续发展性严重不足。</p>
<p>　　那么选择现在一些流行的框架如Hibernate、Spring/Jdonframework是否就表示基础架构打好了呢？其实还不尽然，关键还是取决于你如何使用这些框架来搭建你的业务系统。</p>
<p><strong>存储过程和复杂SQL语句的陷阱</strong></p>
<p>　　首先谈谈存储过程使用的误区，使用存储过程架构的人以为可以解决性能问题，其实它正是导致性能问题的罪魁祸首之一，打个比喻：如果一个人频临死亡，打一针可以让其延长半年，但是打了这针，其他所有医疗方案就全部失效，请问你会使用这种短视方案吗？</p>
<p>　　为什么这样说呢？如果存储过程都封装了业务过程，那么运行负载都集中在数据库端，要中间J2EE应用服务器干什么？要中间服务器的分布式计算和集群能力做什么？只能回到过去集中式数据库主机时代。现在软件都是面向互联网的，不象过去那样局限在一个小局域网，多用户并发访问量都是无法确定和衡量，依靠一台数据库主机显然是不能够承受这样恶劣的用户访问环境的。（当然搞数据库集群也只是五十步和百步的区别）。</p>
<p>　　 从分层角度来看，现在三层架构：表现层、业务层和持久层，三个层次应该分割明显，职责分明：持久层职责持久化保存业务模型对象，业务层对持久层的调用只是帮助我们激活曾经委托其保管的对象，所以，不能因为持久层是保管者，我们就以其为核心围绕其编程，除了要求其归还模型对象外，还要求其做其做复杂的业务组合。打个比喻：你在火车站将水果和盘子两个对象委托保管处保管，过了两天来取时，你还要求保管处将水果去皮切成块，放在盘子里，做成水果盘给你，合理吗？</p>
<p>　　上面是谈过分依赖持久层的一个现象，还有一个正好相反现象，持久层散发出来，开始挤占业务层，腐蚀业务层，整个业务层到处看见的是数据表的影子（包括数据表的字段），而不是业务对象。这样程序员应该多看看<a href="http://www.martinfowler.com/eaaCatalog/index.html" target="_blank">OO经典PoEAA</a>。<a href="http://www.martinfowler.com/eaaCatalog/index.html" target="_blank">PoEAA</a> 认为除了持久层，不应该在其他地方看到数据表或表字段名。</p>
<p>　　当然适量使用存储过程，使用数据库优点也是允许的。按照Evans DDD理论，可以将SQL语句和存储过程作为规则Specification一部分。 </p>
<p><strong>Hibernate等ORM问题</strong><br />
　　现在使用Hibernate人也不少，但是他们发现Hibernate性能缓慢，所以寻求解决方案，其实并不是 Hibernate性能缓慢，而是我们使用方式发生错误：</p>
<p>　　&#8220;最近本人正搞一个项目，项目中我们用到了struts1.2+hibernate3, 由于关系复杂表和表之间的关系很多，在很多地方把lazy都设置false，所以导致数据一加载很慢，而且查询一条数据更是非常的慢。&#8221;</p>
<p>　　Hibernate是一个基于对象模型持久化的技术，因此，关键是我们需要设计出高质量的对象模型，遵循DDD领域建模原则，减少降低关联，通过分层等有效办法处理关联。如果采取围绕数据表进行设计编程，加上表之间关系复杂（没有科学方法处理、侦察或减少这些关系），必然导致 系统运行缓慢，其实同样问题也适用于当初对EJB的实体Bean的CMP抱怨上，实体Bean是Domain Model持久化，如果不首先设计Domain Model，而是设计数据表，和持久化工具设计目标背道而驰，能不出问题吗？关于这个问题N多年就在Jdon争论过。</p>
<p>　　这里同样延伸出另外一个问题：数据库设计问题，数据库是否需要在项目开始设计？<br />
如果我们进行数据库设计，那么就产生了一系列问题：当我们使用Hibernate实现持久保存时，必须考虑事先设计好的数据库表结构以及他们的关系如何和业务对象实现映射，这实际上是非常难实现的，这也是很多人觉得使用ORM框架棘手根本原因所在。</p>
<p>　　当然，也有脑力相当发达的人可以 实现，但是这种围绕数据库实现映射的结果必然扭曲业务对象，这类似于两个板块（数据表和业务对象）相撞，必然产生地震，地震的结果是两败俱伤， 软的一方吃亏，业务对象是代码，相当于数据表结构，属于软的一方，最后导致业务对象变成数据传输对象DTO, DTO满天飞，性能和维护问题随之而来。</p>
<p>　　领域建模解决了上述众多不协调问题，特别是ORM痛苦使用问题，关于ORM/Hibernate使用还是那句老话：如果你不掌握领域建模方法，那么就不要用Hibernate，对于这个层次的你：也许No ORM 更是一个简单之道： No ORM: The simplest solution<br />
<a href="http://www.theserverside.com/blogs/thread.tss?thread_id=41715" target="_blank">http://www.theserverside.com/blogs/thread.tss?thread_id=41715</a></p>
<p><strong>Spring分层矛盾问题</strong><br />
　　Spring是以挑战EJB面貌出现，其本身拥有的强大组件定制功能是优点，但是存在实战的一些问题，Spring作为业务层框架，不支持业务层Session 功能。</p>
<p>　　具体举例如下：当我们实现购物车之类业务功能时，需要将购物场合保存到Session中，由于业务层没有方便的Session支持，我们只得将购物车保存到 HttpSession，而HttpSession只有通过HttpRequest才能获得，再因为在Spring业务层容器中是无法访问到HttpRequest这个对象的，所以， 最后我们只能将&#8220;购物车保存到HttpSession&#8221;这个功能放在表现层中实现，而这个功能明显应该属于业务层功能，这就导致我们的Java项目层次混乱，维护性差。 违背了使用Spring和分层架构最初目的。</p>
<p>　　相关案例：请教一个在完整提交前临时保存的问题:<br />
　　<a href="http://www.jdon.com/jive/article.jsp?forum=46&amp;thread=28429" target="_blank"><font color="#800080">http://www.jdon.com/jive/article.jsp?forum=46&amp;thread=28429</font></a></p>
<p><strong>领域驱动设计DDD</strong><br />
　　现在回到我们讨论的重点上来，分层架构是我们使用Java的根本原因之一，域建模专家Eric Evans在他的&#8220;Domain Model Design&#8221;一书中开篇首先强调的是分层架构，整个DDD理论实际是告诉我们如何使用模型对象oo技术和分层架构来设计实现一个Java项目。</p>
<p>　　我们现在很多人知道Java项目基本有三层：表现层　业务层和持久层，当我们执著于讨论各层框架如何选择之时，实际上我们真正的项目开发工作还没有开始， 就是我们选定了某种框架的组合（如Struts+Spring+Hibernate或Struts+EJB或Struts+JdonFramework），我们还没有意识到业务层工作还需要大量工作，DDD提供了在业务层中再划分新的层次思想，如领域层和服务层，甚至再细分为作业层、能力层、策略层等等。通过层次细化方式达到复杂软件的松耦合。DDD提供了如何细分层次的方式</p>
<p>　　当我们将精力花费在架构技术层面的讨论和研究上时，我们可能忘记以何种依据选择这些架构技术？选择标准是什么？领域驱动设计DDD 回答了这样的问题，DDD会告诉你如果一个框架不能协助你实现分层架构，那就抛弃它，同时，DDD也指出选择框架的考虑目的，使得你不会 人云亦云，陷入复杂的技术细节迷雾中，迷失了架构选择的根本方向。</p>
<p>　　现在也有些人误以为DDD是一种新的理论，其实DDD和设计模式一样，不是一种新的理论，而是实战经验的总结，它将前人 使用面向模型设计的方法经验提炼出来，供后来者学习，以便迅速找到驾驭我们软件项目的根本之道。</p>
<p>　　现在Evans　DDD概念很火，因为它将著名的<a href="http://www.martinfowler.com/eaaCatalog/index.html" target="_blank">PoEAA</a>进行了具化，实现了<a href="http://www.martinfowler.com/eaaCatalog/index.html" target="_blank">PoEAA</a>可操作性，这也是MF大力推崇的原因。最近(8月8日)一位老外博客上用微软的.NET架构和Evans DDD比较的文章：<a href="http://weblogs.asp.net/pgielens/archive/2006/08/08/Organizing-Domain-Logic.aspx">http://weblogs.asp.net/pgielens/archive/2006/08/08/Organizing-Domain-Logic.aspx</a>，这篇文章比较了微软的三层服务应用架构[Microsoft TLSA]和Evans DDD的架构， 使用Microsoft .NET Pet Shop 4为例子，解释两个目标的区别，并且表明<br />
微软是如何在案例中更好地实现支持后者。这篇文章帮助哪些.NET平台上有域设计知识的人实现更好地提高。</p>
<p>　　另外一本关于.NET的DDD书籍也已经出版，这些都说明Evans DDD这把火已经烧到.NET领域，当然DDD在Java领域生根开花多年，Evans的DDD书籍就是以Java为例子的，笔者板桥里人也率先在2005年推出DDD框架JdonFramework 1.3版本，这些都说明，Java在整个软件业先进思想的实践上</p>
<img src ="http://www.blogjava.net/WshmAndLily/aggbug/143469.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/WshmAndLily/" target="_blank">semovy</a> 2007-09-07 16:30 <a href="http://www.blogjava.net/WshmAndLily/articles/143469.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>什么是Web Service？</title><link>http://www.blogjava.net/WshmAndLily/articles/143466.html</link><dc:creator>semovy</dc:creator><author>semovy</author><pubDate>Fri, 07 Sep 2007 08:27:00 GMT</pubDate><guid>http://www.blogjava.net/WshmAndLily/articles/143466.html</guid><wfw:comment>http://www.blogjava.net/WshmAndLily/comments/143466.html</wfw:comment><comments>http://www.blogjava.net/WshmAndLily/articles/143466.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/WshmAndLily/comments/commentRss/143466.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/WshmAndLily/services/trackbacks/143466.html</trackback:ping><description><![CDATA[你可能早就听说过Web service了，你也可能已经对Web service有一些概念了。一时间，好像所有的计算机期刊、书籍和网站都开始提及Web service。然而，当前大多数对Web service的介绍都没能清楚的说明Web service到底是什么。他们只是鼓吹Web service是多么多么的好，简直就像是在做广告。在本文中会讲清楚两件事：Web service到底是什么；在什么情况下你应该使用Web service。 <br />
<br />
分布式应用程序和浏览器 <br />
<br />
研究一下当前的应用程序开发，你会发现一个绝对的倾向：人们开始偏爱基于浏览器的瘦客户应用程序。这当然不是因为瘦客户能够提供更好的用户界面，而是因为它能够避免花在桌面应用程序发布上的高成本。发布桌面应用程序成本很高，一半是因为应用程序安装和配置的问题，另一半是因为客户和服务器之间通信的问题。 <br />
<br />
传统的Windows富客户应用程序使用DCOM来与服务器进行通信和调用远程对象。配置好DCOM使其在一个大型的网络中正常工作将是一个极富挑战性的工作，同时也是许多IT工程师的噩梦。事实上，许多IT工程师宁愿忍受浏览器所带来的功能限制，也不愿在局域网上去运行一个DCOM。在我看来，结果就是一个发布容易，但开发难度大而且用户界面极其受限的应用程序。极端的说，就是你花了更多的资金和时间，却开发出从用户看来功能更弱的应用程序。不信？问问你的会计师对新的基于浏览器的会计软件有什么想法：绝大多数商用程序用户希望使用更加友好的Windows用户界面。 <br />
<br />
关于客户端与服务器的通信问题，一个完美的解决方法是使用HTTP协议来通信。这是因为任何运行Web浏览器的机器都在使用HTTP协议。同时，当前许多防火墙也配置为只允许HTTP连接。 <br />
<br />
许多商用程序还面临另一个问题，那就是与其他程序的互操作性。如果所有的应用程序都是使用COM或.NET语言写的，并且都运行在Windows平台上，那就天下太平了。然而，事实上大多数商业数据仍然在大型主机上以非关系文件(VSAM)的形式存放，并由COBOL语言编写的大型机程序访问。而且，目前还有很多商用程序继续在使用C++、Java、Visual <br />
<br />
Basic和其他各种各样的语言编写。现在，除了最简单的程序之外，所有的应用程序都需要与运行在其他异构平台上的应用程序集成并进行数据交换。这样的任务通常都是由特殊的方法，如文件传输和分析，消息队列，还有仅适用于某些情况的的API，如IBM的"高级程序到程序交流(APPC)"等来完成的。在以前，没有一个应用程序通信标准，是独立于平台、组建模型和编程语言的。只有通过Web <br />
<br />
Service，客户端和服务器才能够自由的用HTTP进行通信，不论两个程序的平台和编程语言是什么。 <br />
<br />
什么是Web Service <br />
<br />
对这个问题，我们至少有两种答案。从表面上看，Web service 就是一个应用程序，它向外界暴露出一个能够通过Web进行调用的API。这就是说，你能够用编程的方法通过Web来调用这个应用程序。我们把调用这个Web service 的应用程序叫做客户。例如，你想创建一个Web service ，它的作用是返回当前的天气情况。那么你可已建立一个ASP页面，它接受邮政编码作为查询字符串，然后返回一个由逗号隔开的字符串，包含了当前的气温和天气。要调用这个ASP页面，客户端需要发送下面的这个HTTP GET请求： <br />
<br />
http://host.company.com/weather.asp?zipcode=20171 <br />
<br />
返回的数据就应该是这样： <br />
<br />
21,晴 <br />
<br />
这个ASP页面就应该可以算作是Web service 了。因为它基于HTTP GET请求，暴露出了一个可以通过Web调用的API。当然，Web service 还有更多的东西。 <br />
<br />
下面是对Web service 更精确的解释： Web services是建立可互操作的分布式应用程序的新平台。作为一个Windows程序员，你可能已经用COM或DCOM建立过基于组件的分布式应用程序。COM是一个非常好的组件技术，但是我们也很容易举出COM并不能满足要求的情况。 <br />
<br />
Web service平台是一套标准，它定义了应用程序如何在Web上实现互操作性。你可以用任何你喜欢的语言，在任何你喜欢的平台上写Web service ，只要我们可以通过Web service标准对这些服务进行查询和访问。 <br />
<br />
新平台 <br />
<br />
Web service平台需要一套协议来实现分布式应用程序的创建。任何平台都有它的数据表示方法和类型系统。要实现互操作性，Web service平台必须提供一套标准的类型系统，用于沟通不同平台、编程语言和组件模型中的不同类型系统。在传统的分布式系统中，基于界面(interface)的平台提供了一些方法来描述界面、方法和参数（译注：如COM和COBAR中的IDL语言）。同样的，Web service平台也必须提供一种标准来描述Web service，让客户可以得到足够的信息来调用这个Web <br />
<br />
service。最后，我们还必须有一种方法来对这个Web service进行远程调用。这种方法实际是一种远程过程调用协议(RPC)。为了达到互操作性，这种RPC协议还必须与平台和编程语言无关。下面几个小节就简要介绍了组成Web service平台的这三个技术。 <br />
<br />
XML和XSD <br />
<br />
可扩展的标记语言(XML)是Web service平台中表示数据的基本格式。除了易于建立和易于分析外，XML主要的优点在于它既是平台无关的，又是厂商无关的。无关性是比技术优越性更重要的：软件厂商是不会选择一个由竞争对手所发明的技术的。 <br />
<br />
XML解决了数据表示的问题，但它没有定义一套标准的数据类型，更没有说怎么去扩展这套数据类型。例如，整形数到底代表什么？16位，32位，还是64位？这些细节对实现互操作性都是很重要的。W3C制定的XML Schema(XSD)就是专门解决这个问题的一套标准。它定义了一套标准的数据类型，并给出了一种语言来扩展这套数据类型。Web service平台就是用XSD来作为其数据类型系统的。当你用某种语言(如VB.NET或C#)来构造一个Web service时，为了符合Web service标准，所有你使用的数据类型都必须被转换为XSD类型。你用的工具可能已经自动帮你完成了这个转换，但你很可能会根据你的需要修改一下转换过程。在第二章中，我们将深入XSD，学习怎样转换自定义的数据类型(例如类)到XSD的类型。 <br />
<br />
SOAP <br />
<br />
Web service建好以后，你或者其他人就会去调用它。简单对象访问协议(SOAP)提供了标准的RPC方法来调用Web service。实际上，SOAP在这里有点用词不当：它意味着下面的Web service是以对象的方式表示的，但事实并不一定如此：你完全可以把你的Web service写成一系列的C函数，并仍然使用SOAP进行调用。SOAP规范定义了SOAP消息的格式，以及怎样通过HTTP协议来使用SOAP。SOAP也是基于XML和XSD的，XML是SOAP的数据编码方式。第三章我们会讨论SOAP，并结识SOAP消息的各种元素。 <br />
<br />
WSDL <br />
<br />
你会怎样向别人介绍你的Web service有什么功能，以及每个函数调用时的参数呢？你可能会自己写一套文档，你甚至可能会口头上告诉需要使用你的Web service的人。这些非正式的方法至少都有一个严重的问题：当程序员坐到电脑前，想要使用你的Web service的时候，他们的工具(如Visual Studio)无法给他们提供任何帮助，因为这些工具根本就不了解你的Web <br />
<br />
service。解决方法是：用机器能阅读的方式提供一个正式的描述文档。Web service描述语言(WSDL)就是这样一个基于XML的语言，用于描述Web service及其函数、参数和返回值。因为是基于XML的，所以WSDL既是机器可阅读的，又是人可阅读的，这将是一个很大的好处。一些最新的开发工具既能根据你的Web service生成WSDL文档，又能导入WSDL文档，生成调用相应Web service的代码。
<img src ="http://www.blogjava.net/WshmAndLily/aggbug/143466.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/WshmAndLily/" target="_blank">semovy</a> 2007-09-07 16:27 <a href="http://www.blogjava.net/WshmAndLily/articles/143466.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>12个最重要的J2EE最佳实践</title><link>http://www.blogjava.net/WshmAndLily/articles/143460.html</link><dc:creator>semovy</dc:creator><author>semovy</author><pubDate>Fri, 07 Sep 2007 08:17:00 GMT</pubDate><guid>http://www.blogjava.net/WshmAndLily/articles/143460.html</guid><wfw:comment>http://www.blogjava.net/WshmAndLily/comments/143460.html</wfw:comment><comments>http://www.blogjava.net/WshmAndLily/articles/143460.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/WshmAndLily/comments/commentRss/143460.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/WshmAndLily/services/trackbacks/143460.html</trackback:ping><description><![CDATA[<p><font size="3"><font face="宋体"><strong>1.&nbsp;始终使用&nbsp;MVC&nbsp;框架。</strong>&nbsp;</font></font></p>
<p><font face="宋体" size="3">　　MVC&nbsp;框架可以将业务逻辑（Java&nbsp;beans&nbsp;和&nbsp;EJB&nbsp;组件)、控制器逻辑（Servlets/Struts&nbsp;动作）、表示层（JSP、XML/XSLT）清晰地分离开来。良好的分层可以带来许多好处。&nbsp;</font></p>
<p><font face="宋体" size="3">　　MVC&nbsp;框架对于成功使用&nbsp;J2EE&nbsp;是如此重要，以致没有其他最佳实践可以与其相提并论。模型-视图-控制器（MVC）是设计&nbsp;J2EE&nbsp;应用程序的基础。MVC&nbsp;将您的程序代码简单地划分下面几个部分：&nbsp;</font></p>
<p><font face="宋体" size="3">　　&#183;负责业务逻辑的代码（即模型——通常使用&nbsp;EJB&nbsp;或者普通的&nbsp;Java&nbsp;对象来实现）。&nbsp;<br />
　　&#183;负责用户界面显示的代码（即视图——通常通过&nbsp;JSP&nbsp;及标记库来实现，有时也使用&nbsp;XML&nbsp;和&nbsp;XSLT&nbsp;来实现）。&nbsp;<br />
　　&#183;负责应用程序流程的代码（即控制器——通常使用&nbsp;Java&nbsp;Servlet&nbsp;或像&nbsp;Struts&nbsp;控制器这样的类来实现）。&nbsp;</font></p>
<p><font face="宋体" size="3">　　如果您不遵循基本的&nbsp;MVC&nbsp;框架，在开发过程中就会出现许多的问题。最常见的问题就是在视图部分添加了太多的成分，例如，可能存在使用&nbsp;JSP&nbsp;标记来执行数据库访问，或者在&nbsp;JSP&nbsp;中进行应用程序的流程控制，这在小规模的应用程序中是比较常见的，但是，随着后期的开发，这样做将会带来问题，因为&nbsp;JSP&nbsp;逐步变得越来越难以维护和调试。&nbsp;</font></p>
<p><font face="宋体" size="3">　　类似地，我们也经常看到将视图层构建到业务逻辑的情况。例如，一个常见的问题就是将在构建视图时使用的&nbsp;XML&nbsp;解析技术直接应用到业务层。业务层应该对业务对象——而不是绑定到视图的特定数据表示进行操作。&nbsp;</font></p>
<p><font face="宋体" size="3">　　然而，只是具有合适的组件并不一定意味着可以使您的应用程序得到合适的分层。我们常常见到一些应用程序包含&nbsp;servlet、JSP&nbsp;和&nbsp;EJB&nbsp;组件所有这三项，然而，其主要的业务逻辑却是在&nbsp;servlet&nbsp;层实现的，或者应用程序导航是在&nbsp;JSP&nbsp;中处理的。您必须进行严格的代码检查并重构您的代码，以确保应用程序的业务逻辑只在模型层（Model&nbsp;layer）进行处理，应用程序导航只通过控制器层（Controller&nbsp;layer）进行处理，而您的视图（Views）只是将传递过来的模型对象以&nbsp;HTML&nbsp;及&nbsp;JavaScript&nbsp;的形式表示出来。&nbsp;</font></p>
<p><font face="宋体" size="3">　　<strong>2.&nbsp;在应用程序的每一层都使用自动单元测试和测试管理。</strong>&nbsp;</font></p>
<p><font face="宋体" size="3">　　不要只是测试您的图形用户界面（GUI)。分层的测试使测试及维护工作变得极其简单。&nbsp;</font></p>
<p><font face="宋体" size="3">　　在过去的几年中，在方法学领域有了相当大的革新，例如新出现的被称为&nbsp;Agile（例如&nbsp;SCRUM&nbsp;[Schwaber]&nbsp;和极限编程&nbsp;[Beck1]）的轻量级方法现在已经得到了很普遍的应用。几乎所有的这些方法中的一个共同的特征是它们都提倡使用自动的测试工具，这些工具可以帮助开发人员用更少的时间进行回归测试&nbsp;(regression&nbsp;testing)，并可以帮助他们避免由于不充分的回归测试造成的错误，因此可以用来提高程序员的工作效率。实际上，还有一种被称为&nbsp;Test-First&nbsp;Development&nbsp;[Beck2]&nbsp;的方法，这种方法甚至提倡在开发实际的代码之前就先编写单元测试。然而，在您测试代码之前，您需要将代码分割成一些可测试的片断。一个"大泥球"是难以测试的，因为它不是只实现一个简单的易于识别的功能。如果您的每个代码片断实现多个方面的功能，这样的代码将难以保证其完全的正确性。&nbsp;</font></p>
<p><font face="宋体" size="3">　　MVC&nbsp;框架（以及&nbsp;J2EE&nbsp;中的&nbsp;MVC&nbsp;实现）的一个优点就是元素的组件化能够（实际上，相当的简单）对您的应用程序进行单元测试。因此，您可以方便地对实体&nbsp;bean、会话&nbsp;bean&nbsp;以及&nbsp;JSP&nbsp;独立编写测试用例，而不必考虑其他的代码。现在有许多用于&nbsp;J2EE&nbsp;测试的框架和工具，这些框架及工具使得这一过程更加简单。例如，JUnit（是一种由&nbsp;junit.org&nbsp;开发的开放源代码工具）和&nbsp;Cactus（由&nbsp;Apache&nbsp;开发的开放源代码工具）对于测试&nbsp;J2EE&nbsp;组件都非常有用。[Hightower]&nbsp;详细探讨了如何在&nbsp;J2EE&nbsp;中使用这些工具。&nbsp;</font></p>
<p><font face="宋体" size="3">　　尽管所有这些详述了怎样彻底地测试您的应用程序，但是我们仍然看到一些人认为只要他们测试了&nbsp;GUI（可能是基于&nbsp;Web&nbsp;的&nbsp;GUI，或者是独立的&nbsp;Java&nbsp;应用程序），则他们就全面地测试了整个应用程序。GUI&nbsp;测试很难达到全面的测试，有以下几种原因。首先，使用&nbsp;GUI&nbsp;测试很难彻底地测试到系统的每一条路径，GUI&nbsp;仅仅是影响系统的一种方式，可能存在后台运算、脚本和各种各样的其他访问点，这也需要进行测试。然而，它们通常并不具有&nbsp;GUI。第二，GUI&nbsp;级的测试是一种非常粗粒度的测试。这种测试只是在宏观水平上测试系统的行为。这意味着一旦发现存在问题，则与此问题相关的整个子系统都要进行检查，这使得找出&nbsp;bug（缺陷）将是非常困难的事情。第三，GUI&nbsp;测试通常只有在整个开发周期的后期才能很好地得到测试，这是因为只有这那个时候&nbsp;GUI&nbsp;才得到完整的定义。这意味着只有在后期才可能发现潜在的&nbsp;bug。第四，一般的开发人员可能没有自动的&nbsp;GUI&nbsp;测试工具。因此，当一个开发人员对代码进行更改时，没有一种简单的方法来重新测试受到影响的子系统。这实际上不利于进行良好的测试。如果开发人员具有自动的代码级单元测试工具，开发人员就能够很容易地运行这些工具以确保所做的更改不会破坏已经存在的功能。最后，如果添加了自动构建功能，则在自动构建过程中添加一个自动的单元测试工具是非常容易的事情。当完成这些设置以后，整个系统就可以有规律地进行重建，并且回归测试几乎不需要人的参与。&nbsp;</font></p>
<p><font face="宋体" size="3">　　另外，我们必须强调，使用&nbsp;EJB&nbsp;和&nbsp;Web&nbsp;服务进行分布式的、基于组件的开发使得测试单个的组件变得非常必要。如果没有"GUI"需要测试，您就必须进行低级（lower-level）测试。最好以这种方式开始测试，省得当您将分布式的组件或&nbsp;Web&nbsp;服务作为您的应用程序的一部分时，您不得不花费心思重新进行测试。&nbsp;</font></p>
<p><font face="宋体" size="3">　　总之，通过使用自动的单元测试，能够很快地发现系统的缺陷，并且也易于发现这些缺陷，使得测试工作变得更加系统化，因此整体的质量也得以提高。&nbsp;</font></p>
<p><font face="宋体" size="3">　　<strong>3.&nbsp;按照规范来进行开发，而不是按照应用服务器来进行开发。</strong>&nbsp;</font></p>
<p><font face="宋体" size="3">　　要将规范熟记于心，如果要背离规范，要经过慎密的考虑后才可以这样做。这是因为当您背离规则的时候，您所做的事情往往并不是您应该做的事情。&nbsp;</font></p>
<p><font face="宋体" size="3">　　当您要背离&nbsp;J2EE&nbsp;可以允许您做的事情的时候，这很容易让使您遭受不幸。我们发现有一些开发人员钻研一些&nbsp;J2EE&nbsp;允许之外的东西，他们认为这样做可以"稍微"改善J2EE的性能，而他们最终只会发现这样做会引起严重的性能问题，或者在以后的移植（从一个厂商到另一个厂商，或者是更常见的从一个版本到另一个版本）中会出现问题。实际上，这种移植问题是如此严重，以致&nbsp;[Beaton]&nbsp;将此原则称为移植工作的基本最佳实践。&nbsp;</font></p>
<p><font face="宋体" size="3">　　现在有好几个地方如果不直接使用&nbsp;J2EE&nbsp;提供的方法肯定会产生问题。一个常见的例子就是开发人员通过使用&nbsp;JAAS&nbsp;模块来替代&nbsp;J2EE&nbsp;安全性，而不是使用内置的遵循规范的应用程序服务器机制来进行验证和授权。要注意不要脱离&nbsp;J2EE&nbsp;规范提供的验证机制，如果脱离了此规范，这将是系统存在安全漏洞以及厂商兼容性问题的主要原因。类似地，要使用&nbsp;servlet&nbsp;和&nbsp;EJB&nbsp;规范提供的授权机制，并且如果您要偏离这些规范的话，要确保使用规范定义的&nbsp;API（例如&nbsp;getCallerPrincipal()）作为实现的基础。通过这种方式，您将能够利用厂商提供的强安全性基础设施，其中，业务要求需要支持复杂的授权规则。&nbsp;</font></p>
<p><font face="宋体" size="3">　　其他常见的问题包括使用不遵循&nbsp;J2EE&nbsp;规范的持久性机制（这使得事务管理变得困难）、在J2EE程序中使用不适当的J2SE&nbsp;方法（例如线程或&nbsp;singleton），以及使用您自己的方法解决程序到程序（program-to-program）的通信，而不是使用&nbsp;J2EE&nbsp;内在支持的机制（例如&nbsp;JCA、JMS&nbsp;或&nbsp;Web&nbsp;服务）。当您将一个遵循&nbsp;J2EE&nbsp;的服务器移植到其他的服务器上，或者移植到相同服务器的新版本上，上述的设计选择将会造成无数的问题。唯一要背离规范的情况是，当一个问题在规范的范围内无法解决的时候。例如，安排执行定时的业务逻辑在&nbsp;EJB2.1&nbsp;出现之前是一个问题，在类似这样的情况下，我们建议当有厂商提供的解决方案时就使用厂商提供的解决方案（例如&nbsp;WebSphere&nbsp;Application&nbsp;Server&nbsp;Enterprise&nbsp;中的&nbsp;Scheduler&nbsp;工具），而在没有厂商提供的解决方案时就使用第三方提供的工具。如果使用厂商提供的解决方案，应用程序的维护以及将其移植到新的规范版本将是厂商的问题，而不是您的问题。&nbsp;</font></p>
<p><font face="宋体" size="3">　　最后，要注意不要太早地采用新技术。太过于热衷采用还没有集成到&nbsp;J2EE&nbsp;规范的其他部分或者还没有集成到厂商的产品中的技术常会带来灾难性的后果。支持是关键的——如果您的厂商不直接支持一种特定的在&nbsp;JSR&nbsp;中提出的技术，但此技术还没有被&nbsp;J2EE&nbsp;所接受，那么您就不应该采用此技术。毕竟，我们中的大多数人从事解决业务问题，而不是推进技术的发展。&nbsp;</font></p>
<p><font face="宋体" size="3">　　<strong>4.&nbsp;从一开始就计划使用&nbsp;J2EE&nbsp;安全性。</strong>&nbsp;</font></p>
<p><font face="宋体" size="3">　　启用&nbsp;WebSphere&nbsp;安全性。这使您的&nbsp;EJB&nbsp;和&nbsp;URL&nbsp;至少可以让所有授权用户访问。不要问为什么——照着做就是了。&nbsp;</font></p>
<p><font face="宋体" size="3">　　在与我们合作的客户中，一开始就打算启用&nbsp;WebSphere&nbsp;J2EE&nbsp;安全性的顾客是非常少的，这一点一直让我们感到吃惊。据我们估计大约只有&nbsp;50%&nbsp;的顾客一开始就打算使用此特性。例如，我们曾与一些大型的金融机构（银行、代理等等）合作过，他们也没有打算启用安全性。幸运的是，这种问题在部署之前的检查时就得以解决.&nbsp;</font></p>
<p><font face="宋体" size="3">　　不使用&nbsp;J2EE&nbsp;安全性是危险的事情。假设您的应用程序需要安全性（几乎所有的应用程序都需要），您敢打赌您的开发人员能够构建出自己的安全性系统，而这个系统比您从&nbsp;J2EE&nbsp;厂商那里买来的更好。这可不是个好的赌注，为分布式的应用程序提供安全性是异常困难的。例如，您需要使用网络安全加密令牌控制对&nbsp;EJB&nbsp;的访问。以我们的经验看来，大多数自己构建的安全性系统是不安全的，并且有重大的缺陷，这使产品系统极其脆弱。&nbsp;</font></p>
<p><font face="宋体" size="3">　　一些不使用&nbsp;J2EE&nbsp;安全性的理由包括：担心性能的下降，相信其他的安全性（例如&nbsp;Netegrity&nbsp;SiteMinder）可以取代&nbsp;J2EE&nbsp;安全性，或者是不知道&nbsp;WebSphere&nbsp;Application&nbsp;Server&nbsp;安全特性及功能。不要陷入这些陷阱之中，尤其是，尽管像&nbsp;Netegrity&nbsp;SiteMinder&nbsp;这样的产品能够提供优秀的安全特性，但是仅仅其自身不可能保护整个&nbsp;J2EE&nbsp;应用程序。这些产品必须与&nbsp;J2EE&nbsp;应用程序服务器联合起来才可能全面地保护您的系统。&nbsp;</font></p>
<p><font face="宋体" size="3">　　其他的一种常见的不使用&nbsp;J2EE&nbsp;安全性的原因是：基于角色的模型没有提供足够的粒度访问控制以满足复杂的业务规则。尽管事实是这样的，但这也不应该成为不使用&nbsp;J2EE&nbsp;安全性的理由。相反地，应该将&nbsp;J2EE&nbsp;验证及&nbsp;J2EE&nbsp;角色与特定的扩展规则结合起来。如果复杂的业务规则需要做出安全性决策，那就编写相应的代码，其安全性决策要基于可以直接使用的以及可靠的&nbsp;J2EE&nbsp;验证信息（用户&nbsp;ID&nbsp;和角色）。&nbsp;</font></p>
<p><font face="宋体" size="3">　　<strong>5.&nbsp;创建您所知道的。</strong>&nbsp;</font></p>
<p><font face="宋体" size="3">　　反复的开发工作将使您能够逐渐地掌握所有的&nbsp;J2EE&nbsp;模块。要从创建小而简单的模块开始而不是从一开始就马上涉及到所有的模块。&nbsp;</font></p>
<p><font face="宋体" size="3">　　我们必须承认&nbsp;J2EE&nbsp;是庞大的体系。如果一个开发小组只是开始使用&nbsp;J2EE，这将很难一下子就能掌握它。在&nbsp;J2EE&nbsp;中有太多的概念和&nbsp;API&nbsp;需要掌握。在这种情况下，成功掌握&nbsp;J2EE&nbsp;的关键是从简单的步骤开始做起。&nbsp;</font></p>
<p><font face="宋体" size="3">　　这种方法可以通过在您的应用程序中创建小而简单的模块来得到最好的实现。如果一个开发小组通过创建一个简单的域模型以及后端的持久性机制（也许使用的是&nbsp;JDBC）,并且对其进行了完整的测试，这会增强他们的自信心，于是他们会使用该域模型去掌握使用&nbsp;servlet&nbsp;和&nbsp;JSP&nbsp;的前端开发。如果一个开发组发现有必要使用&nbsp;EJB，他们也会类似地开始在容器管理的持久性&nbsp;EJB&nbsp;组件之上使用简单的会话&nbsp;Facades，或者使用基于&nbsp;JDBC&nbsp;的数据访问对象（JDBC-based&nbsp;Data&nbsp;Access&nbsp;Objects，DAO），而不是跳过这些去使用更加复杂的构造（例如消息驱动bean和JMS）。&nbsp;</font></p>
<p><font face="宋体" size="3">　　这种方法并不是什么新方法，但是很少有开发组以这种方式来培养他们的技能。相反地，多数开发组由于尝试马上就构建所有的模块，同时涉及&nbsp;MVC&nbsp;中的视图层、模型层和控制器层，这样做的结果是他们往往会陷入进度的压力之中。他们应该考虑一些敏捷（Agile）开发方法，例如极限编程（XP），这种开发方法采用一种增量学习及开发方法。在&nbsp;XP&nbsp;中有一种称为&nbsp;ModelFirst&nbsp;的过程，这个过程涉及到首先构建域模型作为一种机制来组织和实现用户场景。基本说来，您要构建域模型作为您要实现的用户场景的首要部分，然后在域模型之上构建一个用户界面（UI）作为用户场景实现的结果。这种方法非常适合让一个开发组一次只学到一种技术，而不是让他们同时面对很多种情况（或者让他们读很多书），这会令他们崩溃的。&nbsp;</font></p>
<p><font face="宋体" size="3">　　还有，对每个应用程序层重复的开发可能会包含一些适当的模式及最佳实践。如果您从应用程序的底层开始应用一些模式如数据访问对象和会话&nbsp;Facades，您就不应该在您的JSP和其他视图对象中使用域逻辑。&nbsp;</font></p>
<p><font face="宋体" size="3">　　最后，当您开发一些简单的模块时，在开始的初期就可以对您的应用程序进行性能测试。如果直到应用程序开发的后期才进行性能测试的话，这往往会出现灾难性的后果。&nbsp;</font></p>
<p><font face="宋体" size="3">　　<strong>6.&nbsp;当使用&nbsp;EJB&nbsp;组件时，始终使用会话&nbsp;Facades。</strong>&nbsp;</font></p>
<p><font face="宋体" size="3">　　决不要将实体&nbsp;bean&nbsp;直接暴露给任何用户类型。对实体&nbsp;bean&nbsp;只可以使用本地&nbsp;EJB&nbsp;接口（Local&nbsp;EJB&nbsp;interfaces）。&nbsp;</font></p>
<p><font face="宋体" size="3">　　当使用&nbsp;EJB&nbsp;组件时，使用一个会话&nbsp;Facades&nbsp;是一个确认无疑的最佳实践。实际上，这个通用的实践被广泛地应用到任何分布式的技术中，包括&nbsp;CORBA、EJB&nbsp;和&nbsp;DCOM。从根本上讲，您的应用程序的分布"交叉区域"越是底层化，对小块的数据由于多次重复的网络中继造成的时间消耗就越少。要达到这个目的的方法就是：创建大粒度的&nbsp;Facades&nbsp;对象，这个对象包含逻辑子系统，因而可以通过一个方法调用就可以完成一些有用的业务功能。这种方法不但能够降低网络开销，而且在&nbsp;EJB&nbsp;内部通过为整个业务功能创建一个事务环境也可以大大地减少对数据库的访问次数。&nbsp;</font></p>
<p><font face="宋体" size="3">　　EJB&nbsp;本地接口（从&nbsp;EJB&nbsp;2.0&nbsp;规范开始使用）为共存的&nbsp;EJB&nbsp;提供了性能优化方法。本地接口必须被您的应用程序显式地进行访问，这需要代码的改变和防止以后配置&nbsp;EJB&nbsp;时需要应用程序的改变。由于会话&nbsp;Facades&nbsp;和它包含的整个&nbsp;EJB&nbsp;对于彼此来说都应该是本地的，我们建议对会话&nbsp;Facades&nbsp;后面的实体&nbsp;bean&nbsp;使用本地接口。然而，会话&nbsp;Facades&nbsp;本身的实现（典型例子如无状态会话&nbsp;bean）应该设计为远程接口。&nbsp;</font></p>
<p><font face="宋体" size="3">　　为了性能的优化，可以将一个本地接口添加到会话&nbsp;Facades。这样做利用了这样一个事实：在大多数情况下（至少在&nbsp;Web&nbsp;应用程序中），您的&nbsp;EJB&nbsp;客户端和&nbsp;EJB&nbsp;会共同存在于同一个&nbsp;Java&nbsp;虚拟机（JVM）中。另外一种情况，如果会话&nbsp;Facades&nbsp;在本地被调用，可以使用&nbsp;J2EE&nbsp;应用服务器配置优化（configuration&nbsp;optimizations），例如&nbsp;WebSphere&nbsp;中的"No&nbsp;Local&nbsp;Copies"。然而，您必须注意到这些可供选择的方案会将交互方法从按值传递（pass-by-value）改变为按引用传递（pass-by-reference）。这可能会在您的代码中产生很微妙的错误。当您要利用这些方案时，您应该在一开始就考虑其可行性。&nbsp;</font></p>
<p><font face="宋体" size="3">　　如果在您的会话&nbsp;Facades&nbsp;中使用远程接口（而不是本地接口），您也可以将同样的会话&nbsp;Facades&nbsp;在&nbsp;J2EE&nbsp;1.4&nbsp;中以兼容的方式作为&nbsp;Web&nbsp;服务来配置。这是因为&nbsp;JSR&nbsp;109（J2EE&nbsp;1.4&nbsp;中的&nbsp;Web&nbsp;服务部署部分）要求使用无状态会话&nbsp;bean&nbsp;的远程接口作为&nbsp;EJB&nbsp;Web&nbsp;服务和&nbsp;EJB&nbsp;实现的接口。这样做是值得的，因为这样做可以为您的业务逻辑增加客户端类型的数量。&nbsp;</font></p>
<p><font face="宋体" size="3">　　<strong>7.&nbsp;使用无状态会话&nbsp;bean，而不是有状态会话&nbsp;bean。</strong>&nbsp;</font></p>
<p><font face="宋体" size="3">　　这样做可以使您的系统经得起错误的终止。使用&nbsp;HttpSession&nbsp;存储和用户相关的状态。&nbsp;</font></p>
<p><font face="宋体" size="3">　　以我们的观点看来，有状态会话&nbsp;bean&nbsp;的概念已经过时了。如果您仔细对其考虑一下，一个有状态会话&nbsp;bean&nbsp;实际上与一个&nbsp;CORBA&nbsp;对象在体系结构上是完全相同的，无非就是一个对象实例，绑定到一个服务器，并且依赖于服务器来管理其生命周期。如果服务器关闭了，这种对象也就不存在，那么这个&nbsp;bean&nbsp;的客户端的信息也就不存在。&nbsp;</font></p>
<p><font face="宋体" size="3">　　J2EE&nbsp;应用服务器为有状态会话&nbsp;bean&nbsp;提供的故障转移（failover）能够解决一些问题，但是有状态的解决方案没有无状态的解决方案易于扩展。例如，在&nbsp;WebSphere&nbsp;Application&nbsp;Server&nbsp;中，对无状态会话&nbsp;bean&nbsp;的请求，是通过对部署无状态会话的成员集群进行平衡加载来实现。相反地，J2EE&nbsp;应用服务器不能对有状态&nbsp;bean&nbsp;的请求进行平衡加载。这意味着您的集群中的服务器的加载过程会是不均衡的。此外，使用有状态会话&nbsp;bean&nbsp;将会再添加一些状态到您的应用服务器上，这也是不好的做法。这样就增加了系统的复杂性，并且在出现故障的情况下使问题变得复杂化。创建健壮的分布式系统的一个关键原则是尽量使用无状态行为。&nbsp;</font></p>
<p><font face="宋体" size="3">　　因此，我们建议对大多数应用程序使用无状态会话&nbsp;bean&nbsp;方法。任何在处理时需要使用的与用户相关的状态应该以参数的形式传送到&nbsp;EJB&nbsp;的方法中（并且通过使用一种机制如&nbsp;HttpSession&nbsp;来存储它）或者从持久性的后端存储（例如通过使用实体&nbsp;bean)作为&nbsp;EJB&nbsp;事务的一部分来进行检索。在合适的情况下，这个信息可以缓存到内存中，但是要注意在分布式的环境中保存这种缓存所潜在的挑战性。缓存非常适合于只读数据。&nbsp;</font></p>
<p><font face="宋体" size="3">　　总之，您要确保从一开始就要考虑到可伸展性。检查设计中的所有设想，并且考虑到当您的应用程序要在多个服务器上运行时，是否也可以正常运行。这个规则不但适合上述情况的应用程序代码，也适用于如&nbsp;MBean&nbsp;和其他管理界面的情况下。&nbsp;</font></p>
<p><font face="宋体" size="3">　　避免使用有状态性不只是对&nbsp;IBM/WebSphere&nbsp;的建议，这是一个基本的&nbsp;J2EE&nbsp;设计原则。&nbsp;</font></p>
<p><font face="宋体" size="3">　　<strong>8.&nbsp;使用容器管理的事务。</strong>&nbsp;</font></p>
<p><font face="宋体" size="3">　　学习一下&nbsp;J2EE&nbsp;中的两阶段提交事务，并且使用这种方式，而不是开放您自己的事务管理。容器在事务优化方面几乎总是比较好的。&nbsp;</font></p>
<p><font face="宋体" size="3">　　使用容器管理的事务（CMT）提供了两个关键的优势（如果没有容器支持这几乎是不可能的）：可组合的工作单元和健壮的事务行为。&nbsp;</font></p>
<p><font face="宋体" size="3">　　如果您的应用程序代码显式地使用了开始和结束事务（也许使用&nbsp;javax.jts.UserTransaction&nbsp;或者甚至是本地资源事务），而将来的要求需要组合模块（也许会是代码重构的一部分），这种情况下往往需要改变事务代码。例如，如果模块&nbsp;A&nbsp;开始了一个数据库事务，更新数据库，随后提交事务，并且有模块&nbsp;B&nbsp;做出同样的处理，请考虑一下当您在模块&nbsp;C&nbsp;中尝试使用上述两个模块，会出现什么情况呢？现在，模块&nbsp;C&nbsp;正在执行一个逻辑动作，而这个动作实际上将调用两个独立的事务。如果模块&nbsp;B&nbsp;在执行中失败了，而模块&nbsp;A&nbsp;的事务仍然能被提交。这是我们所不希望出现的行为。如果，相反地，模块&nbsp;A&nbsp;和模块&nbsp;B&nbsp;都使用&nbsp;CMT&nbsp;的话，模块&nbsp;C&nbsp;也可以开始一个&nbsp;CMT（通常通过配置描述符），并且在模块&nbsp;A&nbsp;和模块&nbsp;B&nbsp;中的事务将是同一个事务的隐含部分，这样就不再需要复杂的重写代码的工作了。&nbsp;</font></p>
<p><font face="宋体" size="3">　　如果您的应用程序在同一个操作中需要访问多种资源，您就要使用两阶段提交事务。例如，如果从&nbsp;JMS&nbsp;队列中删除一个消息，并且随后更新基于这条消息的纪录，这时，要保证这两个操作都会执行或都不会执行就变得尤为重要。如果一条消息已经从队列中被删除，而系统没有更新与此消息相关的数据库中的纪录，那么这种系统是不稳定的。一些严重的客户及商业纠纷源自不一致的状态。&nbsp;</font></p>
<p><font face="宋体" size="3">　　我们时常看到一些客户应用程序试图实现他们自己的解决方案。也许会通过应用程序的代码在数据库更新失败的时候&nbsp;"撤销"对队列的操作。我们不提倡这样做。这种实现要比您最初的想象要复杂得多，并且还有许多其他的情况（想象一下如果应用程序在执行此操作的过程中突然崩溃的情况）。作为替代的方式，应该使用两阶段提交事务。如果您使用&nbsp;CMT，并且在一个单一的&nbsp;CMT&nbsp;中访问两阶段提交的资源（例如&nbsp;JMS&nbsp;和大多数数据库），WebSphere&nbsp;将会处理所有的复杂工作。它将确保整个事务被执行或者都不被执行，包括系统崩溃、数据库崩溃或其他的情况。其实现在事务日志中保存着事务状态。当应用程序访问多种资源的时候，我们怎么强调使用&nbsp;CMT&nbsp;事务的必要性都不为过。&nbsp;</font></p>
<p><font face="宋体" size="3">　　<strong>9.&nbsp;将&nbsp;JSP&nbsp;作为表示层的首选。</strong>&nbsp;</font></p>
<p><font face="宋体" size="3">　　只有在需要多种表示输出类型，并且输出类型被一个单一的控制器及后端支持时才使用&nbsp;XML/XSLT。&nbsp;</font></p>
<p><font face="宋体" size="3">　　我们常听到一些争论说，为什么您选择&nbsp;XML/XSLT&nbsp;而不是&nbsp;JSP&nbsp;作为表示层技术。选择&nbsp;XML/XSLT&nbsp;的人的观点是，JSP"&nbsp;允许您将模型和视图混合在一起"，而&nbsp;XML/XSLT&nbsp;不会有这种问题。遗憾的是，这种观点并不完全正确，或者至少不像白与黑那样分的清楚。实际上，XSL&nbsp;和&nbsp;XPath&nbsp;是编程语言。XSL&nbsp;是图灵完成的（Turing-complete），尽管它不符合大多数人定义的编程语言，因为它是基于规则的，并且不具备程序员习惯的控制工具。&nbsp;</font></p>
<p><font face="宋体" size="3">　　现在的问题是既然给予了这种灵活性，开发人员就会利用这种灵活性。尽管每个人都认同&nbsp;JSP&nbsp;使开发人员容易在视图中加入"类似模型"的行为，而实际上，在&nbsp;XSL&nbsp;中也有可能做出一些同样的事情。尽管从&nbsp;XSL&nbsp;中进行访问数据库这样的事情会非常困难，但是我们曾经见到过一些异常复杂的&nbsp;XSLT&nbsp;样式表执行复杂的转换，这实际上是模型代码。&nbsp;</font></p>
<p><font face="宋体" size="3">　　然而，应该选择&nbsp;JSP&nbsp;作为首选的表示技术的最基本的原因是，JSP&nbsp;是现在支持最广泛的、也是最被广泛理解的&nbsp;J2EE&nbsp;视图技术。而随着自定义标记库、JSTL&nbsp;和&nbsp;JSP2.0&nbsp;的新特性的引入，创建&nbsp;JSP&nbsp;变得更加容易，并且不需要任何&nbsp;Java&nbsp;代码，以及可以将模型和视图清晰的分离开。在一些开发环境中（如&nbsp;WebSphere&nbsp;Studio）加入了对&nbsp;JSP（包括对调试的支持）的强大支持，并且许多开发人员发现使用&nbsp;JSP&nbsp;进行开发要比使用&nbsp;XLS&nbsp;简单，一些支持&nbsp;JSP&nbsp;的图形设计工具及其他特征（尤其在&nbsp;JSF&nbsp;这样的框架下）使得开发人员可以以所见即所得的方式进行&nbsp;JSP&nbsp;的开发，而对于&nbsp;XSL&nbsp;有时不容易做到。&nbsp;</font></p>
<p><font face="宋体" size="3">　　最后一个要谨慎考虑使用&nbsp;JSP&nbsp;的原因是速度问题。在&nbsp;IBM&nbsp;所作的对比&nbsp;XSL&nbsp;和&nbsp;JSP&nbsp;相对速度的性能测试显示：在大多数情况下，JSP&nbsp;在生成同样的&nbsp;HTML&nbsp;的时候，要比&nbsp;XSL&nbsp;快好几倍，甚至使用编译过的&nbsp;XSL&nbsp;也是如此。尽管多数情况下这不是问题，但在性能要求很高的情况下，这就会成为问题。&nbsp;</font></p>
<p><font face="宋体" size="3">　　然而，这也不能说，您永远也不要使用&nbsp;XSL。在一些情况下，XSL&nbsp;能够表示一组固定的数据，并且可以基于不同的样式表来以不同的方式显示这些数据的能力是显示视图的最佳解决方案。然而，这只是一种例外的情况，而不是通用的规则。如果您只是生成&nbsp;HTML&nbsp;来表达每一个页面，那么在大多数情况下，XSL&nbsp;是一种不必要的技术，并且，它给您的开发人员所带来的问题远比它所能解决的问题多。&nbsp;</font></p>
<p><font face="宋体" size="3">　　<strong>10.&nbsp;当使用&nbsp;HttpSession&nbsp;时，尽量只将当前事务所需要的状态保存其中，其他内容不要保存在&nbsp;HttpSession&nbsp;中。</strong>&nbsp;</font></p>
<p><font face="宋体" size="3">　　启用会话持久性。&nbsp;</font></p>
<p><font face="宋体" size="3">　　HttpSessions&nbsp;对于存储应用程序状态信息是非常有用的。其&nbsp;API&nbsp;易于使用和理解。遗憾的是，开发人员常常遗忘了&nbsp;HttpSession&nbsp;的目的----用来保持暂时的用户状态。它不是任意的数据缓存。我们已经见到过太多的系统为每个用户的会话放入了大量的数据（达到兆字节）。那好了，如果同时有&nbsp;1000&nbsp;个登录系统的用户，每个用户拥有&nbsp;1MB&nbsp;的会话数据，那么就需要&nbsp;1G&nbsp;或者更多的内存用于这些会话。要使这些&nbsp;HTTP&nbsp;会话数据较小一些，不然的话，您的应用程序的性能将会下降。一个大约比较合适的数据量应该是每个用户的会话数据在&nbsp;2K-4K&nbsp;之间，这不是一个硬性的规则，8K&nbsp;仍然没有问题，但是显然会比&nbsp;2K&nbsp;时的速度要慢。一定要注意，不要使&nbsp;HttpSession&nbsp;变成数据堆积的场所。&nbsp;</font></p>
<p><font face="宋体" size="3">　　一个常见的问题是使用&nbsp;HttpSession&nbsp;缓存一些很容易再创建的信息，如果有必要的话。由于会话是持久性的，进行不必要的序列化以及写入数据是一种很奢侈的决定。相反地，应该使用内存中的哈希表来缓存数据，并且在会话中保存一个对此数据进行引用的关键字。这样，如果不能成功登录到另外的应用服务器的话，就可以重新创建数据。&nbsp;</font></p>
<p><font face="宋体" size="3">　　当谈及会话持久性时，不要忘记要启用这项功能。如果您没有启用会话持久性，或者服务器因为某种原因停止了（服务器故障或正常的维护），则所有此应用服务的当前用户的会话将会丢失。这是件令人非常不高兴的事情。用户不得不重新登录，并且重新做一些他们曾经已经做过的事情。相反地，如果启用了会话持久性，WebSphere&nbsp;会自动将用户（以及他们的会话）移到另外一个应用服务器上去。用户甚至不知道会有这种事情的发生。我们曾经见到过一些产品系统因为存在于本地代码中令人难以忍受的&nbsp;bug（不是&nbsp;IBM&nbsp;的代码！）而突然崩溃的情况，这这种情况下，上述功能仍然可以运行良好。&nbsp;</font></p>
<p><font face="宋体" size="3">　　<strong>11.&nbsp;在&nbsp;WebSphere&nbsp;中，使用动态缓存，并使用&nbsp;WebSphere&nbsp;servlet&nbsp;缓存机制。</strong>&nbsp;</font></p>
<p><font face="宋体" size="3">　　通过使用这些功能，系统性能可以得到很大的提高，而开销是很小的。并且不影响编程模型。&nbsp;</font></p>
<p><font face="宋体" size="3">　　通过缓存来提高性能的好处是众所周知的事情。遗憾的是，当前的&nbsp;J2EE&nbsp;规范没有包括一种用于&nbsp;servlet/JSP&nbsp;缓存的机制。然而，WebSphere&nbsp;提供了对页面以及片断缓存的支持，这种支持是通过其动态缓存功能来实现的，并且不需要对应用程序作出任何改变。其缓存的策略是声明性的，而且其配置是通过&nbsp;XML&nbsp;配置描述符来实现的。因此，您的应用程序不会受到影响，并保持与&nbsp;J2EE&nbsp;规范的兼容性和移植性，同时还从&nbsp;WebSphere&nbsp;的&nbsp;servlet&nbsp;及&nbsp;JSP&nbsp;的缓存机制中得到性能的优化。&nbsp;</font></p>
<p><font face="宋体" size="3">　　从&nbsp;servet&nbsp;及&nbsp;JSP&nbsp;的动态缓存机制得到的性能的提高是显而易见的，这取决于应用程序的特性。Cox&nbsp;和&nbsp;Martin&nbsp;[Cox]&nbsp;指出对一个现有的&nbsp;RDF（资源描述格式）站点摘要&nbsp;(RSS)servlet，当使用动态缓存时，其性能可以提高&nbsp;10%。请注意这个实验只涉及到一个简单的&nbsp;servlet，这个性能的增长量可能并不能反映一个复杂的应用程序。&nbsp;</font></p>
<p><font face="宋体" size="3">　　为了更多地提高性能，将&nbsp;WebSphere&nbsp;servlet/JSP&nbsp;结果缓存与&nbsp;WebSphere&nbsp;插件&nbsp;ESI&nbsp;Fragment&nbsp;处理器、IBM&nbsp;HTTP&nbsp;Server&nbsp;Fast&nbsp;Response&nbsp;Cache&nbsp;Accelerator&nbsp;(FRCA)&nbsp;和&nbsp;Edge&nbsp;Server&nbsp;缓存功能集成在一起。对于繁重的基于读取的工作负荷，通过使用这些功能可以得到许多额外的好处。&nbsp;</font></p>
<p><font face="宋体" size="3">　　<strong>12.&nbsp;为了提高程序员的工作效率，将&nbsp;CMP&nbsp;实体&nbsp;bean&nbsp;作为&nbsp;O/R&nbsp;映射的首选解决方案.</strong>&nbsp;</font></p>
<p><font face="宋体" size="3">　　通过&nbsp;WebSphere&nbsp;框架（readahead、缓存、隔离级别等）优化性能。如果可能，有选择的应用一些模式来达到提高性能的目的，例如&nbsp;Fast-Lane&nbsp;阅读器&nbsp;[Marinescu]。&nbsp;</font></p>
<p><font face="宋体" size="3">　　对象/关系（O/R）映射是使用&nbsp;Java&nbsp;创建企业级的应用程序的基础。几乎每个&nbsp;J2EE&nbsp;应用程序都需要一些类型的&nbsp;O/R&nbsp;映射。J2EE&nbsp;厂商提供一种&nbsp;O/R&nbsp;映射机制，这种机制在不同的厂商间是可移植的，高效的，并且能够被一些标准及工具很好地支持。这就是&nbsp;EJB&nbsp;规范中的&nbsp;CMP（容器管理的持久性）部分。&nbsp;</font></p>
<p><font face="宋体" size="3">　　早期的&nbsp;CMP&nbsp;实现以表现不佳及不支持许多&nbsp;SQL&nbsp;结构而著称。然而，随着&nbsp;EJB&nbsp;2.0&nbsp;及&nbsp;2.1&nbsp;规范的出现，以及被一些厂商所采纳，并且随着像&nbsp;IBM&nbsp;WebSphere&nbsp;Studio&nbsp;Application&nbsp;Developer&nbsp;的出现，这些问题已经不再是问题了。&nbsp;</font></p>
<p><font face="宋体" size="3">　　CMP&nbsp;EJB&nbsp;组件现在已经被广泛地应用于许多高性能的应用程序中。WebSphere&nbsp;包括一些优化功能以提高&nbsp;EJB&nbsp;组件的性能，优化功能包括：对生命周期的缓存和&nbsp;read-ahead&nbsp;能力。这两者优化功能都是配置时的选项，并且不需要对应用程序进行修改或者影响可移植性。&nbsp;</font></p>
<p><font face="宋体" size="3">　　处于缓存状态的生命周期缓存&nbsp;CMP&nbsp;状态数据并提供基于时间的无效性。从处于缓存状态的生命周期得到的性能提高可以达到选项&nbsp;A&nbsp;的缓存性能，并且仍然可以为您的应用程序提供可伸展性。Read-ahead&nbsp;能力和容器管理的关系结合使用。这个特性通过在相同的查询中随意地检索相关的数据作为父数据而减少与数据库的交互。如果相关的数据要通过使用并发的查询来访问的话，这种方法可以得到性能的改进。[Gunther]提供了详细的描述以及通过这些特性得到的性能提高的细节。&nbsp;</font></p>
<p><font face="宋体" size="3">　　此外，为了完全优化您的&nbsp;EJB&nbsp;组件，当指定隔离级别时要特别注意。尽可能使用最低的隔离级别，并且仍然保持您的数据的完整性。较低的隔离级别可以提供最佳的性能，并且可以降低出现数据库死锁的危险。&nbsp;</font></p>
<p><font face="宋体" size="3">　　这是目前最有争议的最佳实践。已经有大量的文章赞扬&nbsp;CMP&nbsp;EJB，同样的贬斥声也不绝于耳。然而，这里最基本的问题是数据库开发是困难的。当您开始使用任何持久性解决方案之前，您需要掌握查询以及数据库锁定如何工作这些基础知识。如果您选择使用&nbsp;CMP&nbsp;EJB，您要确保您已经通过一些书籍（例如&nbsp;[Brown]&nbsp;和&nbsp;[Barcia]）知道如何使用它们。在锁定及争用方面有一些微妙的交互难以理解，但是，在您耗费一定的时间及努力后会将其掌握的。&nbsp;</font></p>
<p><font face="宋体" size="3">　　<strong>结束语</strong>&nbsp;</font></p>
<p><font face="宋体" size="3">　　在这个简短的摘要中，我们已经向您介绍了&nbsp;J2EE&nbsp;中的核心模式和最佳实践，这使得&nbsp;J2EE&nbsp;开发成为一种可管理的过程。尽管我们并没有给出所有在实践中使用这些模式的必要细节，但是我们希望能够给您足够的指点和指导，以帮助您决定下一步要做什么。</font></p>
<img src ="http://www.blogjava.net/WshmAndLily/aggbug/143460.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/WshmAndLily/" target="_blank">semovy</a> 2007-09-07 16:17 <a href="http://www.blogjava.net/WshmAndLily/articles/143460.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HTTP协议基础</title><link>http://www.blogjava.net/WshmAndLily/articles/143459.html</link><dc:creator>semovy</dc:creator><author>semovy</author><pubDate>Fri, 07 Sep 2007 08:14:00 GMT</pubDate><guid>http://www.blogjava.net/WshmAndLily/articles/143459.html</guid><wfw:comment>http://www.blogjava.net/WshmAndLily/comments/143459.html</wfw:comment><comments>http://www.blogjava.net/WshmAndLily/articles/143459.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/WshmAndLily/comments/commentRss/143459.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/WshmAndLily/services/trackbacks/143459.html</trackback:ping><description><![CDATA[HTTP（HyperTextTransferProtocol）是超文本传输协议的缩写，它用于传送WWW方式的数据，关于HTTP协议的详细内容请参考RFC2616。HTTP协议采用了请求/响应模型。客户端向服务器发送一个请求，请求头包含请求的方法、URI、协议版本、以及包含请求修饰符、客户信息和内容的类似于MIME的消息结构。服务器以一个状态行作为响应，相应的内容包括消息协议的版本，成功或者错误编码加上包含服务器信息、实体元信息以及可能的实体内容。
<p style="text-indent: 2em">通常HTTP消息包括客户机向服务器的请求消息和服务器向客户机的响应消息。这两种类型的消息由一个起始行，一个或者多个头域，一个只是头域结束的空行和可选的消息体组成。HTTP的头域包括通用头，请求头，响应头和实体头四个部分。每个头域由一个域名，冒号（:）和域值三部分组成。域名是大小写无关的，域值前可以添加任何数量的空格符，头域可以被扩展为多行，在每行开始处，使用至少一个空格或制表符。</p>
<p style="text-indent: 2em">通用头域</p>
<p style="text-indent: 2em">通用头域包含请求和响应消息都支持的头域，通用头域包含Cache-Control、Connection、Date、Pragma、Transfer-Encoding、Upgrade、Via。对通用头域的扩展要求通讯双方都支持此扩展，如果存在不支持的通用头域，一般将会作为实体头域处理。下面简单介绍几个在UPnP消息中使用的通用头域。</p>
<p style="text-indent: 2em">Cache-Control头域</p>
<p style="text-indent: 2em">Cache-Control指定请求和响应遵循的缓存机制。在请求消息或响应消息中设置Cache-Control并不会修改另一个消息处理过程中的缓存处理过程。请求时的缓存指令包括no-cache、no-store、max-age、max-stale、min-fresh、only-if-cached，响应消息中的指令包括public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age。各个消息中的指令含义如下：</p>
<p style="text-indent: 2em">Public指示响应可被任何缓存区缓存。</p>
<p style="text-indent: 2em">Private指示对于单个用户的整个或部分响应消息，不能被共享缓存处理。这允许服务器仅仅描述当用户的部分响应消息，此响应消息对于其他用户的请求无效。</p>
<p style="text-indent: 2em">no-cache指示请求或响应消息不能缓存</p>
<p style="text-indent: 2em">no-store用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存。</p>
<p style="text-indent: 2em">max-age指示客户机可以接收生存期不大于指定时间（以秒为单位）的响应。</p>
<p style="text-indent: 2em">min-fresh指示客户机可以接收响应时间小于当前时间加上指定时间的响应。</p>
<p style="text-indent: 2em">max-stale指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值，那么客户机可以接收超出超时期指定值之内的响应消息。</p>
<p style="text-indent: 2em">Date头域</p>
<p style="text-indent: 2em">Date头域表示消息发送的时间，时间的描述格式由rfc822定义。例如，Date:Mon,31Dec200104:25:57GMT。Date描述的时间表示世界标准时，换算成本地时间，需要知道用户所在的时区。</p>
<p style="text-indent: 2em">Pragma头域</p>
<p style="text-indent: 2em">Pragma头域用来包含实现特定的指令，最常用的是Pragma:no-cache。在HTTP/1.1协议中，它的含义和Cache-Control:no-cache相同。</p>
<p style="text-indent: 2em">请求消息</p>
<p style="text-indent: 2em">请求消息的第一行为下面的格式：</p>
<p style="text-indent: 2em">MethodSPRequest-URISPHTTP-VersionCRLFMethod表示对于Request-URI完成的方法，这个字段是大小写敏感的，包括OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE。方法GET和HEAD应该被所有的通用WEB服务器支持，其他所有方法的实现是可选的。GET方法取回由Request-URI标识的信息。HEAD方法也是取回由Request-URI标识的信息，只是可以在响应时，不返回消息体。POST方法可以请求服务器接收包含在请求中的实体信息，可以用于提交表单，向新闻组、BBS、邮件群组和数据库发送消息。</p>
<p style="text-indent: 2em">SP表示空格。Request-URI遵循URI格式，在此字段为星号（*）时，说明请求并不用于某个特定的资源地址，而是用于服务器本身。HTTP-Version表示支持的HTTP版本，例如为HTTP/1.1。CRLF表示换行回车符。请求头域允许客户端向服务器传递关于请求或者关于客户机的附加信息。请求头域可能包含下列字段Accept、Accept-Charset、Accept-Encoding、Accept-Language、Authorization、From、Host、If-Modified-Since、If-Match、If-None-Match、If-Range、If-Range、If-Unmodified-Since、Max-Forwards、Proxy-Authorization、Range、Referer、User-Agent。对请求头域的扩展要求通讯双方都支持，如果存在不支持的请求头域，一般将会作为实体头域处理。</p>
<p style="text-indent: 2em">典型的请求消息：</p>
<p style="text-indent: 2em">GEThttp://download.microtool.de:80/somedata.exe</p>
<p style="text-indent: 2em">Host:download.microtool.de</p>
<p style="text-indent: 2em">Accept:*/*</p>
<p style="text-indent: 2em">Pragma:no-cache</p>
<p style="text-indent: 2em">Cache-Control:no-cache</p>
<p style="text-indent: 2em">Referer:http://download.microtool.de/</p>
<p style="text-indent: 2em">User-Agent:Mozilla/4.04[en](Win95;I;Nav)</p>
<p style="text-indent: 2em">Range:bytes=554554-</p>
<p style="text-indent: 2em">上例第一行表示HTTP客户端（可能是浏览器、下载程序）通过GET方法获得指定URL下的文件。棕色的部分表示请求头域的信息，绿色的部分表示通用头部分。</p>
<p style="text-indent: 2em">Host头域</p>
<p style="text-indent: 2em">Host头域指定请求资源的Intenet主机和端口号，必须表示请求url的原始服务器或网关的位置。HTTP/1.1请求必须包含主机头域，否则系统会以400状态码返回。</p>
<p style="text-indent: 2em">Referer头域</p>
<p style="text-indent: 2em">Referer头域允许客户端指定请求uri的源资源地址，这可以允许服务器生成回退链表，可用来登陆、优化cache等。他也允许废除的或错误的连接由于维护的目的被追踪。如果请求的uri没有自己的uri地址，Referer不能被发送。如果指定的是部分uri地址，则此地址应该是一个相对地址。</p>
<p style="text-indent: 2em">Range头域</p>
<p style="text-indent: 2em">Range头域可以请求实体的一个或者多个子范围。例如，</p>
<p style="text-indent: 2em">表示头500个字节：bytes=0-499</p>
<p style="text-indent: 2em">表示第二个500字节：bytes=500-999</p>
<p style="text-indent: 2em">表示最后500个字节：bytes=-500</p>
<p style="text-indent: 2em">表示500字节以后的范围：bytes=500-</p>
<p style="text-indent: 2em">第一个和最后一个字节：bytes=0-0,-1</p>
<p style="text-indent: 2em">同时指定几个范围：bytes=500-600,601-999</p>
<p style="text-indent: 2em">但是服务器可以忽略此请求头，如果无条件GET包含Range请求头，响应会以状态码206（PartialContent）返回而不是以200（OK）。</p>
<p style="text-indent: 2em">User-Agent头域</p>
<p style="text-indent: 2em">User-Agent头域的内容包含发出请求的用户信息。</p>
<p style="text-indent: 2em">响应消息</p>
<p style="text-indent: 2em">响应消息的第一行为下面的格式：</p>
<p style="text-indent: 2em">HTTP-VersionSPStatus-CodeSPReason-PhraseCRLF</p>
<p style="text-indent: 2em">HTTP-Version表示支持的HTTP版本，例如为HTTP/1.1。Status-Code是一个三个数字的结果代码。Reason-Phrase给Status-Code提供一个简单的文本描述。Status-Code主要用于机器自动识别，Reason-Phrase主要用于帮助用户理解。Status-Code的第一个数字定义响应的类别，后两个数字没有分类的作用。第一个数字可能取5个不同的值：</p>
<p style="text-indent: 2em">1xx:信息响应类，表示接收到请求并且继续处理</p>
<p style="text-indent: 2em">2xx:处理成功响应类，表示动作被成功接收、理解和接受</p>
<p style="text-indent: 2em">3xx:重定向响应类，为了完成指定的动作，必须接受进一步处理</p>
<p style="text-indent: 2em">4xx:客户端错误，客户请求包含语法错误或者是不能正确执行</p>
<p style="text-indent: 2em">5xx:服务端错误，服务器不能正确执行一个正确的请求</p>
<p style="text-indent: 2em">响应头域允许服务器传递不能放在状态行的附加信息，这些域主要描述服务器的信息和Request-URI进一步的信息。响应头域包含Age、Location、Proxy-Authenticate、Public、Retry-After、Server、Vary、Warning、WWW-Authenticate。对响应头域的扩展要求通讯双方都支持，如果存在不支持的响应头域，一般将会作为实体头域处理。</p>
<p style="text-indent: 2em">典型的响应消息：</p>
<p style="text-indent: 2em">HTTP/1.0200OK</p>
<p style="text-indent: 2em">Date:Mon,31Dec200104:25:57GMT</p>
<p style="text-indent: 2em">Server:Apache/1.3.14(Unix)</p>
<p style="text-indent: 2em">Content-type:text/html</p>
<p style="text-indent: 2em">Last-modified:Tue,17Apr200106:46:28GMT</p>
<p style="text-indent: 2em">Etag:"a030f020ac7c01:1e9f"</p>
<p style="text-indent: 2em">Content-length:39725426</p>
<p style="text-indent: 2em">Content-range:bytes554554-40279979/40279980</p>
<p style="text-indent: 2em">上例第一行表示HTTP服务端响应一个GET方法。棕色的部分表示响应头域的信息，绿色的部分表示通用头部分，红色的部分表示实体头域的信息。</p>
<p style="text-indent: 2em">Location响应头</p>
<p style="text-indent: 2em">Location响应头用于重定向接收者到一个新URI地址。</p>
<p style="text-indent: 2em">Server响应头</p>
<p style="text-indent: 2em">Server响应头包含处理请求的原始服务器的软件信息。此域能包含多个产品标识和注释，产品标识一般按照重要性排序。</p>
<p style="text-indent: 2em">实体</p>
<p style="text-indent: 2em">请求消息和响应消息都可以包含实体信息，实体信息一般由实体头域和实体组成。实体头域包含关于实体的原信息，实体头包括Allow、Content-Base、Content-Encoding、Content-Language、Content-Length、Content-Location、Content-MD5、Content-Range、Content-Type、Etag、Expires、Last-Modified、extension-header。extension-header允许客户端定义新的实体头，但是这些域可能无法未接受方识别。实体可以是一个经过编码的字节流，它的编码方式由Content-Encoding或Content-Type定义，它的长度由Content-Length或Content-Range定义。</p>
<p style="text-indent: 2em">Content-Type实体头</p>
<p style="text-indent: 2em">Content-Type实体头用于向接收方指示实体的介质类型，指定HEAD方法送到接收方的实体介质类型，或GET方法发送的请求介质类型Content-Range实体头</p>
<p style="text-indent: 2em">Content-Range实体头用于指定整个实体中的一部分的插入位置，他也指示了整个实体的长度。在服务器向客户返回一个部分响应，它必须描述响应覆盖的范围和整个实体长度。一般格式：</p>
<p style="text-indent: 2em">Content-Range:bytes-unitSPfirst-byte-pos-last-byte-pos/entity-legth</p>
<p style="text-indent: 2em">例如，传送头500个字节次字段的形式：Content-Range:bytes0-499/1234如果一个http消息包含此节（例如，对范围请求的响应或对一系列范围的重叠请求），Content-Range表示传送的范围，Content-Length表示实际传送的字节数。</p>
<p style="text-indent: 2em">Last-modified实体头</p>
<p style="text-indent: 2em">Last-modified实体头指定服务器上保存内容的最后修订时间。</p>
<img src ="http://www.blogjava.net/WshmAndLily/aggbug/143459.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/WshmAndLily/" target="_blank">semovy</a> 2007-09-07 16:14 <a href="http://www.blogjava.net/WshmAndLily/articles/143459.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Tomcat域名配置</title><link>http://www.blogjava.net/WshmAndLily/articles/143452.html</link><dc:creator>semovy</dc:creator><author>semovy</author><pubDate>Fri, 07 Sep 2007 08:06:00 GMT</pubDate><guid>http://www.blogjava.net/WshmAndLily/articles/143452.html</guid><wfw:comment>http://www.blogjava.net/WshmAndLily/comments/143452.html</wfw:comment><comments>http://www.blogjava.net/WshmAndLily/articles/143452.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/WshmAndLily/comments/commentRss/143452.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/WshmAndLily/services/trackbacks/143452.html</trackback:ping><description><![CDATA[<p>打开tomhome/conf/下的server.xml</p>
<p>添加以下内容：</p>
<p>&lt;Host appBase="C:/aaaa" autoDeploy="true" debug="0" deployXML="true" liveDeploy="true" name="www.xxxxxxxx.com" unpackWARs="true"&gt;<br />
&lt;Context cachingAllowed="true" cookies="true" crossContext="true" debug="0" docBase="C:/aaa/bbb" path="" privileged="false" reloadable="true" swallowOutput="false" useNaming="true" &gt;<br />
&lt;/Context&gt;<br />
&lt;/Host&gt;<br />
仅仅这样还是不够的，配置后，现在输入<a href="http://localhost:8080/"><font color="#414042">http://localhost:8080/</font></a>以及你的IP：8080是没有问题，可是要想从外网访问就必需配置你的hosts文件了。</p>
<p>windows服务器在：C:\WINNT\system32\drivers\etc\下，直接用记事本打开就可以了<br />
例：</p>
<p>
<table bordercolor="#ff9900" cellspacing="0" cellpadding="0" width="100%" bgcolor="#ffffdd" border="1">
    <tbody>
        <tr>
            <td>
            <p># Copyright (c) 1993-1999 Microsoft Corp.<br />
            #<br />
            # This is a sample HOSTS file used by Microsoft TCP/IP for Windows.<br />
            #<br />
            # This file contains the mappings of IP addresses to host names. Each<br />
            # entry should be kept on an individual line. The IP address should<br />
            # be placed in the first column followed by the corresponding host name.<br />
            # The IP address and the host name should be separated by at least one<br />
            # space.<br />
            #<br />
            # Additionally, comments (such as these) may be inserted on individual<br />
            # lines or following the machine name denoted by a '#' symbol.<br />
            #<br />
            # For example:<br />
            #<br />
            #&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 102.54.94.97&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rhino.acme.com&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # source server<br />
            #&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 38.25.63.10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x.acme.com&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # x client host</p>
            <p>127.0.0.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; localhost<br />
            *.*.*.*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://www.***.com/"><font color="#414042">www.***.com</font></a></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>linux服务器在/etc/下,命令行下：vi hosts</p>
<p>例：
<table bordercolor="#ff9900" cellspacing="0" cellpadding="0" width="100%" bgcolor="#ffffdd" border="1">
    <tbody>
        <tr>
            <td># Do not remove the following line, or various programs<br />
            # that require network functionality will fail.<br />
            127.0.0.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; localhost.localdomain&nbsp;&nbsp;&nbsp; localhost&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lkpor1<br />
            *.*.*.*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://www.***.com/"><font color="#414042">www.***.com</font></a><br />
            </td>
        </tr>
    </tbody>
</table>
</p>
如果在Tomcat下面配置域名（如：<a href="http://www.***.com/"><font color="#0000ff">www.***.com</font></a>）的时候，同时又不希望客户通过我们网站的IP或者域名访问到Tomcat默认的ROOT，配制方法如下：<br />
1、打开Tomcat安装目录下的\conf\server.xml文件<br />
2、在server.xml中将原有的&lt;Host name=&#8220;localhost&#8220; appBase=&#8220;webapps&#8220; &#8230;&#8230;&gt;修改为&lt;Host name=&#8220;您要配置的域名&#8220; appBase=&#8220;webapps&#8220;&#8230;&#8230;&gt;<br />
3、在\conf\Catalina目录下建立目录&#8220;&lt;您要配置的域名的名称&gt;&#8221;,然后建立ROOT.xml文件，其格式和\conf\localhost目录下的ROOT.xml一致，但是内容如下：<br />
&nbsp;&nbsp; &lt;?xml version='1.0' encoding='utf-8'?&gt;<br />
&nbsp;&nbsp; &lt;Context displayName="Welcome to 56World!" docBase="D:\workplace\inbuilding" path=""&gt;<br />
&nbsp;&nbsp; &lt;/Context&gt;<br />
其中docBase中的内容就是你希望的打开您的域名（<a href="http://www.***.com/"><font color="#0000ff">www.***.com</font></a>） 的时候映射到的目录和默认的网页（如：index.jsp）<br />
4、启动Tomcat服务器，就可以直接敲入域名访问你要访问的地址了。
<img src ="http://www.blogjava.net/WshmAndLily/aggbug/143452.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/WshmAndLily/" target="_blank">semovy</a> 2007-09-07 16:06 <a href="http://www.blogjava.net/WshmAndLily/articles/143452.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于Tomcat虚拟主机域名的设置</title><link>http://www.blogjava.net/WshmAndLily/articles/143450.html</link><dc:creator>semovy</dc:creator><author>semovy</author><pubDate>Fri, 07 Sep 2007 08:05:00 GMT</pubDate><guid>http://www.blogjava.net/WshmAndLily/articles/143450.html</guid><wfw:comment>http://www.blogjava.net/WshmAndLily/comments/143450.html</wfw:comment><comments>http://www.blogjava.net/WshmAndLily/articles/143450.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/WshmAndLily/comments/commentRss/143450.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/WshmAndLily/services/trackbacks/143450.html</trackback:ping><description><![CDATA[<p><font size="2"><strong>1.设置本地主机域名</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp; Hosts是一个没有扩展名的系统文件，可以用记事本等工具打开，其作用就是将一些常用的网址域名与其对应的IP地址建立一个关联&#8220;数据库&#8221;，当用户在浏览器中输入一个需要登录的网址时，系统会首先自动从Hosts文件中寻找对应的IP地址，一旦找到，系统会立即打开对应网页，如果没有找到，则系统再会将网址提交DNS域名解析服务器进行IP地址的解析。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 通过修改本地主机上的一个hosts文件，可以进行对ip地址与本地域名的映射，从而解决在本地调试JSP项目的时候，通过本地域名进行访问。<br />
&nbsp;&nbsp;&nbsp;&nbsp; hosts文件在系统目录C:\WINDOWS\system32\drivers\etc\下，这个目录不容易记忆，如果要经常修改这个文件的话不是很方便找，可以 建立一个批处理hosts.bat文件，用文本编辑器打开，写入内容explorer "C:\WINDOWS\system32\drivers\etc"，保存退出，可以把这个hosts.bat文件放在桌面，每次双击它就能打开hosts文件所在的目录。也可以将hosts.bat文件放到C:\WINDOWS下，这样，每次只要从点&#8220;开始&#8221;-&gt;&#8220;运行&#8221;，输入hosts，点回车就可以打开hosts文件所在的目录了，另外在命令行也可以输入hosts打开hosts文件所在的目录。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 找到hosts文件后，用文本编辑器打开，默认状态下，hosts文件里只有一个映射关系：<br />
</font><font color="#c01d3e" size="2">&nbsp;&nbsp;&nbsp;&nbsp; 127.0.0.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; localhost<br />
&nbsp;&nbsp;&nbsp;&nbsp; 按照这个格式再添加一个映射：<br />
&nbsp;&nbsp;&nbsp;&nbsp; 202.112.113.171&nbsp;&nbsp;&nbsp;</font><a href="http://www.yujiaxin.com/"><font color="#c01d3e" size="2">www.yujiaxin.com</font></a><br />
<font size="2">&nbsp;&nbsp;&nbsp;&nbsp; 保存，退出。这时候本地IP地址202.112.113.171已经和</font><a href="http://www.yujiaxin.com/"><font size="2">www.yujiaxin.com</font></a><font size="2">这个本地域名做了对应的映射关系。<br />
<br />
<strong>2.server.xml配置简介</strong> <br />
server.xml的基本配置信息，更具体的配置信息见tomcat的文档 <br />
server: <br />
port 指定一个端口，这个端口负责监听关闭tomcat的请求 <br />
shutdown 指定向端口发送的命令字符串 <br />
service: <br />
name 指定service的名字 <br />
Connector (表示客户端和service之间的连接): <br />
port 指定服务器端要创建的端口号，并在这个断口监听来自客户端的请求 <br />
minProcessors 服务器启动时创建的处理请求的线程数 <br />
maxProcessors 最大可以创建的处理请求的线程数 <br />
enableLookups 如果为true，则可以通过调用request.getRemoteHost()进行DNS查询来得到远程客户端的实际主机名，若为false则不进行DNS查询，而是返回其ip地址 <br />
redirectPort 指定服务器正在处理http请求时收到了一个SSL传输请求后重定向的端口号 <br />
acceptCount 指定当所有可以使用的处理请求的线程数都被使用时，可以放到处理队列中的请求数，超过这个数的请求将不予处理 <br />
connectionTimeout 指定超时的时间数(以毫秒为单位) <br />
Engine (表示指定service中的请求处理机，接收和处理来自Connector的请求): <br />
defaultHost 指定缺省的处理请求的主机名，它至少与其中的一个host元素的<br />
name属性值是一样的 <br />
Context (表示一个web应用程序，通常为WAR文件，关于WAR的具体信息见servlet规范): <br />
docBase 应用程序的路径或者是WAR文件存放的路径 <br />
path 表示此web应用程序的url的前缀，这样请求的url为</font><a href="http://localhost:8080/path/"><font size="2">http://localhost:8080/path/</font></a><font size="2">**** <br />
reloadable 这个属性非常重要，如果为true，则tomcat会自动检测应用程序的/WEB-INF/lib 和/WEB-INF/classes目录的变化，自动装载新的应用程序，可以在不重起tomcat的情况下改变应用程序 <br />
host (表示一个虚拟主机): <br />
name 指定主机名 <br />
appBase 应用程序基本目录，即存放应用程序的目录 <br />
unpackWARs 如果为true，则tomcat会自动将WAR文件解压，否则不解压，直接从WAR文件中运行应用程序 <br />
Logger (表示日志，调试和错误信息): <br />
className 指定logger使用的类名，此类必须实现<br />
org.apache.catalina.Logger 接口 <br />
prefix 指定log文件的前缀 <br />
suffix 指定log文件的后缀 <br />
timestamp 如果为true，则log文件名中要加入时间，如下例:localhost_log.2001-10-04.txt <br />
Realm (表示存放用户名，密码及role的数据库): <br />
className 指定Realm使用的类名，此类必须实现org.apache.catalina.Realm接口 <br />
Valve (功能与Logger差不多，其prefix和suffix属性解释和Logger 中的一样): <br />
className 指定Valve使用的类名，如用org.apache.catalina.valves.AccessLogValve类可以记录应用程序的访问信息directory 指定log文件存放的位置 <br />
pattern 有两个值，common方式记录远程主机名或ip地址，用户名，日期，第一行请求的字符串，HTTP响应代码，发送的字节数。combined方式比common方式记录的值更多<br />
<br />
<strong>3.配置虚拟主机（Virtual Hosts）</strong> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 关于server.xml中&#8220;Host&#8221;这个元素，只有在你设置虚拟主机的才需要修改。虚拟主机是一种在一个web服务器上服务多个域名的机制，对每个域名而言，都好象独享了整个主机。实际上，大多数的小型商务网站都是采用虚拟主机实现的，这主要是因为虚拟主机能直接连接到Internet并提供相应的带宽，以保障合理的访问响应速度，另外虚拟主机还能提供一个稳定的固定IP。 <br />
　　基于名字的虚拟主机可以被建立在任何web服务器上，建立的方法就是通过在域名服务器（DNS）上建立IP地址的别名，并且告诉web服务器把去往不同域名的请求分发到相应的网页目录。在Tomcat中使用虚拟主机，需要设置DNS或主机数据。在server.xml中设置内容，如下： </font></p>
<p><font color="#3f60e2" size="2">&lt;Server port="8005" shutdown="SHUTDOWN" debug="0"&gt; <br />
&lt;Service name="Tomcat-Standalone"&gt; <br />
&lt;Connector className="org.apache.coyote.tomcat4.CoyoteConnector" port="80" minProcessors="5" maxProcessors="75" enableLookups="true" redirectPort="8443"/&gt; <br />
&lt;Connector className="org.apache.coyote.tomcat4.CoyoteConnector" port="8443" minProcessors="5" maxProcessors="75" acceptCount="10" debug="0" scheme="https" secure="true"/&gt; <br />
&lt;Factory className="org.apache.coyote.tomcat4.CoyoteServerSocketFactory" clientAuth="false" protocol="TLS" /&gt; <br />
&lt;/Connector&gt; <br />
&lt;Engine name="Standalone" defaultHost="localhost" debug="0"&gt; <br />
&lt;!-- This Host is the default Host --&gt; <br />
&lt;Host name="localhost" debug="0" appBase="webapps" unpackWARs="true" autoDeploy="true"&gt; <br />
&lt;Context path="" docBase="ROOT" debug="0"/&gt; <br />
&lt;Context path="/orders" docBase="/orders" debug="0" reloadable="true" crossContext="true"&gt; <br />
&lt;/Context&gt; <br />
&lt;/Host&gt; </font></p>
<p><font color="#c01d3e" size="2">&lt;!-- This Host is the first "Virtual Host": </font><a href="http://www.yujiaxin.com/"><font color="#c01d3e" size="2">http://www.yujiaxin.com</font></a><font color="#c01d3e" size="2"> --&gt; <br />
&lt;Host name="</font><a href="http://www.yujiaxin.com/"><font color="#c01d3e" size="2">www.yujiaxin.com</font></a><font color="#3f60e2"><font size="2"><font color="#c01d3e">" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false"&gt;<br />
&lt;Context docBase="jspwebsite" path="" reloadable="true" /&gt;<br />
&lt;/Host&gt;</font> </font></font></p>
<p><font size="2"><font color="#3f60e2">&lt;/Engine&gt; <br />
&lt;/Service&gt; <br />
&lt;/Server&gt;</font>&nbsp;&nbsp;</font></p>
<p><font size="2">　　Tomcat的server.xml文件，在初始状态下，只包括一个虚拟主机，但是它容易被扩充到支持多个虚拟主机。增加虚拟主机只要增加完整Host标签即可。每一个Host元素必须包括一个或多个context元素，所包含的context元素中必须有一个是默认的context，这个默认的context的显示路径应该为空（例如，path=""）。</font></p>
<img src ="http://www.blogjava.net/WshmAndLily/aggbug/143450.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/WshmAndLily/" target="_blank">semovy</a> 2007-09-07 16:05 <a href="http://www.blogjava.net/WshmAndLily/articles/143450.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>J2EE的13种核心技术</title><link>http://www.blogjava.net/WshmAndLily/articles/143449.html</link><dc:creator>semovy</dc:creator><author>semovy</author><pubDate>Fri, 07 Sep 2007 08:03:00 GMT</pubDate><guid>http://www.blogjava.net/WshmAndLily/articles/143449.html</guid><wfw:comment>http://www.blogjava.net/WshmAndLily/comments/143449.html</wfw:comment><comments>http://www.blogjava.net/WshmAndLily/articles/143449.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/WshmAndLily/comments/commentRss/143449.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/WshmAndLily/services/trackbacks/143449.html</trackback:ping><description><![CDATA[<p>Java最初是在浏览器和客户端机器中粉墨登场的。当时，很多人质疑它是否适合做服务器端的开发。现在，随着对Java2平台企业版（J2EE）第三方支持的增多，Java被广泛接纳为开发企业级服务器端解决方案的首选平台之一。<br />
<br />
J2EE平台由一整套服务（Services）、应用程序接口（APIs）和协议构成，它对开发基于Web的多层应用提供了功能支持。<br />
<br />
在本文中我将解释支撑J2EE的13种核心技术：JDBC, JNDI, EJBs, RMI, JSP, Java servlets, XML, JMS, Java IDL, JTS, JTA, JavaMail 和 JAF，同时还将描述在何时、何处需要使用这些技术。当然，我还要介绍这些不同的技术之间是如何交互的。<br />
<br />
此外，为了让您更好地感受J2EE的真实应用，我将在WebLogic应用服务?来自BEA Systems公司的一种广为应用的产品环境下来介绍这些技术。不论对于WebLogic应用服务器和J2EE的新手，还是那些想了解J2EE能带来什么好处的项目管理者和系统分析员，相信本文一定很有参考价值。<br />
<br />
宏观印象: 分布式结构和J2EE<br />
<br />
过去，二层化应用 -- 通常被称为client/server应用 -- 是大家谈论的最多的。在很多情况下，服务器提供的惟一服务就是数据库服务。在这种解决方案中，客户端程序负责数据访问、实现业务逻辑、用合适的样式显示结果、弹出预设的用户界面、接受用户输入等。client/server结构通常在第一次部署的时候比较容易，但难于升级或改进，而且经常基于某种专有的协议，通常是某种数据库协议。它使得重用业务逻辑和界面逻辑非常困难。更重要的是，在Web时代，二层化应用通常不能体现出很好的伸缩性，因而很难适应Internet的要求。<br />
<br />
Sun设计J2EE的部分起因就是想解决二层化结构的缺陷。于是，J2EE定义了一套标准来简化N层企业级应用的开发。它定义了一套标准化的组件，并为这些组件提供了完整的服务。J2EE还自动为应用程序处理了很多实现细节，如安全、多线程等。<br />
<br />
用J2EE开发N层应用包括将二层化结构中的不同层面切分成许多层。一个N层化应用A能够为以下的每种服务提供一个分开的层：<br />
<br />
显示：在一个典型的Web应用中，客户端机器上运行的浏览器负责实现用户界面。<br />
<br />
动态生成显示: 尽管浏览器可以完成某些动态内容显示，但为了兼容不同的浏览器，这些动态生成工作应该放在Web服务器端进行，使用JSP、Servlets，或者XML（可扩展标记语言）和（可扩展样式表语言）。<br />
<br />
业务逻辑：业务逻辑适合用Session EJBs（后面将介绍）来实现。<br />
<br />
数据访问：数据访问适合用Entity EJBs（后面将介绍）和JDBC来实现。<br />
<br />
后台系统集成: 同后台系统的集成可能需要用到许多不同的技术，至于何种最佳需要根据后台系统的特征而定。<br />
<br />
您可能开始诧异：为什么有这么多的层？事实上，多层方式可以使企业级应用具有很强的伸缩性，它允许每层专注于特定的角色。例如，让Web服务器负责提供页面，应用服务器处理应用逻辑，而数据库服务器提供数据库服务。<br />
<br />
由于J2EE建立在Java2平台标准版（J2SE）的基础上，所以具备了J2SE的所有优点和功能。包括&#8220;编写一次，到处可用&#8221;的可移植性、通过JDBC访问数据库、同原有企业资源进行交互的CORBA技术，以及一个经过验证的安全模型。在这些基础上，J2EE又增加了对EJB（企业级Java组件）、Java servlets、Java服务器页面（JSPs）和XML技术的支持。<br />
<br />
分布式结构与WebLogic应用服务器<br />
<br />
J2EE提供了一个框架--一套标准API--用于开发分布式结构的应用，这个框架的实际实现留给了第三方厂商。部分厂商只是专注于整个J2EE架构中的的特定组件，例如Apache的Tomcat提供了对JSP和servlets的支持，BEA系统公司则通过其WebLogic应用服务器产品为整个J2EE规范提供了一个较为完整的实现。<br />
<br />
WebLogic服务器已使建立和部署伸缩性较好的分布式应用的过程大为简化。WebLogic和J2EE代你处理了大量常规的编程任务，包括提供事务服务、安全领域、可靠的消息、名字和目录服务、数据库访问和连接池、线程池、负载平衡和容错处理等。<br />
<br />
通过以一种标准、易用的方式提供这些公共服务，象WebLogic服务器这样的产品造就了具有更好伸缩性和可维护性的应用系统，使其为大量的用户提供了增长的可用性。<br />
<br />
J2EE技术<br />
<br />
在接下来的部分里，我们将描述构成J2EE的各种技术，并且了解WebLogic服务器是如何在一个分布式应用中对它们进行支持的。最常用的J2EE技术应该是JDBC、JNDI、EJB、JSP和servlets，对这些我们将作更仔细的考察。<br />
<br />
Java Database Connectivity (JDBC)<br />
<br />
JDBC API以一种统一的方式来对各种各样的数据库进行存取。和ODBC一样，JDBC为开发人员隐藏了不同数据库的不同特性。另外，由于JDBC建立在Java的基础上,因此还提供了数据库存取的平台独立性。<br />
<br />
JDBC定义了4种不同的驱动程序，现分述如下：<br />
<br />
类型 1: JDBC-ODBC Bridge<br />
<br />
在JDBC出现的初期，JDBC-ODBC桥显然是非常有实用意义的，通过JDBC-ODBC桥，开发人员可以使用JDBC来存取ODBC数据源。不足的是，他需要在客户端安装ODBC驱动程序，换句话说，必须安装Microsoft Windows的某个版本。使用这一类型你需要牺牲JDBC的平台独立性。另外，ODBC驱动程序还需要具有客户端的控制权限。<br />
<br />
类型 2: JDBC-native driver bridge<br />
<br />
JDBC本地驱动程序桥提供了一种JDBC接口，它建立在本地数据库驱动程序的顶层，而不需要使用ODBC。 JDBC驱动程序将对数据库的API从标准的JDBC调用转换为本地调用。使用此类型需要牺牲JDBC的平台独立性，还要求在客户端安装一些本地代码。<br />
<br />
类型 3: JDBC-network bridge<br />
<br />
JDBC网络桥驱动程序不再需要客户端数据库驱动程序。它使用网络上的中间服务器来存取数据库。这种应用使得以下技术的实现有了可能，这些技术包括负载均衡、连接缓冲池和数据缓存等。由于第3种类型往往只需要相对更少的下载时间，具有平台独立性，而且不需要在客户端安装并取得控制权，所以很适合于Internet上的应用。<br />
<br />
类型 4: Pure Java driver<br />
<br />
第4种类型通过使用一个纯Java数据库驱动程序来执行数据库的直接访问。此类型实际上在客户端实现了2层结构。要在N-层结构中应用，一个更好的做法是编写一个EJB，让它包含存取代码并提供一个对客户端具有数据库独立性的服务。<br />
<br />
WebLogic服务器为一些通常的数据库提供了JDBC驱动程序，包括Oracle, Sybase, Microsoft SQL Server以及Informix。它也带有一种JDBC驱动程序用于Cloudscape，这是一种纯Java的DBMS，WebLogic服务器中带有该数据库的评估版本。<br />
<br />
以下让我们看一个实例。<br />
<br />
JDBC实例<br />
<br />
在这个例子中我们假定你已经在Cloudscape中建立了一个PhoneBook数据库，并且包含一个表，名为 CONTACT_TABLE ，它带有2个字段：NAME 和 PHONE。 开始的时候先装载Cloudscape JDBC driver，并请求 driver manager得到一个对PhoneBook Cloudscape数据库的连接。通过这一连接，我们可以构造一个 Statement 对象并用它来执行一个简单的SQL查询。最后，用循环来遍历结果集的所有数据，并用标准输出将NAME和PHONE字段的内容进行输出。<br />
<br />
<br />
<br />
<br />
import java.sql.*;<br />
public class JDBCExample<br />
{<br />
public static void main( String args[] )<br />
{<br />
try<br />
{<br />
Class.forName("COM.cloudscape.core.JDBCDriver");<br />
Connection conn = DriverManager.getConnection("jdbc:cloudscape:PhoneBook");<br />
Statement stmt = conn.createStatement();<br />
String sql = "SELECT name, phone FROM CONTACT_TABLE ORDER BY name";<br />
ResultSet resultSet = stmt.executeQuery( sql );<br />
String name;<br />
String phone;<br />
while ( resultSet.next() )<br />
{<br />
name = resultSet.getString(1).trim();<br />
phone = resultSet.getString(2).trim();<br />
System.out.println( name + ", " + phone );<br />
}<br />
}<br />
catch ( Exception e )<br />
{<br />
// Handle exception here<br />
e.printStackTrace();<br />
}<br />
}<br />
}<br />
<br />
<br />
<br />
<br />
OK。接着我们来看一看JDBC是如何在企业应用中的进行使用。<br />
<br />
JDBC在企业级应用中的应用<br />
<br />
以上实例其实是很基本的，可能有些微不足道。它假定了一个2层结构。在一个多层的企业级应用中，更大的可能是在客户端和一个EJB进行通信，该EJB将建立数据库连接。为了实现和改进可伸缩性和系统性能， WebLogic服务器提供了对连接缓冲池connection pool的支持。<br />
<br />
Connection pool减少了建立和释放数据库连接的消耗。在系统启动以后即可建立这样的缓冲池，此后如故再有对数据库的请求，WebLogic服务器可以很简单地从缓冲池中取出数据。数据缓冲池可以在WebLogic服务器的 weblogic.properties 文件中进行定义。(可参考 weblogic.properties 文件中的例子，WebLogic服务器的文档中还有更详细的参考信息)<br />
<br />
在企业级应用的另一个常见的数据库特性是事务处理。事务是一组申明statement，它们必须做为同一个statement来处理以保证数据完整性。缺省情况下JDBC使用 auto-commit 事务模式。这可以通过使用Connection类的 setAutoCommit() 方法来实现。<br />
<br />
现在我们已经对JDBC有了一些认识，下面该转向JNDI了。</p>
<p>Java Naming and Directory Interface (JNDI)<br />
<br />
JNDI API被用于执行名字和目录服务。它提供了一致的模型来存取和操作企业级的资源如DNS和LDAP，本地文件系统，后者在应用服务器中的对象。<br />
<br />
在JNDI中，在目录结构中的每一个结点称为context。每一个JNDI名字都是相对于context的。这里没有绝对名字的概念存在。对一个应用来说，它可以通过使用 InitialContext 类来得到其第一个context:<br />
<br />
<br />
<br />
<br />
Context ctx = new InitialContext();<br />
<br />
<br />
<br />
<br />
应用可以通过这个初始化的context经有这个目录树来定位它所需要的资源或对象。例如，假设你在Weblogic服务器中展开了一个EJB并将home接口绑定到名字 myApp.myEJB ，那么该EJB的某个客户在取得一个初始化context以后，可以通过以下语句定位home接口：<br />
<br />
<br />
MyEJBHome home = ctx.lookup( "myApp.myEJB" );<br />
<br />
<br />
<br />
<br />
在这个例子中，一旦你有了对被请求对象的参考，EJB的home接口就可以在它上面调用方法。我们将在下面的"Enterprise Java Beans"章节中做更多的介绍。<br />
<br />
以上关于JNDI的讨论只是冰山之一角而已。如果要更进一步地在context中查找对象，JNDI也提供了一些方法来进行以下操作：　<br />
<br />
将一个对象插入或绑定到context。这在你展开一个EJB的时候是很有效的。<br />
<br />
从context中移去对象。<br />
<br />
列出context中的所有对象。<br />
<br />
创建或删除子一级的context。<br />
<br />
接下来，我们要开始关注EJB了。<br />
<br />
Enterprise Java Beans (EJB)<br />
<br />
J2EE技术之所以赢得某体广泛重视的原因之一就是EJB。它们提供了一个框架来开发和实施分布式商务逻辑，由此很显著地简化了具有可伸缩性和高度复杂的企业级应用的开发。EJB规范定义了EJB组件在何时如何与它们的容器进行交互作用。容器负责提供公用的服务，例如目录服务、事务管理、安全性、资源缓冲池以及容错性。<br />
<br />
EJB规范定义了3中基本的bean类型:<br />
<br />
Stateless session beans: 提供某种单一的服务，不维持任何状态，在服务器故障发生时无法继续存在，生命期相对较短。例如，一个stateless session bean可能被用于执行温度转换计算。<br />
<br />
Stateful session bean: T提供了与客户端的会话交互，可以存储状态从而代表一个客户。典型例子是购物车。Stateful session bean在服务器故障时无法继续生存，生命气相对较短。每一个实例只用于一个单个的线程。<br />
<br />
Entity beans: 提供了一致性数据的表示-- 通常存放在数据库中 -- 在服务器故障发生后能继续存在。多用户情况下可以使用EJB来表示相同的数据。entity EJB的一个典型例子是客户的帐号信息。<br />
<br />
尽管有以上的区别，所有的EJB还是有许多的共同之处。它们都处理home interface。它定义了一个客户端是如何创建与消亡EJB的。可以在bean中对定义了客户端方法的远程接口进行调用；bean类则执行了主要的商务逻辑。<br />
<br />
描述EJB的开发已经超出了本文的范围。但是，如果一个EJB已经被开发了或者从第三方进行了购买，它就必须在应用服务器中进行发布。WebLogic Server 5.1带有一个EJB Deployer Tool来协助处理EJB的发布。当你使用EJB Deployer Tool的时候，你要定义客户端所用的JNDI名字来定位EJB。Deployer Tool将生成wrapper类来处理和容器的通信以及在一个jar文件中把被请求的Java类绑定在一起。<br />
<br />
一旦EJB被发布，客户端就可以使用它的JNDI名字来定位EJB。首先，它必须得到一个到home接口的reference。然后，客户端可以使用该接口，调用一个 create() 方法来得到服务器上运行的某个bean实例的句柄；最后，客户端可以使用该句柄在bean中调用方法。<br />
<br />
了解 EJB后，让我们再来看JSP。<br />
<br />
JavaServer Pages (JSPs)<br />
<br />
我们中间可能已经有许多人已经熟悉Microsoft的Active Server Pages (ASP)技术了。JSP和ASP相对应的，但更具有平台对立性。他们被设计用以帮助Web内容开发人员创建动态网页，并且只需要相对较少的代码。 即使Web设计师不懂得如何编程也可以使用JSP，因为JSP应用是很方便的。 JSP页面由HTML代码和嵌入其中的Java代码所组成。服务器在页面被客户端所请求以后对这些Java代码进行处理，然后将生成的HTML页面返回给客户端的浏览器。<br />
<br />
下面我们来看一个JSP的简单实例。它只显示了服务器的当前日期和时间。虽然，对语法的具体解释已经超出了本文的范围，但我们还是可以很直观地看到，Java代码被放在符号的中间，而Java的表达式则放在符号之间。<br />
<br />
Date JSP sample<br />
<br />
The current date is .<br />
<br />
您可能有时候听说过JHTML。这是JSP以前的一种较老的标准。WebLogic服务器既可支持JSP，又可支持JHTML。请注意，在缺省状况下，JSP在WebLogic服务器中并没有处于有效状态。要使之有效，你可以编辑weblogic.properties文件。如果Web服务器还没有处于有效状态，则要先使之有效。Servlet的情况和JSP是一样的。<br />
<br />
下面是: Java servlets<br />
<br />
Java servlets<br />
<br />
servlet提供的功能大多与JSP类似，不过实现的方式不同。JSP通常是大多数HTML代码中嵌入少量的Java代码，而servlets全部由Java写成并且生成HTML。<br />
<br />
servlet是一种小型的Java程序，它扩展了Web服务器的功能。作为一种服务器端的应用，当被请求时开始执行，这和CGI Perl脚本很相似。Servlets和CGI脚本的一个很大的区别是：每一个CGI在开始的时候都要求开始一个新的进程 -- 而servlets是在servlet引擎中以分离的线程来运行的。因此servlets在可伸缩性上提供了很好的改进。<br />
<br />
在开发servlets的时候，您常常需要扩展javax.servlet.http.HttpServlet 类，并且override一些它的方法，其中包括：<br />
<br />
service(): 作为dispatcher来实现命令-定义方法<br />
<br />
doGet(): 处理客户端的HTTP GET请求。<br />
<br />
doPost(): 进行HTTP POST操作<br />
<br />
其它的方法还包括处理不同类型的HTTP请求 -- 可以参考HttpServlet API文档。<br />
<br />
以上描述的是标准J2EE Servlet API的各种方法。WebLogic服务器提供了一个该API完整的实现途径。一旦你开发了一个servlet，你就可以在weblogic.properties 中加以注册并由此可以在WebLogic服务器中对它进行配置。<br />
<br />
通过Java servlets,我们已经到达了J2EE主要技术的末尾了。但J2EE所提供的并不止于这些。下面的段落中我们将简要地看一下现存的一些技术，包括RMI, Java IDL和CORBA, JTA, 以及XML，等等。<br />
<br />
Remote Method Invocation (RMI)<br />
<br />
正如其名字所表示的那样，RMI协议是在远程对象上调用一些方法。它使用了连续序列方式在客户端和服务器端传递数据。RMI是一种被EJB使用的更下层的协议。<br />
<br />
Java IDL/CORBA<br />
<br />
在Java IDL的支持下，开发人员可以将Java和CORBA集成在一起。 他们可以创建Java对象并使之可在CORBA ORB中展开, 或者他们还可以创建Java类并作为和其它ORB一起展开的CORBA对象的客户。后一种方法提供了另外一种途径，通过它Java可以被用于将你的新的应用和legacy系统相集成。<br />
<br />
Java Transaction Architecture (JTA)/Java Transaction Service (JTS)<br />
<br />
JTA定义了一种标准的API，应用系统由此可以存取各种事务监控。<br />
<br />
JTS是CORBA OTS事务监控的基本的实现。JTS规定了事务管理器的实现方式。该事务管理器是在高层支持Java Transaction API (JTA)规范，并且在较底层实现OMG OTS specification的Java映像。JTS事务管理器为应用服务器、资源管理器、独立的应用以及通信资源管理器提供了事务服务。<br />
<br />
JavaMail and JavaBeans Activation Framework<br />
<br />
JavaMail是用于存取邮件服务器的API，它提供了一套邮件服务器的抽象类。不仅支持SMTP服务器，也支持IMAP服务器。<br />
<br />
JavaMail利用JavaBeans Activation Framework (JAF)来处理MIME-编码的邮件附件。MIME的字节流可以被转换成Java对象，或者转换自Java对象。由此大多数应用都可以不需要直接使用JAF。<br />
<br />
Java Messaging Service (JMS)<br />
<br />
JMS是用于和面向消息的中间件相互通信的应用程序接口(API)。它既支持点对点的域，有支持发布/订阅(publish/subscribe)类型的域，并且提供对下列类型的支持：经认可的消息传递,事务型消息的传递，一致性消息和具有持久性的订阅者支持。JMS还提供了另一种方式来对您的应用与legacy backend系统相集成。<br />
<br />
Extensible Markup Language (XML)<br />
<br />
XML是一种可以用来定义其它标记语言的语言。它被用来在不同的商务过程中共享数据。XML的发展和Java是相互独立的，但是，它和Java具有的相同目标正是平台独立性。通过将Java和XML的组合，您可以得到一个完美的具有平台独立性的解决方案。目前正有许多不同的公司在为Java和XML的组合而努力。如果要了解更多的这方面的信息，可以访问Sun的Java-XML页面，或者IBM developerWorks的XML Zone。</p>
<img src ="http://www.blogjava.net/WshmAndLily/aggbug/143449.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/WshmAndLily/" target="_blank">semovy</a> 2007-09-07 16:03 <a href="http://www.blogjava.net/WshmAndLily/articles/143449.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>J2EE面试题集锦(附答案)</title><link>http://www.blogjava.net/WshmAndLily/articles/143445.html</link><dc:creator>semovy</dc:creator><author>semovy</author><pubDate>Fri, 07 Sep 2007 07:57:00 GMT</pubDate><guid>http://www.blogjava.net/WshmAndLily/articles/143445.html</guid><wfw:comment>http://www.blogjava.net/WshmAndLily/comments/143445.html</wfw:comment><comments>http://www.blogjava.net/WshmAndLily/articles/143445.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/WshmAndLily/comments/commentRss/143445.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/WshmAndLily/services/trackbacks/143445.html</trackback:ping><description><![CDATA[<div class="cnt">
<div style="font-size: 10.5pt">
<p><font face="Arial">一、基础问答</font></p>
<p><font face="Arial">　　1.下面哪些类可以被继承?</font></p>
<p><font face="Arial">　　　java.lang.Thread&nbsp;&nbsp; (T)<br />
　　　java.lang.Number&nbsp;&nbsp; (T)<br />
　　　java.lang.Double&nbsp;&nbsp; (F)<br />
　　　java.lang.Math&nbsp;&nbsp;&nbsp;&nbsp; (F)<br />
　　　java.lang.Void&nbsp;&nbsp;&nbsp;&nbsp; (F)<br />
　　　java.lang.Class&nbsp;&nbsp;&nbsp;&nbsp; (F)<br />
　　　java.lang.ClassLoader&nbsp;&nbsp; (T)</font></p>
<p><font face="Arial">　　2.抽象类和接口的区别</font></p>
<p><font face="Arial">　　(1)接口可以被多重implements,抽象类只能被单一extends<br />
　　(2)接口只有定义,抽象类可以有定义和实现<br />
　　(3)接口的字段定义默认为:public&nbsp;&nbsp; static&nbsp;&nbsp; final,&nbsp;&nbsp; 抽象类字段默认是"friendly"(本包可见)</font></p>
<p><font face="Arial">　　3.Hashtable的原理,并说出HashMap与Hashtable的区别</font></p>
<p><font face="Arial">　　HashTable的原理:通过节点的关键码确定节点的存储位置,即给定节点的关键码k,通过一定的函数关系H(散列函数),得到函数值H(k),将此值解释为该节点的存储地址.<br />
HashMap&nbsp;&nbsp; 与Hashtable很相似,但HashMap&nbsp;&nbsp; 是非同步(unsynchronizded)和可以以null为关键码的.</font></p>
<p><font face="Arial">　　4.forward和redirect的区别</font></p>
<p><font face="Arial">　　forward:&nbsp;&nbsp; an&nbsp;&nbsp; internal&nbsp;&nbsp; transfer&nbsp;&nbsp; in&nbsp;&nbsp; servlet<br />
　　redirect:&nbsp;&nbsp; 重定向,有2次request,第2次request将丢失第一次的attributs/parameters等</font></p>
<p><font face="Arial">　　5.什么是Web容器?</font></p>
<p><font face="Arial">　　实现J2EE规范中web协议的应用.该协议定义了web程序的运行时环境,包括:并发性,安全性,生命周期管理等等.</font></p>
<p><font face="Arial">　　6.解释下面关于J2EE的名词</font></p>
<p><font face="Arial">　　(1)JNDI:Java&nbsp;&nbsp; Naming&nbsp;&nbsp; &amp;&nbsp;&nbsp; Directory&nbsp;&nbsp; Interface,JAVA命名目录服务.主要提供的功能是：提供一个目录系统，让其它各地的应用程序在其上面留下自己的索引，从而满足快速查找和定位分布式应用程序的功能.<br />
　　(2)JMS：Java&nbsp;&nbsp; Message&nbsp;&nbsp; Service,JAVA消息服务.主要实现各个应用程序之间的通讯.包括点对点和广播.<br />
　　(3)JTA：Java&nbsp;&nbsp; Transaction&nbsp;&nbsp; API,JAVA事务服务.提供各种分布式事务服务.应用程序只需调用其提供的接口即可.<br />
　　(4)JAF:&nbsp;&nbsp; Java&nbsp;&nbsp; Action&nbsp;&nbsp; FrameWork,JAVA安全认证框架.提供一些安全控制方面的框架.让开发者通过各种部署和自定义实现自己的个性安全控制策略.<br />
　　(5)RMI:Remote&nbsp;&nbsp; Method&nbsp;&nbsp; Interface,远程方法调用</font></p>
<p><font face="Arial">　　7.EJB是基于哪些技术实现的？并说&nbsp;&nbsp; 出SessionBean和EntityBean的区别，StatefulBean和StatelessBean的区别.</font></p>
<p><font face="Arial">　　EJB包括Session&nbsp;&nbsp; Bean、Entity&nbsp;&nbsp; Bean、Message&nbsp;&nbsp; Driven&nbsp;&nbsp; Bean，基于JNDI、RMI、JAT等技术实现.</font></p>
<p><font face="Arial">　　SessionBean在J2EE应用程序中被用来完成一些服务器端的业务操作，例如访问数据库、调用其他EJB组件.EntityBean被用来代表应用系统中用到的数据.对于客户机，SessionBean是一种非持久性对象，它实现某些在服务器上运行的业务逻辑;EntityBean是一种持久性对象，它代表一个存储在持久性存储器中的实体的对象视图，或是一个由现有企业应用程序实现的实体.</font></p>
<p><font face="Arial">　　Session&nbsp;&nbsp; Bean&nbsp;&nbsp; 还可以再细分为&nbsp;&nbsp; Stateful&nbsp;&nbsp; Session&nbsp;&nbsp; Bean&nbsp;&nbsp; 与&nbsp;&nbsp; Stateless&nbsp;&nbsp; Session&nbsp;&nbsp; Bean&nbsp;&nbsp; .这两种的&nbsp;&nbsp; Session&nbsp;&nbsp; Bean都可以将系统逻辑放在&nbsp;&nbsp; method之中执行，不同的是&nbsp;&nbsp; Stateful&nbsp;&nbsp; Session&nbsp;&nbsp; Bean&nbsp;&nbsp; 可以记录呼叫者的状态，因此通常来说，一个使用者会有一个相对应的&nbsp;&nbsp; Stateful&nbsp;&nbsp; Session&nbsp;&nbsp; Bean&nbsp;&nbsp; 的实体.Stateless&nbsp;&nbsp; Session&nbsp;&nbsp; Bean&nbsp;&nbsp; 虽然也是逻辑组件，但是他却不负责记录使用者状态，也就是说当使用者呼叫&nbsp;&nbsp; Stateless&nbsp;&nbsp; Session&nbsp;&nbsp; Bean&nbsp;&nbsp; 的时候，EJB&nbsp;&nbsp; Container&nbsp;&nbsp; 并不会找寻特定的&nbsp;&nbsp; Stateless&nbsp;&nbsp; Session&nbsp;&nbsp; Bean&nbsp;&nbsp; 的实体来执行这个&nbsp;&nbsp; method.换言之，很可能数个使用者在执行某个&nbsp;&nbsp; Stateless&nbsp;&nbsp; Session&nbsp;&nbsp; Bean&nbsp;&nbsp; 的&nbsp;&nbsp; methods&nbsp;&nbsp; 时，会是同一个&nbsp;&nbsp; Bean&nbsp;&nbsp; 的&nbsp;&nbsp; Instance&nbsp;&nbsp; 在执行.从内存方面来看，&nbsp;&nbsp; Stateful&nbsp;&nbsp; Session&nbsp;&nbsp; Bean&nbsp;&nbsp; 与&nbsp;&nbsp; Stateless&nbsp;&nbsp; Session&nbsp;&nbsp; Bean&nbsp;&nbsp; 比较，&nbsp;&nbsp; Stateful&nbsp;&nbsp; Session&nbsp;&nbsp; Bean&nbsp;&nbsp; 会消耗&nbsp;&nbsp; J2EE&nbsp;&nbsp; Server&nbsp;&nbsp; 较多的内存，然而&nbsp;&nbsp; Stateful&nbsp;&nbsp; Session&nbsp;&nbsp; Bean&nbsp;&nbsp; 的优势却在于他可以维持使用者的状态.</font></p>
<p><font face="Arial">　　8.XML的解析方法</font></p>
<p><font face="Arial">　　Sax,DOM,JDOM</font></p>
<p><font face="Arial">　　9.什么是Web&nbsp;&nbsp; Service?</font></p>
<p><font face="Arial">　　Web&nbsp;&nbsp; Service就是为了使原来各孤立的站点之间的信息能够相互通信、共享而提出的一种接口。<br />
Web&nbsp;&nbsp; Service所使用的是Internet上统一、开放的标准，如HTTP、XML、SOAP（简单对象访问协议）、WSDL等，所以Web&nbsp;&nbsp; Service可以在任何支持这些标准的环境（Windows,Linux）中使用。</font></p>
<p><font face="Arial">　　注：SOAP协议（Simple&nbsp;&nbsp; Object&nbsp;&nbsp; Access&nbsp;&nbsp; Protocal,简单对象访问协议）,它是一个用于分散和分布式环境下网络信息交换的基于XML的通讯协议。在此协议下，软件组件或应用程序能够通过标准的HTTP协议进行通讯。它的设计目标就是简单性和扩展性，这有助于大量异构程序和平台之间的互操作性，从而使存在的应用程序能够被广泛的用户访问。</font></p>
<p><font face="Arial">　　优势：</font></p>
<p><font face="Arial">　　(1).跨平台。<br />
　　(2).SOAP协议是基于XML和HTTP这些业界的标准的，得到了所有的重要公司的支持。<br />
　　(3).由于使用了SOAP，数据是以ASCII文本的方式而非二进制传输，调试很方便；并且由于这样，它的数据容易通过防火墙，不需要防火墙为了程序而单独开一个&#8220;漏洞&#8221;。<br />
　　(4).此外，WebService实现的技术难度要比CORBA和DCOM小得多。<br />
　　(5).要实现B2B集成，EDI比较完善与比较复杂；而用WebService则可以低成本的实现，小公司也可以用上。<br />
　　(6).在C/S的程序中，WebService可以实现网页无整体刷新的与服务器打交道并取数。</font></p>
<p><font face="Arial">　　缺点：</font></p>
<p><font face="Arial">　　(1).WebService使用了XML对数据封装，会造成大量的数据要在网络中传输。<br />
　　(2).WebService规范没有规定任何与实现相关的细节，包括对象模型、编程语言，这一点，它不如CORBA。</font></p>
<p><font face="Arial">　　10.多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么?</font></p>
<p><font face="Arial">　　答：多线程有两种实现方法，分别是继承Thread类与实现Runnable接口<br />
　　同步的实现方面有两种，分别是synchronized,wait与notify</font></p>
<p><font face="Arial">　　11.JSP中动态INCLUDE与静态INCLUDE的区别？&nbsp;&nbsp;</font></p>
<p><font face="Arial">　　动态INCLUDE用jsp:include动作实现</font></p>
<p><font face="Arial">&lt;jsp:include&nbsp;&nbsp; page="included.jsp"&nbsp;&nbsp; flush="true"/&gt;</font></p>
<p><font face="Arial">　　它总是会检查所含文件中的变化，适合用于包含动态页面，并且可以带参数</font></p>
<p><font face="Arial">　　静态INCLUDE用include伪码实现,定不会检查所含文件的变化，适用于包含静态页面</font></p>
<p><font face="Arial">　　&lt;%@&nbsp;&nbsp; include&nbsp;&nbsp; file="included.htm"&nbsp;&nbsp; %&gt;</font></p>
<p><font face="Arial">二、Java编程与程序运行结果</font></p>
<p><font face="Arial">　　1.Java编程,打印昨天的当前时刻</font></p>
<p><font face="Arial">public&nbsp;&nbsp; class&nbsp;&nbsp; YesterdayCurrent{<br />
&nbsp;&nbsp;&nbsp; public&nbsp;&nbsp; void&nbsp;&nbsp; main(String[]&nbsp;&nbsp; args){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calendar&nbsp;&nbsp; cal&nbsp;&nbsp; =&nbsp;&nbsp; Calendar.getInstance();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cal.add(Calendar.DATE,&nbsp;&nbsp; -1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(cal.getTime());<br />
&nbsp;&nbsp;&nbsp; }<br />
}</font></p>
<p><font face="Arial">　　2.文件读写,实现一个计数器</font></p>
<p><font face="Arial">程序代码： <br />
&nbsp;&nbsp; public int getNum(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i = -1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String stri="";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedReader in = new BufferedReader(new FileReader(f));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while((stri=in.readLine())!=null){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i = Integer.parseInt(stri.trim());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }catch(Exception e){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return i;<br />
&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp; public void setNum(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i = getNum();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i++;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PrintWriter out=new PrintWriter(new BufferedWriter(new FileWriter(f,false)));&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.write(String.valueOf(i));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //可能是编码的原因，如果直接写入int的话，将出现java编码和windows编码的混乱，因此此处写入的是String<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.close() ;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }catch(Exception e){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp; } </font></p>
<font face="Arial">
<p><br />
　　3.&nbsp;&nbsp; 指出下面程序的运行结果:</p>
<p>class&nbsp;&nbsp; A{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print("1");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp;&nbsp; A(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print("2");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
}<br />
class&nbsp;&nbsp; B&nbsp;&nbsp; extends&nbsp;&nbsp; A{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print("a");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp;&nbsp; B(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print("b");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
}<br />
public&nbsp;&nbsp; class&nbsp;&nbsp; Hello{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp;&nbsp; static&nbsp;&nbsp; void&nbsp;&nbsp; main(String[]&nbsp;&nbsp; ars){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A&nbsp;&nbsp; ab&nbsp;&nbsp; =&nbsp;&nbsp; new&nbsp;&nbsp; B();&nbsp;&nbsp; //执行到此处,结果:&nbsp;&nbsp; 1a2b<br />
ab&nbsp;&nbsp; =&nbsp;&nbsp; new&nbsp;&nbsp; B();&nbsp;&nbsp; //执行到此处,结果:&nbsp;&nbsp; 1a2bab<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
}<br />
　　注:类的static&nbsp;&nbsp; 代码段,可以看作是类首次加载(被虚拟机加载)执行的代码,而对于类的加载,首先要执行其基类的构造,再执行其本身的构造</p>
<p>　　4.写一个Singleton模式的例子</p>
<p>public&nbsp;&nbsp; class&nbsp;&nbsp; Singleton{<br />
private&nbsp;&nbsp; static&nbsp;&nbsp; Singleton&nbsp;&nbsp; single&nbsp;&nbsp; =&nbsp;&nbsp; new&nbsp;&nbsp; Singleton();<br />
private&nbsp;&nbsp; Singleton(){}<br />
public&nbsp;&nbsp; Singleton&nbsp;&nbsp; getInstance(){<br />
&nbsp;&nbsp;&nbsp; return&nbsp;&nbsp; single;<br />
}<br />
}<br />
三、数据库</p>
<p>　　1.删除表的重复记录</p>
<p>　　如果记录完全相同才算重复记录,那么:&nbsp;&nbsp;&nbsp;&nbsp; (sql&nbsp;&nbsp; server2000下测试通过)</p>
<p>select&nbsp;&nbsp; distinct&nbsp;&nbsp; *&nbsp;&nbsp; into&nbsp;&nbsp; #tmpp&nbsp;&nbsp; from&nbsp;&nbsp; tid<br />
delete&nbsp;&nbsp; from&nbsp;&nbsp; tid&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
insert&nbsp;&nbsp; into&nbsp;&nbsp; tid&nbsp;&nbsp; select&nbsp;&nbsp; *&nbsp;&nbsp; from&nbsp;&nbsp; #tmpp<br />
drop&nbsp;&nbsp; table&nbsp;&nbsp; #tmpp</p>
<p>　　如果有id主键(数字,自增1的那种),那么:(sql&nbsp;&nbsp; server2000下测试通过)</p>
<p>delete&nbsp;&nbsp; from&nbsp;&nbsp; tableA&nbsp;&nbsp; where&nbsp;&nbsp; id&nbsp;&nbsp; not&nbsp;&nbsp; in<br />
(select&nbsp;&nbsp; id&nbsp;&nbsp; =&nbsp;&nbsp; min(id)&nbsp;&nbsp; from&nbsp;&nbsp; tableA&nbsp;&nbsp; group&nbsp;&nbsp; by&nbsp;&nbsp; name)<br />
　　2.delete&nbsp;&nbsp; from&nbsp;&nbsp; tablea&nbsp;&nbsp; &amp;&nbsp;&nbsp; truncate&nbsp;&nbsp; table&nbsp;&nbsp; tablea的区别</p>
<p>　　truncate&nbsp;&nbsp; 语句执行速度快,占资源少,并且只记录页删除的日志；<br />
　　delete&nbsp;&nbsp; 对每条记录的删除均需要记录日志</p>
</font></div>
</div>
<img src ="http://www.blogjava.net/WshmAndLily/aggbug/143445.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/WshmAndLily/" target="_blank">semovy</a> 2007-09-07 15:57 <a href="http://www.blogjava.net/WshmAndLily/articles/143445.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Quartz从入门到进阶</title><link>http://www.blogjava.net/WshmAndLily/articles/143435.html</link><dc:creator>semovy</dc:creator><author>semovy</author><pubDate>Fri, 07 Sep 2007 07:42:00 GMT</pubDate><guid>http://www.blogjava.net/WshmAndLily/articles/143435.html</guid><wfw:comment>http://www.blogjava.net/WshmAndLily/comments/143435.html</wfw:comment><comments>http://www.blogjava.net/WshmAndLily/articles/143435.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/WshmAndLily/comments/commentRss/143435.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/WshmAndLily/services/trackbacks/143435.html</trackback:ping><description><![CDATA[<h4>摘要:</h4>
<p>你曾经需要应用执行一个任务吗？这个任务每天或每周星期二晚上11：30，或许仅仅每个月的最后一天执行。一个自动执行而无须干预的任务在执行过程中如果发生一个严重错误，应用能够知到其执行失败并尝试重新执行吗？果这些问题中任何一个你回答是，那么你应该使用Quartz调度器。Matrix目前就大量使用到了Quartz </p>
<p><strong><span style="font-size: 16px">Quartz</span><br />
<br />
</strong>Quartz是一个开源的作业调度框架，它完全由java写成，并设计用于J2SE和J2EE应用中。它提供了巨大的灵活性而不牺牲简单性。你能够用它来为执行一个作业而创建简单的或复杂的调度。它有很多特征，如：数据库支持，集群，插件，EJB作业预构建，JavaMail及其它，支持cron-like表达式等等。<br />
<br />
<strong>本文内容</strong><br />
<span style="color: maroon">1．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Quartz让任务调度简单<br />
2．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Quartz的发展史<br />
3．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 上手Quartz<br />
4．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Quartz内部架构<br />
5．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作业<br />
6．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作业管理和存储<br />
7．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 有效作业存储<br />
8．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作业和触发器<br />
9．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 调度一个作业<br />
10．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用调度器（Scheduler）调用你的作业<br />
11．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 编程调度同声明性调度<br />
12．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 有状态和无状态作业<br />
13．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Quartz框架的其他特征<br />
14．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Quartz下一步计划<br />
15．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 了解更多Quartz特征</span><br />
<br />
你曾经需要应用执行一个任务吗？这个任务每天或每周星期二晚上11：30，或许仅仅每个月的最后一天执行。一个自动执行而无须干预的任务在执行过程中如果发生一个严重错误，应用能够知到其执行失败并尝试重新执行吗？你和你的团队是用java编程吗？如果这些问题中任何一个你回答是，那么你应该使用Quartz调度器。<br />
<br />
<span style="color: red"><strong>旁注：</strong></span>Matrix目前就大量使用到了Quartz。比如，排名统计功能的实现，在Jmatrix里通过Quartz定义了一个定时调度作业，在每天凌晨一点，作业开始工作，重新统计大家的Karma和排名等。<br />
还有，RSS文件的生成，也是通过Quartz定义作业，每隔半个小时生成一次RSS XML文件。<br />
所以Quartz使用的地方很多，本文无疑是一篇很好的入门和进阶的文章，在此，感谢David w Johnson的努力！<br />
<br />
<br />
<strong><span style="font-size: 16px">Quartz让作业调度简单</span></strong><br />
<br />
Quartz是一个完全由java编写的开源作业调度框架。不要让作业调度这个术语吓着你。尽管Quartz框架整合了许多额外功能， 但就其简易形式看，你会发现它易用得简直让人受不了！。简单地创建一个实现org.quartz.Job接口的java类。Job接口包含唯一的方法：<br />
<br />
</p>
<pre class="overflow">public void execute(JobExecutionContext context) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws JobExecutionException;</pre>
<p><br />
<br />
在你的Job接口实现类里面，添加一些逻辑到execute()方法。一旦你配置好Job实现类并设定好调度时间表，Quartz将密切注意剩余时间。当调度程序确定该是通知你的作业的时候，Quartz框架将调用你Job实现类（作业类）上的execute()方法并允许做它该做的事情。无需报告任何东西给调度器或调用任何特定的东西。仅仅执行任务和结束任务即可。如果配置你的作业在随后再次被调用，Quartz框架将在恰当的时间再次调用它。<br />
<br />
如果你使用了其它流行的开源框架象struts，你会对Quartz的设计和部件感到舒适。虽然两个开源工程是解决完全不同的问题，还是有很多相似的之处，就是开源软件用户每天感觉很舒适。Quartz能用在单机J2SE应用中，作为一个RMI服务器，也可以用在web应用中，甚至也可以用在J2EE应用服务器中。<br />
<br />
<strong><span style="font-size: 16px">Quartz的发展史</span></strong><br />
<br />
尽管Quartz今年开始受到人们注意，但还是暂时流行。Quartz由James House创建并最初于2001年春天被加入sourceforge工程。接下来的几年里，有许多新特征和版本出现，但是直到项目迁移到新的站点并成为OpenSymphony项目家族的一员，才开始真正启动并受到应有的关注。<br />
James House仍然和几个协助他的业余开发者参与大量开发工作。Quartz开发团队今年能发布几个新版本，包括当前正处在候选发布阶段的1.5版。<br />
<br />
<strong><span style="font-size: 16px">上手Quartz</span></strong><br />
Quartz工程驻留在OpenSymphony站点上。在Quartz站点上可以找到许多有用的资源：JavaDocs，包含指南的文档，CVS访问，用户和开发者论坛的连接，当然也有下载。<br />
从下载连接取得Quartz的发布版本，并且解压到到本地目录。这个下载文件包含了一个预先构建好的Quartz二进制文件（quartz.jar），你可以将它放进自己的应用中。Quartz框架只需要少数的第三方库，并且这些三方库是必需的，你很可能已经在使用这些库了。<br />
<br />
你要把Quartz的安装目录的&lt;quartz- install&gt;/lib/core 和 &lt;quartz-install&gt;/lib/optional目录中的第三方库加进你自己的工程中。大多数第三方库是我们所熟知和喜欢的标准Jakarta Commons库，像Commons Logging, Commons BeantUtils等等。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<strong>quartz.properties文件</strong><br />
Quartz有一个叫做quartz.properties的配置文件，它允许你修改框架运行时环境。缺省是使用Quartz.jar里面的quartz.properties文件。当然，你应该创建一个quartz.properties文件的副本并且把它放入你工程的classes目录中以便类装载器找到它。quartz.properties样本文件如例1所示。<br />
<br />
例1.quartz.properties文件允许修改Quartz运行环境：<br />
<br />
</p>
<pre class="overflow">#===============================================================<br />
# Configure Main Scheduler Properties&nbsp;&nbsp;<br />
#===============================================================<br />
<br />
org.quartz.scheduler.instanceName = QuartzScheduler<br />
org.quartz.scheduler.instanceId = AUTO<br />
<br />
#===============================================================<br />
# Configure ThreadPool&nbsp;&nbsp;<br />
#===============================================================<br />
<br />
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool<br />
org.quartz.threadPool.threadCount =&nbsp;&nbsp; 5<br />
org.quartz.threadPool.threadPriority = 5<br />
<br />
#===============================================================<br />
# Configure JobStore&nbsp;&nbsp;<br />
#===============================================================<br />
<br />
org.quartz.jobStore.misfireThreshold = 60000<br />
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore</pre>
<p><br />
<br />
一旦将Quartz.jar文件和第三方库加到自己的工程里面并且quartz.properties文件在工程的classes目录中，就可以创建作业了。然而，在做这之前，我们暂且回避一下先简短讨论一下Quartz架构。<br />
<br />
<strong><span style="font-size: 16px">Quartz内部架构</span></strong><br />
在规模方面，Quartz跟大多数开源框架类似。大约有300个java类和接口，并被组织到12个包中。这可以和Apache Struts把大约325个类和接口以及组织到11个包中相比。尽管规模几乎不会用来作为衡量框架质量的一个特性，但这里的关键是quarts内含很多功能，这些功能和特性集是否成为、或者应该成为评判一个开源或非开源框架质量的因素。<br />
<br />
<strong>Quartz调度器</strong><br />
Quartz框架的核心是调度器。调度器负责管理Quartz应用运行时环境。调度器不是靠自己做所有的工作，而是依赖框架内一些非常重要的部件。Quartz不仅仅是线程和线程管理。为确保可伸缩性，Quartz采用了基于多线程的架构。启动时，框架初始化一套worker线程，这套线程被调度器用来执行预定的作业。这就是Quartz怎样能并发运行多个作业的原理。Quartz依赖一套松耦合的线程池管理部件来管理线程环境。本片文障中，我们会多次提到线程池管理，但Quartz里面的每个对象是可配置的或者是可定制的。所以，例如，如果你想要插进自己线程池管理设施，我猜你一定能！<br />
<br />
<strong><span style="font-size: 16px">作业</span></strong><br />
用Quartz的行话讲，作业是一个执行任务的简单java类。任务可以是任何java代码。只需你实现org.quartz.Job接口并且在出现严重错误情况下抛出JobExecutionException异常即可。Job接口包含唯一的一个方法execute()，作业从这里开始执行。一旦实现了Job接口和execute()方法，当Quartz确定该是作业运行的时候，它将调用你的作业。Execute()方法内就完全是你要做的事情。下面有一些你要在作业里面做事情的例子：<br />
&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用JavaMail（或者用其他的像Commons Net一样的邮件框架）发送邮件<br />
&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 创建远程接口并且调用在EJB上的方法<br />
&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 获取Hibernate Session，查询和更新关系数据库里的数据<br />
&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用OSWorkflow并且从作业调用一个工作流<br />
&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用FTP和到处移动文件<br />
&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 调用Ant构建脚本开始预定构建<br />
<br />
这种可能性是无穷的，正事这种无限可能性使得框架功能如此强大。Quartz给你提供了一个机制来建立具有不同粒度的、可重复的调度表，于是，你只需创建一个java类，这个类被调用而执行任务。<br />
<br />
<strong><span style="font-size: 16px">作业管理和存储</span></strong><br />
作业一旦被调度，调度器需要记住并且跟踪作业和它们的执行次数。如果你的作业是30分钟后或每30秒调用，这不是很有用。事实上，作业执行需要非常准确和即时调用在被调度作业上的execute()方法。Quartz通过一个称之为作业存储（JobStore）的概念来做作业存储和管理。<br />
<br />
<br />
<strong><span style="font-size: 16px">有效作业存储</span></strong><br />
<br />
Quartz提供两种基本作业存储类型。第一种类型叫做RAMJobStore，它利用通常的内存来持久化调度程序信息。这种作业存储类型最容易配置、构造和运行。对许多应用来说，这种作业存储已经足够了。然而，因为调度程序信息是存储在被分配给JVM的内存里面，所以，当应用程序停止运行时，所有调度信息将被丢失。如果你需要在重新启动之间持久化调度信息，则将需要第二种类型的作业存储。<br />
<br />
第二种类型的作业存储实际上提供两种不同的实现，但两种实现一般都称为JDBC作业存储。两种JDBC作业存储都需要JDBC驱动程序和后台数据库来持久化调度程序信息。这两种类型的不同在于你是否想要控制数据库事务或这释放控制给应用服务器例如BEA's WebLogic或Jboss。（这类似于J2EE领域中，Bean管理的事务和和容器管理事务之间的区别）<br />
这两种JDBC作业存储是：<br />
<br />
&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JobStoreTX：当你想要控制事务或工作在非应用服务器环境中是使用<br />
&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JobStoreCMT：当你工作在应用服务器环境中和想要容器控制事务时使用。<br />
<br />
JDBC作业存储为需要调度程序维护调度信息的用户而设计。<br />
<br />
<strong><span style="font-size: 16px">作业和触发器</span></strong><br />
<br />
Quartz设计者做了一个设计选择来从调度分离开作业。Quartz中的触发器用来告诉调度程序作业什么时候触发。框架提供了一把触发器类型，但两个最常用的是SimpleTrigger和CronTrigger。SimpleTrigger为需要简单打火调度而设计。典型地，如果你需要在给定的时间和重复次数或者两次打火之间等待的秒数打火一个作业，那么SimpleTrigger适合你。另一方面，如果你有许多复杂的作业调度，那么或许需要CronTrigger。<br />
<br />
CronTrigger是基于Calendar-like调度的。当你需要在除星期六和星期天外的每天上午10点半执行作业时，那么应该使用CronTrigger。正如它的名字所暗示的那样，CronTrigger是基于Unix克隆表达式的。<br />
<br />
作为一个例子，下面的Quartz克隆表达式将在星期一到星期五的每天上午10点15分执行一个作业。<br />
<span style="color: blue">0 15 10 ? * MON-FRI</span><br />
<br />
下面的表达式<br />
<span style="color: blue">0 15 10 ? * 6L 2002-2005</span><br />
将在2002年到2005年的每个月的最后一个星期五上午10点15分执行作业。<br />
<br />
你不可能用SimpleTrigger来做这些事情。你可以用两者之中的任何一个，但哪个跟合适则取决于你的调度需要。<br />
<br />
<br />
<strong><span style="font-size: 16px">调度一个作业</span></strong><br />
<br />
让我们通过看一个例子来进入实际讨论。现假定你管理一个部门，无论何时候客户在它的FTP服务器上存储一个文件，都得用电子邮件通知它。我们的作业将用FTP登陆到远程服务器并下载所有找到的文件。然后，它将发送一封含有找到和下载的文件数量的电子邮件。这个作业很容易就帮助人们整天从手工执行这个任务中解脱出来，甚至连晚上都无须考虑。我们可以设置作业循环不断地每60秒检查一次，而且工作在7&#215;24模式下。这就是Quartz框架完全的用途。<br />
<br />
首先创建一个Job类，将执行FTP和Email逻辑。下例展示了Quartz的Job类，它实现了org.quartz.Job接口。<br />
<br />
例2．从FTP站点下载文件和发送email的Quartz作业<br />
<br />
</p>
<pre class="overflow">public class ScanFTPSiteJob implements Job {<br />
&nbsp;&nbsp;&nbsp;&nbsp; private static Log logger = LogFactory.getLog(ScanFTPSiteJob.class);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; /*<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Called the scheduler framework at the right time<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp;&nbsp; public void execute(JobExecutionContext context)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws JobExecutionException {<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JobDataMap jobDataMap = context.getJobDataMap();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Check the ftp site for files<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File[] files = JobUtil.checkForFiles(jobDataMap);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JobUtil.sendEmail(jobDataMap, files);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (Exception ex) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new JobExecutionException(ex.getMessage());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp; }<br />
}</pre>
<p><br />
<br />
我们故意让ScanFTPSiteJob保持很简单。我们为这个例子创建了一个叫做JobUtil的实用类。它不是Quartz的组成部分，但对构建各种作业能重用的实用程序库来说是有意义的。我们可以轻易将那种代码组织进作业类中，quarts 调度器一样好用，因为我们一直在使用quarts，所以那些代码可继续重用。<br />
<br />
JobUtil.checkForFiles() and JobUtil.sendEmail()方法使用的参数是Quartz创建的JobDataMap的实例。实例为每个作业的执行而创建，它是向作业类传递配置参数的方法。<br />
这里并没有展示JobUtil的实现，但我们能用Jakarta上的Commons Net轻易地实现FTP和Email功能。<br />
<br />
<strong><span style="font-size: 16px">用调度器调用作业</span></strong><br />
<br />
首先创建一个作业，但为使作业能被调度器调用，你得向调度程序说明你的作业的调用时间和频率。这个事情由与作业相关的触发器来完成。因为我们仅仅对大约每60秒循环调用作业感兴趣，所以打算使用SimpleTrigger。<br />
<br />
作业和触发器通过Quartz调度器接口而被调度。我们需要从调度器工厂类取得一个调度器的实例。最容易的办法是调用StdSchedulerFactory这个类上的静态方法getDefaultScheduler()。<br />
使用Quartz框架，你需要调用start()方法来启动调度器。例3的代码遵循了大多数Quartz应用的一般模式：创建一个或多个作业，创建和设置触发器，用调度器调度作业和触发器，启动调度器。<br />
<br />
例3．Quartz作业通过Quartz调度器而被调度<br />
<br />
</p>
<pre class="overflow">public class MyQuartzServer {<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; public static void main(String[] args) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MyQuartzServer server = new MyQuartzServer();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; server.startScheduler();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (SchedulerException ex) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ex.printStackTrace();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; protected void startScheduler() throws SchedulerException {<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Use the factory to create a Scheduler instance<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // JobDetail holds the definition for Jobs<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JobDetail jobDetail = <br />
new JobDetail("ScanFTPJob", Scheduler.DEFAULT_GROUP,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ScanFTPSiteJob.class);<br />
<br />
// Store job parameters to be used within execute()<br />
jobDetail.getJobDataMap().put(<br />
"FTP_HOST", <br />
"\\home\\cavaness\\inbound");<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Other neccessary Job parameters here<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Create a Trigger that fires every 60 seconds<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Trigger trigger = TriggerUtils.makeSecondlyTrigger(60);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Setup the Job and Trigger with the Scheduler<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; scheduler.scheduleJob(jobDetail, trigger );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Start the Scheduler running<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; scheduler.start();<br />
&nbsp;&nbsp;&nbsp;&nbsp; }<br />
}</pre>
<p><br />
<br />
<br />
<strong><span style="font-size: 16px">编程调度同声明性调度</span></strong><br />
<br />
例3中，我们通过编程的方法调度我们的ScanFTPSiteJob作业。就是说，我们用java代码来设置作业和触发器。Quartz框架也支持在xml文件里面申明性的设置作业调度。申明性方法允许我们更快速地修改哪个作业什么时候被执行。<br />
<br />
Quartz框架有一个插件，这个插件负责读取xml配置文件。xml配置文件包含了关于启动Quartz应用的作业和触发器信息。所有xml文件中的作业连同相关的触发器都被加进调度器。你仍然需要编写作业类，但配置那些作业类的调度器则非常动态化。例4展示了一个用申明性方式执行与例3代码相同的逻辑的xml配置文件。<br />
<br />
例4．能使用xml文件调度的作业<br />
<br />
</p>
<pre class="overflow">&lt;?xml version='1.0' encoding='utf-8'?&gt;<br />
&lt;quartz&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;job&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;job-detail&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;name&gt;ScanFTPSiteJob&lt;/name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;group&gt;DEFAULT&lt;/group&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;description&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A job that scans an ftp site for files<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/description&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;job-class&gt;ScanFTPSiteJob&lt;/job-class&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;job-data-map allows-transient-data="true"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;entry&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;key&gt;FTP_HOST&lt;/key&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;\home\cavaness\inbound&lt;/value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/entry&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!--&nbsp;&nbsp; Other neccessary Job parameters here --&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/job-data-map&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/job-detail&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;trigger&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;simple&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;name&gt;ScanFTPSiteJobTrigger&lt;/name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;group&gt;DEFAULT&lt;/group&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;job-name&gt;ScanFTPSiteJob&lt;/job-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;job-group&gt;DEFAULT&lt;/job-group&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;start-time&gt;2005-09-11 6:10:00 PM&lt;/start-time&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- repeat indefinitely every 60 seconds --&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;repeat-count&gt;-1&lt;/repeat-count&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;repeat-interval&gt;60000&lt;/repeat-interval&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/simple&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/trigger&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;/job&gt;<br />
&lt;/quartz&gt;</pre>
<p><br />
<br />
你可以将xml文件中的元素跟例3代码作个比较，它们从概念上来看是相同的。使用例4式的申明性方法的好处是维护变得极其简单，只需改变xml配置文件和重新启动Quartz应用即可。无须修改代码，无须重新编译，无须重新部署。<br />
<br />
<strong><span style="font-size: 16px">有状态和无状态作业</span></strong><br />
<br />
在本文中你所看到的作业到是无状态的。这意味着在两次作业执行之间，不会去维护作业执行时JobDataMap的状态改变。如果你需要能增、删，改JobDataMap的值，而且能让作业在下次执行时能看到这个状态改变，则需要用Quartz有状态作业。<br />
如果你是一个有经验的EJB开发者的话，深信你会立即退缩，因为有状态带有负面含义。这主要是由于EJB带来的伸缩性问题。Quartz有状态作业实现了org.quartz.StatefulJob接口。无状态和有状态作业的关键不同是有状态作业在每次执行时只有一个实例。大多数情况下，有状态的作业不回带来大的问题。然而，如果你有一个需要频繁执行的作业或者需要很长时间才能完成的作业，那么有状态作业可能给你带来伸缩性问题。<br />
<br />
<strong><span style="font-size: 16px">Quartz框架的其他特征</span></strong><br />
<br />
Quartz框架有一个丰富的特征集。事实上，quarts有太多特性以致不能在一种情况中全部领会，下面列出了一些有意思的特征，但没时间在此详细讨论。<br />
<br />
<strong>监听器和插件</strong><br />
<br />
每个人都喜欢监听和插件。今天，几乎下载任何开源框架，你必定会发现支持这两个概念。监听是你创建的java类，当关键事件发生时会收到框架的回调。例如，当一个作业被调度、没有调度或触发器终止和不再打火时，这些都可以通过设置来来通知你的监听器。Quartz框架包含了调度器监听、作业和触发器监听。你可以配置作业和触发器监听为全局监听或者是特定于作业和触发器的监听。<br />
<br />
一旦你的一个具体监听被调用，你就能使用这个技术来做一些你想要在监听类里面做的事情。例如，你如果想要在每次作业完成时发送一个电子邮件，你可以将这个逻辑写进作业里面，也可以JobListener里面。写进JobListener的方式强制使用松耦合有利于设计上做到更好。<br />
<br />
Quartz插件是一个新的功能特性，无须修改Quartz源码便可被创建和添加进Quartz框架。他为想要扩展Quartz框架又没有时间提交改变给Quartz开发团队和等待新版本的开发人员而设计。如果你熟悉Struts插件的话，那么完全可以理解Quartz插件的使用。<br />
<br />
与其Quartz提供一个不能满足你需要的有限扩展点，还不如通过使用插件来拥有可修整的扩展点。<br />
<br />
<strong>集群Quartz应用</strong><br />
Quartz应用能被集群，是水平集群还是垂直集群取决于你自己的需要。集群提供以下好处：<br />
&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 伸缩性<br />
&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 搞可用性<br />
&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 负载均衡<br />
目前，Quartz只能借助关系数据库和JDBC作业存储支持集群。将来的版本这个制约将消失并且用RAMJobStore集群将是可能的而且将不需要数据库的支持。<br />
<br />
<strong>Quartz web应用</strong><br />
使用框架几个星期或几个月后，Quartz用户所显示的需求之一是需要集成Quartz到图形用户界面中。目前Quartz框架已经有一些工具允许你使用Java servlet来初始化和启动Quartz。一旦你可以访问调度器实例，你就可以把它存储在web容器的servlet上下文中（ServletContext中）并且可以通过调度器接口管理调度环境。<br />
<br />
幸运的是一些开发者已正影响着单机Quartz web应用，它用来更好地管理调度器环境。构建在若干个流行开源框架如Struts和Spring之上的图形用户界面支持很多功能，这些功能都被包装进一个简单接口。GUI的一个画面如图1所示：<br />
<br />
<br />
<img style="display: inline" alt="image" src="http://www.matrix.org.cn/resource/upload/article/2005_11_21_215014_IqWaiHmDYR.gif" border="0" resized="0" /><br />
图1.Quartz Web应用允许比较容易地管理Quartz环境。<br />
<br />
<strong><span style="font-size: 16px">Quartz的下一步计划</span></strong><br />
<br />
Quartz是一个活动中的工程。Quartz开发团队明确表示不会停留在已有的荣誉上。Quartz下一个主要版本已经在启动中。你可以在OpenSymphony的 wiki上体验一下Quartz 2.0的设计和特征。<br />
总之，Quartz用户每天都自由地添加特性建议和设计创意以便能被核心框架考虑（看重）。<br />
<br />
<strong><span style="font-size: 16px">了解更多Quartz特征</span></strong><br />
<br />
当你开始使用Quartz框架的更多特性时，User and Developer Forum论坛变成一个回答问题和跟其他Quartz用户沟通的极其有用的资源。经常去逛逛这个论坛时很有好处的，你也可以依靠James House来共享与你的需要相关的知识和意见。<br />
<br />
这个论坛时免费的，你不必登陆便可以查找和查看归档文件。然而，如果你觉得这个论坛比较好而且需要向某人回复问题时，你必须得申请一个免费帐号并用该帐号登陆。<br />
</p>
<img src ="http://www.blogjava.net/WshmAndLily/aggbug/143435.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/WshmAndLily/" target="_blank">semovy</a> 2007-09-07 15:42 <a href="http://www.blogjava.net/WshmAndLily/articles/143435.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java企业应用系统框架的比较与选择</title><link>http://www.blogjava.net/WshmAndLily/articles/135815.html</link><dc:creator>semovy</dc:creator><author>semovy</author><pubDate>Fri, 10 Aug 2007 06:11:00 GMT</pubDate><guid>http://www.blogjava.net/WshmAndLily/articles/135815.html</guid><wfw:comment>http://www.blogjava.net/WshmAndLily/comments/135815.html</wfw:comment><comments>http://www.blogjava.net/WshmAndLily/articles/135815.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/WshmAndLily/comments/commentRss/135815.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/WshmAndLily/services/trackbacks/135815.html</trackback:ping><description><![CDATA[摘 要 目前流行的Java企业应用系统框架种类繁多，为了使开发人员正确选择系统架构从而提高Java企业应用的开发效率，首先针对基于EJB和基于POJOs的较为流行的几种框架分别进行了概述，然后对这些框架从表现层、业务逻辑层和持久层的实现细节进行了对比，总结了Java企业应用系统框架选择需要侧重考虑因素，得到了基于EJB的框架和基于POJOs的框架分别适用的范围。 <br><br><strong>　　关键词</strong> Java企业应用系统框架；EJB3.0；Spring；Hibernate <br><br>　　<strong>引言</strong> <br><br>　　EJB的体系结构是J2EE的基础和核心，J2EE定义了整个标准的应用开发体系结构和一个部署环境，基于EJB的框架一度成为人们开发Java企业应用的首选。随着Java开源项目阵营的发展壮大， 一些基于POJOs(Plan Old Java Objects)的开源框架被越来越广泛地引入到Java企业应用的开发中来。根据复杂程度人们习惯把前者称为重量级框架，把后者称为轻量级框架。Java企业应用框架一般被划分为三个层次：表现层、业务逻辑组件层和持久层。本文主要对目前企业应用对应于这三个层次的两种类型的流行框架进行了细节比较，最后针对Java企业应用的系统框架选择提出作者的观点。<br><br>　　<strong>两种类型框架概述</strong> <br><br>　　1、基于EJB的重量级框架 <br><br>　　由于 EJB容器能够很好的处理系统性能、事务机制、安全访问权限以及分布式运算等问题，基于EJB框架进行开发能保证企业应用平滑发展，而不是发展到一种规模就重新更换一套软件系统，且可以保证开发人员将大部份精力集中在业务逻辑的开发上。采用EJB框架开发的企业应用具有必须继承或依赖EJB容器的特点。EJB充分考虑到了顶级大型项目的需求，使用它几乎能解决企业级应用涉及到的所有问题，相应的基于EJB框架也是一个功能复杂的重量级框架。<br><br>　　J2EE1.4标准规定的EJB 2.1框架缺少设计且实现起来有些过于复杂。当前J2EE5.0的新规范提出的EJB 3.0的目标就是简化开发[1]，借鉴了一些基于POJO的思想，它相对于EJB2.1中两个重要的变化分别是：一是使用了Java5中的程序注释工具，注释取代了过多的XML配置文件并且消除了严格组件模型需求；二是采用了基于Hibernate和TopLink思想的O/R Mapping模型。<br><br>　　J2EE5.0的新规范中定义企业应用三个层次的标准实现为：表现层采用JSF（Java Server Face），JSF的开发流程的核心是事件驱动，组件和标签的封装程度非常高，很多典型应用已经不需要开发者去处理http。整个过程是通过IoC(依赖注入)[2]来实现的；业务组件层采用EJB3.0的Session Bean。EJB3.0允许开发者使用藕合松散的组件来开发应用。这些组件通过自己发布的商业接口来耦合，不必像EJB 2.1规范定义的那样一个Bean必须遵守的严格的组件模型，每一个EJB类必须从某一种抽象类中继承，并为容器提供了回调的钩子；持久层采用EJB3.0实体Bean持久化模型，吸收了Hibernate的一些思想采用O/R Mapping模式， EJBQL也有许多重要的改变。<br><br>　　2、基于POJOs的轻量级框架<br><br>　　在基于POJOs轻量级框架上开发的应用程序无需依赖于EJB容器可独立运行，对应于Java企业应用三个层次的轻量级框架技术分别都得到了一定的发展，这三个层次流行的框架如下：<br><br>　　目前比较流行的开源表现层框架主要有Struts和Tapestry。Tapestry与Struts应用框架不同的是，它是基于组件，而不是面向脚本语言（比如JSP和Velocity）的，组件是由一个定义文件(以XML的格式)、一个HTML模板、一个JAVA类构成的；业务组件层轻量级解决方案也不少，包括Spring、Hivemind等。但是目前使用最为广泛的还是Spring框架，Spring框架是一个基于IoC和AOP（面向方面编程）[3]的构架。采用IoC使得它可以很容易的实现bean的装配，提供了简洁的AOP并据此实现事务管理等，但是它不具备处理应用分布式的能力。Spring的核心要点是：支持不绑定到特定J2EE服务的可重用业务和数据访问对象。这样的对象可以在不同J2EE环境（Web或EJB）、独立应用程序、测试环境之间重用；持久层框主要有Hibernate和各种JDO产品，以及iBATIS。Hibernate是一个开源的O/R Mapping框架，它对JDBC进行了非常轻量级的对象封装，可以应用在任何使用JDBC的场合，可以在应用EJB的J2EE框架中取代CMP，完成数据持久化的重任。iBATIS是一个简易的SQL Map工具，它是将手工编写的在xml配置文件中的SQL语句映射成Java对象。<br>　　<strong>对应于三个层次的框架比较</strong> <br><br>　　1、表现层框架比较 <br><br>　　MVC设计模式不再是某一种表现层框架的特点而是这几种框架的共性。Struts框架由于出现时间早，所以使用相对广泛，它的社区非常活跃，很容易找到很多现成的开源功能标签以供使用以及样例程序可供参考。但是它的组件在页面中显示的粗粒度，以及框架类的限制在很多情况下会表现得过于死板，给表示层的开发会带来一些额外的代码开销。JSF在很大程度上类似Struts，只是JSF的组件概念没有象Struts那样必须继承ActionForm的限制，JSF在事件粒度上要比Struts细腻。JSF有的另外一个优势就是其身后有Sun公司和其他的一些大公司的支持。Tapestry是一个完全组件的框架，Tapestry的组件可以被套嵌并包裹其它组件，因此可以组合形成一个更大的组件或逻辑页面。组件的行为模式为Web页面编程提供了很大的方便，事件处理也方便很多。所以，如果做一个对页面要求灵活度相当高的系统就可以考虑选用Tapestry。<br><br>　　表1 三种框架的表现层功能技术细节比较<br><br>
<table cellSpacing=0 cellPadding=0 border=1>
    <tbody>
        <tr>
            <td width=96><br>框架<br></td>
            <td width=228><br>Struts<br></td>
            <td width=168><br>Tapestry3.0<br></td>
            <td width=156><br>JSF<br></td>
        </tr>
        <tr>
            <td width=96><br>View组件实现模式<br></td>
            <td width=228><br>标签库+组件，组件必须继承ActionForm<br></td>
            <td width=168><br>完全组件，分显式调用和隐式调用，组件必须继承BaseComponent<br></td>
            <td width=156><br>标签库+组件，普通POJO无需继承<br></td>
        </tr>
        <tr>
            <td width=96><br>组件在View显示粒度<br></td>
            <td width=228><br>View页面只能显示与表单对应的ActionForm，配置中Action与 ActionForm与 页面一般只能1:1:1关系。<br></td>
            <td width=168><br>可将组件嵌入页面任何一行，对使用组件数量无限制。<br></td>
            <td width=156><br>同Tapestry<br></td>
        </tr>
        <tr>
            <td width=96><br>页面跳转<br></td>
            <td width=228><br>使用标签库html:link中写明目标URL，URL名称需要对照struts_config.xml配置文件中的path命名，与组件Action耦合。<br></td>
            <td width=168><br>URL名称是目标的组件名称，不涉及URL和路径等操作，方便稳固。<br></td>
            <td width=156><br>类似Struts，也需要在配置文件中查找，与组件分离。<br></td>
        </tr>
        <tr>
            <td width=96><br>事件触发<br></td>
            <td width=228><br>通过表单提交submit激活，不能细化到表单里字段。<br></td>
            <td width=168><br>能够给于表单每个字段赋一个事件，事件组件必须实现PageListener接口<br></td>
            <td width=156><br>同Tapestry，事件组件必须实现ActionListener <br></td>
        </tr>
    </tbody>
</table>
<br>　　2、业务组件层框架比较 <br><br>　　EJB 2.1框架有些过于复杂了，有如下缺点：① EJB模型需要建立许多组件接口和实现许多不必要的回滚方法；②EJB的部署描述复杂而容易出错；③开发人员不能脱离EJB容器测试。对于以上缺点JCP (Java Community Process)制订的EJB3.0标准框架做了相应的改进，该框架为所有主要的J2EE厂商支持。EJB3.0和Spring两个框架结构都有一个共同核心设计理念：将中间件服务传递给耦合松散的POJOs。<br><br>　　EJB3.0框架与应用<a class=bluekey href="http://server.chinabyte.com/" target=_blank><u><font color=#0000ff>服务器</font></u></a>高度整合，服务整合代码也包装在一个标准接口后面。EJB框架一方面有成熟的EJB容器支持，基于EJB框架的企业应用性能优良；另一方面EJB容器设计因为考虑了多方面的功能，所以在其内核上总是会显得臃肿，这也是一种重量表现。不需要的东西存在肯定会影响效率，EJB不能根据项目需求对EJB整体包括EJB容器进行可配置式的切割。<br><br>　　Spring框架处于应用服务器和服务库的上方，服务整合的代码属于框架，并暴露于应用开发者。它与应用服务器整合的能力相对EJB3.0要弱。但是Spring框架模块的可分离配置体现了它优于EJB3.0的灵活性。<br><br>　　表2 EJB和Spring框架的具体细节比较<br>
<table cellSpacing=0 cellPadding=0 border=1>
    <tbody>
        <tr>
            <td width=96><br>框架<br></td>
            <td width=258><br>EJB2/EJB3<br></td>
            <td width=294><br>Spring Framework 1.x<br></td>
        </tr>
        <tr>
            <td width=96><br>灵活性(松耦合)<br></td>
            <td width=258><br>EJB3比EJB2更具灵活性，EJB3支持应用系统POJO<br></td>
            <td width=294><br>支持应用系统POJO，框架本身可分离配置<br></td>
        </tr>
        <tr>
            <td width=96><br>功能完整性<br></td>
            <td width=258><br>全面，支持异步JMS 分布式事务<br></td>
            <td width=294><br>较为全面。有自己的表现层和持久层模板，可支持异步<br></td>
        </tr>
        <tr>
            <td width=96><br>领域范围<br></td>
            <td width=258><br>支持业务逻辑Session<br></td>
            <td width=294><br>不支持，需要开发者额外基于ThreadLocal编制代码<br></td>
        </tr>
        <tr>
            <td width=96><br>IoC/AOP支持<br></td>
            <td width=258><br>EJB3支持IoC， JBoss等EJB3服务器支持AOP；基于业务组件的较粗粒度<br></td>
            <td width=294><br>基于JavaBeans类的细粒度支持AOP<br></td>
        </tr>
        <tr>
            <td width=96><br>单台性能<br></td>
            <td width=258><br>一般，批量查询等大数据量业务处理须小心，存在本地不透明缺陷。<br></td>
            <td width=294><br>一般，应用程序可配置cache/Pool以提高性能<br></td>
        </tr>
        <tr>
            <td width=96><br>可伸缩性<br></td>
            <td width=258><br>可支持多台服务器分布式计算。<br></td>
            <td width=294><br>不支持，可依靠EJB实现<br></td>
        </tr>
        <tr>
            <td width=96><br>开发效率<br></td>
            <td vAlign=top width=258><br>学习曲线长，导致熟练掌握难。借助商业开发工具可加快熟练者的开发速度。<br></td>
            <td vAlign=top width=294><br>可挑选只适合自己的功能实现。相对EJB稍简单。<br></td>
        </tr>
        <tr>
            <td width=96><br>系统规模<br></td>
            <td width=258><br>EJB2适合大型系统;EJB3适合中大型系统<br></td>
            <td width=294><br>适合中小型系统，可借助EJB支持中大型系统<br></td>
        </tr>
    </tbody>
</table>
<br>　　3、持久层框架比较 <br><br>　　容器管理持久性（CMP）是对EJB中Entity Bean进行持久性管理的方式。EJB2.1 持久性模型过于复杂并且存在基础缺陷[3]。EJB3.0持久层针对EJB2.1的缺陷做了相应改进，采用与Hibernate类似的机制。<br><br>　　Hibernate相对而言其基本优势如下：①Hibernate 使用 Java 反射机制而不是字节码增强程序来实现透明性；②Hibernate的使用简单；③映射的灵活性很出色，它支持各种关系数据库，从一对一到多对多的各种复杂关系。Hibernate 也有一些缺点，它限制所使用的对象模型 (例如，一个持久性类不能映射到多个表)。 <br>　　　　　　　　　　　　　　　　　　　　　　　<br>　　使用iBATIS提供的O/R Mapping机制，对业务逻辑实现人员而言，面对的是纯粹的Java对象，这一层与通过Hibernate 实现O/R Mapping 而言基本一致，而对于具体的数据操作，Hibernate 会自动生成SQL 语句，而iBATIS则要求开发者编写具体的SQL 语句。相对Hibernate等 &#8220;全自动&#8221;O/R Mapping机制而言，iBATIS以SQL开发的工作量和数据库移植性上的让步，为系统设计提供了更大的自由空间。作为&#8220;全自动&#8221;ORM 实现的一种有益补充，iBATIS的出现显得别具意义。<br><br>　　<strong>企业应用系统框架选择</strong> <br><br>　　设计和性能是实际框架选择的两个基本点，善于平衡才是框架选择的主要宗旨。轻量级框架和重量级框架解决问题的侧重点是不同的。<br><br>　　轻量级框架侧重于减小开发的复杂度，相应的它的处理能力便有所减弱（如事务功能弱、不具备分布式处理能力），比较适用于开发中小型企业应用。采用轻量框架一方面因为尽可能的采用基于POJOs的方法进行开发，使应用不依赖于任何容器，这可以提高开发调试效率；另一方面轻量级框架多数是开源项目，开源社区提供了良好的设计和许多快速构建工具以及大量现成可供参考的开源代码，这有利于项目的快速开发。例如目前Tomcat+Spring+Hibernate已经成为许多开发者开发J2EE中小型企业应用偏爱的一种架构选择。随着可供选择的框架层出不穷，开发者可以根据需要对应于企业应用三个层次的轻量级框架选择，本文第2节的内容可供选择参考。<br><br>　　而作为重量级框架EJB框架则强调高可伸缩性，适合与开发大型企业应用。在EJB体系结构中，一切与基础结构服务相关的问题和底层分配问题都由应用程序容器或服务器来处理，且EJB容器通过减少数据库访问次数以及分布式处理等方式提供了专门的系统性能解决方案，能够充分解决系统性能问题。<br><br>　　轻量级框架的产生并非是对重量级框架的否定，甚至在某种程度上可以说二者是互补的。轻量级框架在努力发展以开发具有更强大，功能更完备的企业应用；而新的EJB规范EJB3.0则在努力简化J2EE的使用以使得EJB不仅仅是擅长处理大型企业系统，也利用开发中小型系统，这也是EJB轻量化的一种努力。对于大型企业应用以及将来可能涉及到能力扩展的中小型应用采用结合使用轻量级框架和重量级框架也不失为一种较好的解决方案。<br><br>　　<strong>总结</strong> 　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　<br>　　目前适用Java企业应用的系统框架可谓百花齐放，各种框架都有长短，选择应用系统框架时不可盲目的追求流行，首先需要明确所要实现的应用系统的系统处理能力需求，然后在熟悉比较各种框架细节的基础上从设计以及开发效率方面进行考虑。本文旨在为系统框架选择提供一个参考，限于篇幅本文只对其中的几种框架做了比较，开发者可以根据需要对更多其他框架细节进行比较。(转载文章请保留出处：<a href="http://www.javajia.com/"><u><font color=#0000ff>Java家(www.javajia.com)</font></u></a>) 
<img src ="http://www.blogjava.net/WshmAndLily/aggbug/135815.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/WshmAndLily/" target="_blank">semovy</a> 2007-08-10 14:11 <a href="http://www.blogjava.net/WshmAndLily/articles/135815.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ajax参数传递时含有特殊字符解决(否则只获取一部分字符，或者出错)</title><link>http://www.blogjava.net/WshmAndLily/articles/130590.html</link><dc:creator>semovy</dc:creator><author>semovy</author><pubDate>Mon, 16 Jul 2007 07:33:00 GMT</pubDate><guid>http://www.blogjava.net/WshmAndLily/articles/130590.html</guid><wfw:comment>http://www.blogjava.net/WshmAndLily/comments/130590.html</wfw:comment><comments>http://www.blogjava.net/WshmAndLily/articles/130590.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/WshmAndLily/comments/commentRss/130590.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/WshmAndLily/services/trackbacks/130590.html</trackback:ping><description><![CDATA[我的统一编码是UTF-8<br><br>ajax 的XMLHttpRequest的头部http_request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");默认编码是utf-8，我以post的方式向服务器提交文章<br><br>var url = "../../article.do?action=save";<br>&nbsp;&nbsp;articleXMLHttpRequest = getXMLHttpRequest();<br>&nbsp;&nbsp;send_request(articleXMLHttpRequest,"post",url,"itemId=" + itemId + "&amp;title=" + title + "&amp;content=" + <span style="COLOR: red">escape(encodeURIComponent(content)),"</span>xml",initialArticlesList);<br><br>经过encodeURIComponent();编码<br>&nbsp;&nbsp;<br><br>在服务器解码,用java.net.URLDecoder <br><br>String content = new URLDecoder().decode(request.getParameter("content"),"utf-8");以utf-8以方式解码
<img src ="http://www.blogjava.net/WshmAndLily/aggbug/130590.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/WshmAndLily/" target="_blank">semovy</a> 2007-07-16 15:33 <a href="http://www.blogjava.net/WshmAndLily/articles/130590.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>FCKeditor_2.3.2 在线网页编辑器(Java) </title><link>http://www.blogjava.net/WshmAndLily/articles/123193.html</link><dc:creator>semovy</dc:creator><author>semovy</author><pubDate>Sun, 10 Jun 2007 07:44:00 GMT</pubDate><guid>http://www.blogjava.net/WshmAndLily/articles/123193.html</guid><wfw:comment>http://www.blogjava.net/WshmAndLily/comments/123193.html</wfw:comment><comments>http://www.blogjava.net/WshmAndLily/articles/123193.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/WshmAndLily/comments/commentRss/123193.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/WshmAndLily/services/trackbacks/123193.html</trackback:ping><description><![CDATA[<p>/******************************************<br>*Author:Java619<br>*Time:20070515<br>*******************************************/</p>
<p>首先下载相关文件</p>
<p>FCKeditor_2.3.2.zip</p>
<p><a href="http://prdownloads.sourceforge.net/fckeditor/FCKeditor_2.3.2.zip?download"><u><font color=#0000ff>http://prdownloads.sourceforge.net/fckeditor/FCKeditor_2.3.2.zip?download</font></u></a></p>
<p>FCKeditor-2.3&nbsp;(for&nbsp;java)</p>
<p><a href="http://nchc.dl.sourceforge.net/sourceforge/fckeditor/FCKeditor-2.3.zip"><u><font color=#0000ff>http://nchc.dl.sourceforge.net/sourceforge/fckeditor/FCKeditor-2.3.zip</font></u></a></p>
<p>1&gt;&nbsp;下载完成后，在J2EE应用中，建立项目:<font color=#0000ff>fcktest</font>，在应用根目录中建立文件夹<span style="COLOR: rgb(0,0,255)">FCKeditor，</span>将FCKeditor中的<span style="COLOR: rgb(0,0,255)">editor目录及&nbsp;fckconfig.js、fckeditor.js、fckstyles.xml、fcktemplates.xml</span>文件拷贝到FCKeditor目录下。</p>
<p>2&gt;&nbsp;然后我们将<span style="COLOR: rgb(0,0,255)">FCKeditor-2.3\web\WEB-INF\lib中</span>的两个jar包拷贝到<span style="COLOR: rgb(0,0,255)">\fcktest\WEB-INF\lib</span>目录下，将&nbsp;<span style="COLOR: rgb(0,0,255)">FCKeditor-2.3\src下的FCKeditor.tld</span>拷贝到<span style="COLOR: rgb(0,0,255)">\fcktest\WEB-INF</span>下。<br><br>3&gt;&nbsp;编辑\fcktest\WEB-INF\web.xml文件，将FCKeditor-2.3\web\WEB-INF\web.xml里的内容合并到项目的\WEB-INF\目录下的web.xml文件中，修改<span style="COLOR: rgb(0,0,255)">&lt;servlet-mapping&gt;</span>里的内容为：<br></p>
<div class="codeArea xml">
<div style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<font color=#0000ff>&lt;</font><font color=#a52a2a>servlet</font>-<font color=#a52a2a>mapping</font><font color=#0000ff>&gt;</font><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color=#0000ff>&lt;</font><font color=#a52a2a>servlet</font>-<font color=#a52a2a>name</font><font color=#0000ff>&gt;</font><font color=#a52a2a>Connector</font><font color=#0000ff>&lt;/</font><font color=#a52a2a>servlet</font>-<font color=#a52a2a>name</font><font color=#0000ff>&gt;</font><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color=#0000ff>&lt;</font><font color=#a52a2a>url</font>-<font color=#a52a2a>pattern</font><font color=#0000ff>&gt;/</font><font color=#a52a2a>FCKeditor</font><font color=#0000ff>/</font><font color=#a52a2a>editor</font><font color=#0000ff>/</font><font color=#a52a2a>filemanager</font><font color=#0000ff>/</font><font color=#a52a2a>browser</font><font color=#0000ff>/</font><font color=#a52a2a>default</font><font color=#0000ff>/</font><font color=#a52a2a>connectors</font><font color=#0000ff>/</font><font color=#a52a2a>jsp</font><font color=#0000ff>/</font><font color=#a52a2a>connector</font><font color=#0000ff>&lt;/</font><font color=#a52a2a>url</font>-<font color=#a52a2a>pattern</font><font color=#0000ff>&gt;</font><br>&nbsp;&nbsp;&nbsp;&nbsp;<font color=#0000ff>&lt;/</font><font color=#a52a2a>servlet</font>-<font color=#a52a2a>mapping</font><font color=#0000ff>&gt;</font><br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<font color=#0000ff>&lt;</font><font color=#a52a2a>servlet</font>-<font color=#a52a2a>mapping</font><font color=#0000ff>&gt;</font><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color=#0000ff>&lt;</font><font color=#a52a2a>servlet</font>-<font color=#a52a2a>name</font><font color=#0000ff>&gt;</font><font color=#a52a2a>SimpleUploader</font><font color=#0000ff>&lt;/</font><font color=#a52a2a>servlet</font>-<font color=#a52a2a>name</font><font color=#0000ff>&gt;</font><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color=#0000ff>&lt;</font><font color=#a52a2a>url</font>-<font color=#a52a2a>pattern</font><font color=#0000ff>&gt;/</font><font color=#a52a2a>FCKeditor</font><font color=#0000ff>/</font><font color=#a52a2a>editor</font><font color=#0000ff>/</font><font color=#a52a2a>filemanager</font><font color=#0000ff>/</font><font color=#a52a2a>upload</font><font color=#0000ff>/</font><font color=#a52a2a>simpleuploader</font><font color=#0000ff>&lt;/</font><font color=#a52a2a>url</font>-<font color=#a52a2a>pattern</font><font color=#0000ff>&gt;</font><br>&nbsp;&nbsp;&nbsp;&nbsp;<font color=#0000ff>&lt;/</font><font color=#a52a2a>servlet</font>-<font color=#a52a2a>mapping</font><font color=#0000ff>&gt;</font><br></div>
</div>
<p>&nbsp;4&gt;&nbsp;&nbsp;修改合并后的web.xml文件，将名为SimpleUploader的Servlet的enabled参数值改为true，以允许上传功能，Connector&nbsp;Servlet的baseDir参数值用于设置上传文件存放的位置。<br>&nbsp;&nbsp;&nbsp;&nbsp;并添加下面内容</p>
<div class="codeArea xml">
<div style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<font color=#0000ff>&lt;</font><font color=#a52a2a>taglib</font><font color=#0000ff>&gt;</font><br>&nbsp;&nbsp;&nbsp;&nbsp;<font color=#0000ff>&lt;</font><font color=#a52a2a>taglib</font>-<font color=#a52a2a>uri</font><font color=#0000ff>&gt;/</font><font color=#a52a2a>FCKeditor</font><font color=#0000ff>&lt;/</font><font color=#a52a2a>taglib</font>-<font color=#a52a2a>uri</font><font color=#0000ff>&gt;</font><br>&nbsp;&nbsp;&nbsp;&nbsp;<font color=#0000ff>&lt;</font><font color=#a52a2a>taglib</font>-<font color=#a52a2a>location</font><font color=#0000ff>&gt;/</font><font color=#a52a2a>WEB</font>-<font color=#a52a2a>INF</font><font color=#0000ff>/</font><font color=#a52a2a>FCKeditor</font>.<font color=#a52a2a>tld</font><font color=#0000ff>&lt;/</font><font color=#a52a2a>taglib</font>-<font color=#a52a2a>location</font><font color=#0000ff>&gt;</font><br>&nbsp;&nbsp;&nbsp;&nbsp;<font color=#0000ff>&lt;/</font><font color=#a52a2a>taglib</font><font color=#0000ff>&gt;</font></div>
</div>
<p>5&gt;修改页面fckconfig.js</p>
<p><span style="COLOR: rgb(255,0,0)">将FCKConfig.LinkBrowserURL等的值替换成以下内容：</span><br><font color=#000000>FCKConfig.LinkBrowserURL = FCKConfig.BasePath + 'filemanager/browser/default/browser.html?Connector=connectors/jsp/connector' ;</font></p>
<p>FCKConfig.ImageBrowserURL = FCKConfig.BasePath + 'filemanager/browser/default/browser.html?Type=Image&amp;Connector=connectors/jsp/connector';</p>
<p>FCKConfig.FlashBrowserURL = FCKConfig.BasePath + 'filemanager/browser/default/browser.html?Type=Flash&amp;Connector=connectors/jsp/connector' ;</p>
<p>FCKConfig.LinkUploadURL = FCKConfig.BasePath + 'filemanager/upload/simpleuploader?Type=File';</p>
<p>FCKConfig.ImageUploadURL = FCKConfig.BasePath + 'filemanager/upload/simpleuploader?Type=Image';</p>
<p>FCKConfig.FlashUploadURL = FCKConfig.BasePath +'filemanager/upload/simpleuploader?Type=Flash';</p>
<p>6&gt;&nbsp;添加页面&nbsp;index.jsp</p>
<p>&lt;<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#37;&#64;&#112;&#97;&#103;&#101;"><u><font color=#0000ff>%@page</font></u></a> contentType="text/html;charset=UTF-8"%&gt;<br>&lt;<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#37;&#64;&#112;&#97;&#103;&#101;"><u><font color=#0000ff>%@page</font></u></a> pageEncoding="UTF-8"%&gt;<br>&lt;html&gt;<br>&nbsp;&nbsp;&nbsp; &lt;head&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;title&gt;JSP Page&lt;/title&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;script type="text/javascript" src="FCKeditor/fckeditor.js"&gt;&lt;/script&gt; <br>&nbsp;&nbsp;&nbsp; &lt;/head&gt;<br>&nbsp;&nbsp;&nbsp; &lt;body&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;form action="sampleposteddata.jsp" method="post" target="_blank"&gt; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;table border="0" width="700"&gt;&lt;tr&gt;&lt;td&gt; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;textarea id="content" name="content" style="WIDTH: 100%; HEIGHT: 400px"&gt;&lt;/textarea&gt; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;script type="text/javascript"&gt; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var oFCKeditor = new FCKeditor('content') ; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oFCKeditor.BasePath = "FCKeditor/" ; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oFCKeditor.Height = 400;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oFCKeditor.ReplaceTextarea(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/script&gt; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;input type="submit" value="Submit"&gt; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/form&gt; <br>&nbsp;&nbsp;&nbsp; &lt;/body&gt;<br>&lt;/html&gt;</p>
<p><font color=#000000>7&gt;&nbsp;&nbsp;添加接受页面sampleposteddata.jsp</font></p>
<p><font color=#0000ff><font color=#000000>&lt;%@ page contentType="text/html;charset=UTF-8"%&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;%@ page language="java" import="java.util.*" %&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;%<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Enumeration params = request.getParameterNames();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" &gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;html&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;head&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;title&gt;FCKeditor - Samples - Posted Data&lt;/title&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;meta name="robots" content="noindex, nofollow"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;link href="../sample.css" rel="stylesheet" type="text/css" /&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/head&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;body&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;h1&gt;FCKeditor中国的中 - Samples - Posted Data&lt;/h1&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; This page lists all data posted by the form.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;hr&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;table width="100%" border="1" cellspacing="0" bordercolor="#999999"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tr style="FONT-WEIGHT: bold; COLOR: #dddddd; BACKGROUND-COLOR: #999999"&gt;<br></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color=#000000>&nbsp; &lt;td noWrap&gt;Field Name&amp;nbsp;&amp;nbsp;&lt;/td&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;Value&lt;/td&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/tr&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;%<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String parameter = null ;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while( params.hasMoreElements() )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parameter = (String) params.nextElement() ;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tr&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td valign="top" nowrap&gt;&lt;b&gt;&lt;%=parameter%&gt;&lt;/b&gt;&lt;/td&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td width="100%"&gt;&lt;%=request.getParameter(parameter)%&gt;&lt;/td&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/tr&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;%<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/table&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/body&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/html&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br></font></p>
<img src ="http://www.blogjava.net/WshmAndLily/aggbug/123193.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/WshmAndLily/" target="_blank">semovy</a> 2007-06-10 15:44 <a href="http://www.blogjava.net/WshmAndLily/articles/123193.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用Ajax实现无限级目录树（.NET)[转载]</title><link>http://www.blogjava.net/WshmAndLily/articles/114273.html</link><dc:creator>semovy</dc:creator><author>semovy</author><pubDate>Sat, 28 Apr 2007 02:51:00 GMT</pubDate><guid>http://www.blogjava.net/WshmAndLily/articles/114273.html</guid><wfw:comment>http://www.blogjava.net/WshmAndLily/comments/114273.html</wfw:comment><comments>http://www.blogjava.net/WshmAndLily/articles/114273.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/WshmAndLily/comments/commentRss/114273.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/WshmAndLily/services/trackbacks/114273.html</trackback:ping><description><![CDATA[<strong>比较符合自己的习惯，整个代码不难。是利用CSS实现的。<br>家里的电脑上不能安装MS SQL，索性就用MySQL。顺路学习了一下使用MySql的Function。<br>希望使用的XDJM能在这里留个言。谢谢</strong>
<p><strong>数据库：</strong><br>ysql&gt; create table category(<br>&nbsp;&nbsp;&nbsp; -&gt; categoryid int,<br>&nbsp;&nbsp;&nbsp; -&gt; categoryname varchar(20),<br>&nbsp;&nbsp;&nbsp; -&gt; FatherId int);<br>&nbsp;&nbsp;&nbsp; <br>DELIMITER //&nbsp;&nbsp;&nbsp; <br>mysql&gt; create function IsLeaf(cat_id int)<br>&nbsp;&nbsp;&nbsp; -&gt; returns int<br>&nbsp;&nbsp;&nbsp; -&gt; begin<br>&nbsp;&nbsp;&nbsp; -&gt; declare count int;<br>&nbsp;&nbsp;&nbsp; -&gt; select count(*) into count from category where fatherid=cat_id;<br>&nbsp;&nbsp;&nbsp; -&gt; if count = 0 then<br>&nbsp;&nbsp;&nbsp; -&gt; return 1<br>&nbsp;&nbsp;&nbsp; -&gt; ;<br>&nbsp;&nbsp;&nbsp; -&gt; end if;<br>&nbsp;&nbsp;&nbsp; -&gt; return 0;<br>&nbsp;&nbsp;&nbsp; -&gt; end;<br>&nbsp;&nbsp;&nbsp; -&gt; //<br>&nbsp;&nbsp;&nbsp; <br>mysql&gt; insert into category values(1,'My Documen<br>&nbsp;&nbsp;&nbsp; -&gt; ;<br>Query OK, 1 row affected (0.08 sec)</p>
<p>mysql&gt; insert into category values(2,'ASP.NET',1<br>&nbsp;&nbsp;&nbsp; -&gt; ;<br>Query OK, 1 row affected (0.02 sec)</p>
<p>mysql&gt; insert into category values(3,'JAVA',1)<br>&nbsp;&nbsp;&nbsp; -&gt; ;<br>Query OK, 1 row affected (0.03 sec)</p>
<p>mysql&gt; insert into category values(4,'C#',1)<br>&nbsp;&nbsp;&nbsp; -&gt; ;<br>Query OK, 1 row affected (0.04 sec)</p>
<p>mysql&gt; insert into category values(5,'HTML',1)<br>&nbsp;&nbsp;&nbsp; -&gt; ;<br>Query OK, 1 row affected (0.01 sec)</p>
<p>mysql&gt; insert into category values(6,'Oracle',1)<br>&nbsp;&nbsp;&nbsp; -&gt; ;<br>Query OK, 1 row affected (0.02 sec)</p>
<p>mysql&gt; insert into category values(7,'Line',1)<br>&nbsp;&nbsp;&nbsp; -&gt; ;<br>Query OK, 1 row affected (0.02 sec)</p>
<p><strong>Tree.aspx<br></strong>&lt;%@ Page Language="C#" AutoEventWireup="true" CodeFile="Tree.aspx.cs" Inherits="Tree" %&gt;</p>
<p>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "<a href="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><u><font color=#0000ff>http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd</font></u></a>"&gt;</p>
<p>&lt;html xmlns="<a href="http://www.w3.org/1999/xhtml"><u><font color=#0000ff>http://www.w3.org/1999/xhtml</font></u></a>" &gt;<br>&nbsp;&lt;head&gt;<br>&nbsp;&nbsp;&lt;title&gt;Tree&lt;/title&gt;<br>&nbsp;&nbsp;&lt;meta name="CODE_LANGUAGE" content="C#" /&gt;<br>&nbsp;&nbsp;&lt;meta name="vs_defaultClientScript" content="JavaScript" /&gt;<br>&nbsp;&nbsp;&lt;meta name="vs_targetSchema" content="<a href="http://schemas.microsoft.com/intellisense/ie5"><u><font color=#0000ff>http://schemas.microsoft.com/intellisense/ie5</font></u></a>" /&gt;<br>&nbsp;&nbsp;&lt;link type="text/css" href="css/tree.css" rel="stylesheet" /&gt;<br>&nbsp;&lt;/head&gt;<br>&nbsp;&lt;body&gt;<br>&nbsp;&nbsp;&lt;form id="Form1" method="post" runat="server"&gt;<br>&nbsp;&nbsp;&nbsp;&lt;div class="TreeMenu" id="CategoryTree"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;h4&gt;基于Ajax的动态树型菜单&lt;/h4&gt;<br>&nbsp;&nbsp;&nbsp;&lt;/div&gt;<br>&nbsp;&nbsp;&nbsp;&lt;div id="docContent" style=""&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;div id="title" align="center"&gt;&lt;/div&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;div id="author" align="right"&gt;&lt;/div&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;div id="writetime" align="right"&gt;&lt;/div&gt;<br>&nbsp;&nbsp;&nbsp;&lt;/div&gt;<br>&nbsp;&nbsp;&nbsp;&lt;div id="docList" style=""&gt;<br>&nbsp;&nbsp;&nbsp;&lt;/div&gt;<br>&nbsp;&nbsp;&nbsp;&lt;script language="jscript" type="text/jscript"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;function ExpandSubCategory(iCategoryID)<br>&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;var li_father = document.getElementById("li_" + iCategoryID);<br>&nbsp;&nbsp;&nbsp;&nbsp;if (li_father.getElementsByTagName("li").length &gt; 0) //分类已下载<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ChangeStatus(iCategoryID);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;displayDocList(iCategoryID);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;li_father.className = "Opened";<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;switchNote(iCategoryID, true);<br>&nbsp;&nbsp;&nbsp;&nbsp;Tree.GetSubCategory(iCategoryID, GetSubCategory_callback);&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;function GetSubCategory_callback(response)<br>&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;var dt = response.value.Tables[0];<br>&nbsp;&nbsp;&nbsp;&nbsp;if (dt.Rows.length &gt; 0)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var iCategoryID = dt.Rows[0].FatherID;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;var li_father = document.getElementById("li_" + iCategoryID);<br>&nbsp;&nbsp;&nbsp;&nbsp;var ul = document.createElement("ul");<br>&nbsp;&nbsp;&nbsp;&nbsp;for (var i = 0;i &lt; dt.Rows.length;i++)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (dt.Rows[i].IsChild == 1) //叶子节点<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var li = document.createElement("li");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;li.className = "Child";<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;li.id = "li_" + dt.Rows[i].CategoryID;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var img = document.createElement("img");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;img.id = dt.Rows[i].CategoryID;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;img.className = "s";<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;img.src = "css/s.gif";<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var a = document.createElement("a");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.href = "javascript:OpenDocument('" + dt.Rows[i].CategoryID + "');";<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.innerHTML = dt.Rows[i].CategoryName;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var li = document.createElement("li");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;li.className = "Closed";<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;li.id = "li_" + dt.Rows[i].CategoryID;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var img = document.createElement("img");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;img.id = dt.Rows[i].CategoryID;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;img.className = "s";<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;img.src = "css/s.gif";<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;img.onclick = function () {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ExpandSubCategory(this.id);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;img.alt = "展开/折叠";<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var a = document.createElement("a");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.href = "javascript:ExpandSubCategory(" +<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dt.Rows[i].CategoryID + ");";<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.innerHTML = dt.Rows[i].CategoryName;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;li.appendChild(img);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;li.appendChild(a);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ul.appendChild(li);&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;li_father.appendChild(ul);<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;displayDocList(iCategoryID);<br>&nbsp;&nbsp;&nbsp;&nbsp;switchNote(iCategoryID, false);<br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;function OpenDocument(iCategoryID)<br>&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;var div_docContent = document.getElementById("docContent");<br>&nbsp;&nbsp;&nbsp;&nbsp;var div_docList = document.getElementById("docList");<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;div_docContent.style.display = "";<br>&nbsp;&nbsp;&nbsp;&nbsp;div_docList.style.display = "none";<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;Tree.GetDocInfo(iCategoryID, GetDocInfo_callback);<br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;function GetDocInfo_callback(response)<br>&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;function ChangeStatus(iCategoryID)<br>&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;var li_father = document.getElementById("li_" + iCategoryID);<br>&nbsp;&nbsp;&nbsp;&nbsp;if (li_father.className == "Closed")<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;li_father.className = "Opened";<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;else<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;li_father.className = "Closed";<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;function switchNote(iCategoryID, show)<br>&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;var li_father = document.getElementById("li_" + iCategoryID);<br>&nbsp;&nbsp;&nbsp;&nbsp;if (show)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var ul = document.createElement("ul");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ul.id = "ul_note_" + iCategoryID;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var note = document.createElement("li");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;note.className = "Child";<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var img = document.createElement("img");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;img.className = "s";<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;img.src = "css/s.gif";<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var a = document.createElement("a");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.href = "javascript:void(0);";<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.innerHTML = "请稍候...";<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;note.appendChild(img);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;note.appendChild(a);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ul.appendChild(note);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;li_father.appendChild(ul);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;else<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var ul = document.getElementById("ul_note_" + iCategoryID);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (ul)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;li_father.removeChild(ul);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;function displayDocList(iCategoryID)<br>&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;var div_docContent = document.getElementById("docContent");<br>&nbsp;&nbsp;&nbsp;&nbsp;var div_docList = document.getElementById("docList");<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;div_docContent.style.display = "none";<br>&nbsp;&nbsp;&nbsp;&nbsp;div_docList.style.display = "";<br>&nbsp;&nbsp;&nbsp;&nbsp;div_docList.style.padding = 20;<br>&nbsp;&nbsp;&nbsp;&nbsp;while (div_docList.childNodes.length &gt; 0)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;div_docList.removeChild(div_docList.childNodes[0]);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;var dt = Tree.GetDocInfoInCategory(iCategoryID).value.Tables[0];<br>&nbsp;&nbsp;&nbsp;&nbsp;if (dt)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (var i = 0;i &lt; dt.Rows.length;i++)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var a = document.createElement("a");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.href = "javascript:OpenDocument(" + dt.Rows[i].CategoryID + ");";<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.innerHTML = "&lt;font color=#1122aa size=2&gt;" + dt.Rows[i].CategoryName + "&lt;/font&gt;";<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var li = document.createElement("li");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;li.appendChild(a);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var div = document.createElement("div");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;div.appendChild(li);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;div_docList.appendChild(div);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;// 加载根节点<br>&nbsp;&nbsp;&nbsp;var tree = document.getElementById("CategoryTree");<br>&nbsp;&nbsp;&nbsp;var root = document.createElement("li");<br>&nbsp;&nbsp;&nbsp;root.id = "li_0";<br>&nbsp;&nbsp;&nbsp;tree.appendChild(root);<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;// 加载页面时显示第一级分类<br>&nbsp;&nbsp;&nbsp;ExpandSubCategory(0);<br>&nbsp;&nbsp;&nbsp;&lt;/script&gt;</p>
<p>&nbsp;&nbsp;&lt;/form&gt;<br>&nbsp;&lt;/body&gt;</p>
<p>&lt;/html&gt;</p>
<p><strong>Tree.aspx.cs<br></strong>using System;<br>using System.Data;<br>using System.Configuration;<br>using System.Collections;<br>using System.Web;<br>using System.Web.Security;<br>using System.Web.UI;<br>using System.Web.UI.WebControls;<br>using System.Web.UI.WebControls.WebParts;<br>using System.Web.UI.HtmlControls;<br>using AjaxPro;<br>using MySql.Data.MySqlClient;<br>public partial class Tree : System.Web.UI.Page<br>{<br>&nbsp;&nbsp;&nbsp; protected void Page_Load(object sender, EventArgs e)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Utility.RegisterTypeForAjax(typeof(Tree));<br>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; private Random rand = new Random();</p>
<p>&nbsp;&nbsp;&nbsp; [AjaxMethod()]<br>&nbsp;&nbsp;&nbsp; public DataSet GetSubCategory(int iCategoryID)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DataSet ds = new DataSet();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MySqlConnection conn = new MySqlConnection("server=127.0.0.1;uid=root;pwd=111111;database=test");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MySqlCommand cmd = conn.CreateCommand();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmd.CommandText = string.Format("SELECT CategoryID, CategoryName, FatherID, IsLeaf(CategoryID) as IsChild FROM Category WHERE FatherID = {0}", iCategoryID);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MySqlDataAdapter da = new MySqlDataAdapter(cmd);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; da.Fill(ds);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch (MySqlException)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; finally<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.Close();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.Threading.Thread.Sleep(500 + rand.Next(1000));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine(ds.Tables[0].Rows.Count.ToString());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ds;<br>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; [AjaxMethod()]<br>&nbsp;&nbsp;&nbsp; public DataSet GetDocInfo(int iCategoryID)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DataSet ds = new DataSet();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ds;<br>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; [AjaxMethod()]<br>&nbsp;&nbsp;&nbsp; public DataSet GetDocInfoInCategory(int iCategoryID)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DataSet ds = new DataSet();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MySqlConnection conn = new MySqlConnection("server=127.0.0.1;uid=root;pwd=111111;database=test");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MySqlCommand cmd = conn.CreateCommand();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmd.CommandText = string.Format(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "SELECT CategoryID, CategoryName, FatherID FROM Category WHERE FatherID = {0} AND IsLeaf(CategoryID) = 1", iCategoryID);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MySqlDataAdapter da = new MySqlDataAdapter(cmd);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; da.Fill(ds);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch (MySqlException)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; finally<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.Close();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ds;<br>&nbsp;&nbsp;&nbsp; }<br>}<br></p>
<p><strong>CSS<br></strong>a<br>{<br>&nbsp;text-decoration:none;<br>}<br>a,a:visited<br>{<br>&nbsp;color:#000;<br>&nbsp;background:inherit;<br>}<br>body<br>{<br>&nbsp;margin:0;<br>&nbsp;padding:20px;<br>&nbsp;font:12px tahoma,宋体,sans-serif;<br>}<br>dt<br>{<br>&nbsp;font-size:22px;<br>&nbsp;font-weight:bold;<br>&nbsp;margin:0 0 0 15px;<br>}<br>dd<br>{<br>&nbsp;margin:0 0 0 15px;<br>}<br>h4<br>{<br>&nbsp;margin:0;<br>&nbsp;padding:0;<br>&nbsp;font-size:18px;<br>&nbsp;text-align:center;<br>}<br>p<br>{<br>&nbsp;margin:0;<br>&nbsp;padding:0 0 0 18px;<br>}<br>p a,p a:visited<br>{<br>&nbsp;color:#00f;<br>&nbsp;background:inherit;<br>}</p>
<p>.TreeMenu img.s<br>{<br>&nbsp;cursor:hand;<br>&nbsp;vertical-align:middle;<br>}<br>.TreeMenu ul<br>{<br>&nbsp;padding:0;<br>}<br>.TreeMenu li<br>{<br>&nbsp;list-style:none;<br>&nbsp;padding:0;<br>}<br>.Closed ul<br>{<br>&nbsp;display:none;<br>}<br>.Child img.s<br>{<br>&nbsp;background:none;<br>&nbsp;cursor:default;<br>}</p>
<p>#CategoryTree ul<br>{<br>&nbsp;margin:0 0 0 17px;<br>}<br>#CategoryTree img.s<br>{<br>&nbsp;width:34px;<br>&nbsp;height:18px;<br>}<br>#CategoryTree .Opened img.s<br>{<br>&nbsp;background:url(skin3/opened.gif) no-repeat 0 1px;<br>}<br>#CategoryTree .Closed img.s<br>{<br>&nbsp;background:url(skin3/closed.gif) no-repeat 0 1px;<br>}<br>#CategoryTree .Child img.s<br>{<br>&nbsp;background:url(skin3/child.gif) no-repeat 13px 2px;<br>}</p>
<p>#CategoryTree<br>{<br>&nbsp;float:left;<br>&nbsp;width:249px;<br>&nbsp;border:1px solid #99BEEF;<br>&nbsp;background:#D2E4FC;<br>&nbsp;color:inherit;<br>&nbsp;margin:3px;<br>&nbsp;padding:3px;<br>}<br></p>
<img src ="http://www.blogjava.net/WshmAndLily/aggbug/114273.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/WshmAndLily/" target="_blank">semovy</a> 2007-04-28 10:51 <a href="http://www.blogjava.net/WshmAndLily/articles/114273.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用CronTrigger的CronExpression</title><link>http://www.blogjava.net/WshmAndLily/articles/104548.html</link><dc:creator>semovy</dc:creator><author>semovy</author><pubDate>Sun, 18 Mar 2007 03:52:00 GMT</pubDate><guid>http://www.blogjava.net/WshmAndLily/articles/104548.html</guid><wfw:comment>http://www.blogjava.net/WshmAndLily/comments/104548.html</wfw:comment><comments>http://www.blogjava.net/WshmAndLily/articles/104548.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/WshmAndLily/comments/commentRss/104548.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/WshmAndLily/services/trackbacks/104548.html</trackback:ping><description><![CDATA[
		<div>Cron 表达式 
<p>Cron-Expressions are used to configure instances of CronTrigger. Cron-Expressions are strings that are actually made up of six sub-expressions, that describe individual details of the schedule. These sub-expression are separated with white-space, and represent: <br /><font color="#ff0000">Cron 表达式被用来注册CronTrigger实例的。Cron表达式是字符串，它由六个子表达式组成，它描述了不同的调度细节。这些子表达式被白色表达式隔开，表现：</font></p><p><font color="#ff0000">Seconds  秒<br />Minutes  分<br />Hours    时<br />Day-of-Month  日<br />Month         月<br />Day-of-Week   周</font></p><p></p><p><font color="#ff0000">例如：  "0 30 10-13 ? * WED,FRI"</font></p><p><font color="#ff0000">对应      秒分  小时   日月  周</font></p><p><font color="#ff0000">表示每周的10：30，11：30，12：30，13：30</font></p><p></p><p>An example of a complete cron-expression is the string "0 0 12 ? * WED" - which means "every Wednesday at 12:00 pm".<br />一个完整的Cron 表达式例子是字符串“0 0 12 ? * WEB” 意味着每周三上午12：00。 
</p><p>Individual sub-expressions can contain ranges and/or lists. For example, the day of week field in the previous (which reads "WED") example could be replaces with "MON-FRI", "MON, WED, FRI", or even "MON-WED,SAT".<br />单独的子表达式可以包含平行的 和/或。例如，在上一个例子一周的一天字段（它读作"WED"）可以被“MON-FRI”,"MON,WED,FRI"，或者甚至"MON-WED,SAT"替换掉。 
</p><p>Wild-cards (the '*' character) can be used to say "every" possible value of this field. Therefore the '*' character in the "Month" field of the previous example simply means "every month". A '*' in the Day-Of-Week field would obviously mean "every day of the week".<br />统配符（"*"字符）可以被用来作为这个字段的"每一个"可能值。所以,在上一个例子月字段中的"*"字符表示每个月。 一个"*"在周天将明显意味着周的每一天。 
</p><p>All of the fields have a set of valid values that can be specified. These values should be fairly obvious - such as the numbers 0 to 59 for seconds and minutes, and the values 0 to 23 for hours. Day-of-Month can be any value 0-31, but you need to be careful about how many days are in a given month! Months can be specified as values between 0 and 11, or by using the strings JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC. Days-of-Week can be specified as vaules between 1 and 7 (1 = Sunday) or by using the strings SUN, MON, TUE, WED, THU, FRI and SAT.<br />所有字段都用一个合法限定的值。这些值应该是明显的，例如0到59数字为秒和分的限定，0到23为小时。月的某天可以是0-31的，或者你需要消息给个月有多少天！月份可以被限定在0到11，或者，使用英文字符串缩写。一个礼拜的一天可以被限定作为1到7（1=Sunnday）或者使用英文字符串。 
</p><p><br />The '/' character can be used to specify increments to values. For example, if you put '0/15' in the Minutes field, it means 'every 15 minutes, starting at minute zero'. If you used '3/20' in the Minutes field, it would mean 'every 20 minutes during the hour, starting at minute three' - or in other words it is the same as specifying '3,23,43' in the Minutes field.<br />"/"字符可以内用来限定值的增加。例如，如果你将'0/15'放到分钟字段，它意味着"每15分钟，开始于0分钟"。如果你使用"3/20"在分钟字段中，你将意味着"一个小时内每20分钟，开始于3分钟"---  或者换言之，它和在分钟字段"3,23,43"限定是一样的。 
</p><p><br />The '?' character is allowed for the day-of-month and day-of-week fields. It is used to specify "no specific value". This is useful when you need to specify something in one of the two fields, but not the other. See the examples below (and CronTrigger JavaDOC) for clarification. 
</p><p>"?"字符是允许为月的某一天或者周的某一天字段的。它被用来限定"没有限定值"。这是有用的，当你需要限定一些事情在一个或两个字段中，但不是这里的。 
</p><p>The 'L' character is allowed for the day-of-month and day-of-week fields. This character is short-hand for "last", but it has different meaning in each of the two fields. For example, the value "L" in the day-of-month field means "the last day of the month" - day 31 for January, day 28 for February on non-leap years. If used in the day-of-week field by itself, it simply means "7" or "SAT". But if used in the day-of-week field after another value, it means "the last xxx day of the month" - for example "6L" or "FRIL" both mean "the last friday of the month". When using the 'L' option, it is important not to specify lists, or ranges of values, as you'll get confusing results. 
</p><p>"L"字符是允许用来月某天和周某天字段。这个字符是一个"last"的缩写，但是它有不同的意义在两个字段的其中之一。例如，这个值"L"在月字段的某一天意味着" 这个月的最后一天"，31或者28等等。 
</p><p>Here are a few more examples of expressions and their meanings - you can find even more in the JavaDOC for CronTrigger 
</p><p>CronTrigger Example 1 - an expression to create a trigger that simply fires every 5 minutes 
</p><p>  "0 0/5 * * * ?" 
</p><p>CronTrigger Example 2 - an expression to create a trigger that fires every 5 minutes, at 10 seconds after the minute (i.e. 10:00:10 am, 10:05:10 am, etc.). 
</p><p>  "10 0/5 * * * ?" 
</p><p>CronTrigger Example 3 - an expression to create a trigger that fires at 10:30, 11:30, 12:30, and 13:30, on every Wednesday and Friday. 
</p><p>  "0 30 10-13 ? * WED,FRI" 
</p><p>CronTrigger Example 4 - an expression to create a trigger that fires every half hour between the hours of 8 am and 10 am on the 5th and 20th of every month. Note that the trigger will NOT fire at 10:00 am, just at 8:00, 8:30, 9:00 and 9:30 
</p><p>  "0 0/30 8-9 5,20 * ?" 
</p><p>Note that some scheduling requirements are too complicated to express with a single trigger - such as "every 5 minutes between 9:00 am and 10:00 am, and every 20 minutes between 1:00 pm and 10:00 pm". The solution in this scenario is to simply create two triggers, and register both of them to run the same job.</p></div>
<img src ="http://www.blogjava.net/WshmAndLily/aggbug/104548.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/WshmAndLily/" target="_blank">semovy</a> 2007-03-18 11:52 <a href="http://www.blogjava.net/WshmAndLily/articles/104548.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>J2EE网站经验共享</title><link>http://www.blogjava.net/WshmAndLily/articles/103252.html</link><dc:creator>semovy</dc:creator><author>semovy</author><pubDate>Mon, 12 Mar 2007 03:35:00 GMT</pubDate><guid>http://www.blogjava.net/WshmAndLily/articles/103252.html</guid><wfw:comment>http://www.blogjava.net/WshmAndLily/comments/103252.html</wfw:comment><comments>http://www.blogjava.net/WshmAndLily/articles/103252.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/WshmAndLily/comments/commentRss/103252.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/WshmAndLily/services/trackbacks/103252.html</trackback:ping><description><![CDATA[
		<span class="tpc_content">网站包括 商家博客，个人博客，论坛，新闻等<br /><br />设计采用了MVC模式，具体调用的时候采用了命令模式<br />数据操作层Model中，例如;BlockDAO,TopicDAO,ResponseDAO,UserDAO等。<br />里面封装了一个对象所有的数据操作<br /><br />视图/传输层 View 例如BlockDTO,TopicDTO等，主要是对象的属性<br />jsp用它来显示，dao用它作为DTO<br /><br /><br />最后就是控制层 Controll 控制层的类都继承了Service接口<br />里面有一个方法<br />execute(ServletContext context, HttpServletRequest request,<br />HttpServletResponse response) {<br />}<br />，因为使用命令模式，后面会说明<br />例如 ManageBlock, ManageTopic等<br />主要是接收请求然后调用DAO,把结果返回给jsp<br /><br /><br />调用的时候，我采用的是命令模式<br />一个所有请求的总入口Servlet被影射到controll.do;他获取Service的类名，然后<br />实例化这个类，调用对应的方法<br />例如 ../controll.do?Service=ManageBlock&amp;action=save<br /><br /><pre>String Name = request.getParameter(<font color="#00bb00">"Service"</font><font color="black">);
  <b>if</b> (Name == <b>null</b>||Name.equals(</font><font color="#00bb00">""</font><font color="black">)){
    ErrorView error=<b>new</b> ErrorView(</font><font color="#00bb00">"系统获取Service错误。"</font><font color="black">);
    request.setAttribute(</font><font color="#00bb00">"error"</font><font color="black">,error);
    request.getRequestDispatcher(Constant.ErrorPage).forward(request,response);
  }
 String  serviceName = </font><font color="#00bb00">"aill.bbs.controll."</font><font color="black"> + Name;
<b>try</b> {
    Class serviceClass = Class.forName(serviceName);
    Service service = (Service) serviceClass.newInstance();  
      <b>boolean</b> isSuc = service.execute(<b>this</b>.getServletContext(), request,
                                      response);
      }<b>catch</b>(Exception e){}
</font></pre><br /><br />下面说说安全架构：<br />网站采用J2EE的身份认证系统，通过对不同路径的权限限制来做到不用角色具有不同操作捐献<br />例如:bbs/user/* 下主要是普通用户的操作权限<br />想新建帖子的时候，请求地址是 bbs/user/insertTopic.jsp<br /><br />bbs/blockAdmin/*主要是板块管理员的权限<br />bbs/bbsAdmin/* 下是论坛管理员的权限<br />bbs/sysAdmin/* 下主要是系统管理员的权限<br /><br />最后再说说缓存，<br />缓存的内容主要是数据源，所有板块分类，所有板块的信息[因为这些内容不多，而且使用<br />比较频繁]；还缓存了最新的N个帖子，和点击率最高的N个帖子；<br />另外还缓存了N[差不多是每个板块前5页的]个帖子点击数<br /><br />因为缓存主要有两类，一个是只读，一种是读写。数据源就属于只读的，点击数就属于读写的<br /><br />我设计了两个缓存接口，一个CacheRObject,一个CacheRWObject<br />CacheRObject里有个init()和 get(key)方法，<br />init()当然是初始化或者更新缓存的时候用 get方法就是获取被缓存的对象<br />CacheRWObject里有init(),save()和get(key)方法<br />这里多出来的save()就是把缓存里的内容更新到sql数据库中<br /><br />具体要缓存什么东西，只要写一个类继承CacheRObject,或者CacheRWObject<br /><br />例如 <br /><pre><b>public</b><b>class</b> BlockKindCache implements CacheRWObject{
        HashMap cache=<b>new</b> HashMap();
        <b>int</b> size；<font color="#0000aa"><i>//还有其他一些属性，</i></font><font color="black">
        init(){调用dao获取初始化的内容}
        save(){</font><font color="#0000aa"><i>//保存}</i></font><font color="black">
        get(key){</font><font color="#0000aa"><i>//获取}</i></font><font color="black">
       }
</font></pre><br />缓存的属性设置都是些在cache.xml配置文件中，包括缓存大小，要更新那些缓存对象<br />更新的间隔等等<br />服务器启动的时候，获取这些设置，初始化缓存；<br />同时服务器关闭的时候把所有CacheRWObject类型缓存中的内容保存到数据库<br /><br />---其实做这个网站前我从来没做过什么大的java项目，在jdon中也只是一个潜水者，通过这个网站真的学了很多东西，在这里要特别感谢bang大哥和其他各位jdon的兄弟，<br /><br />说实在的这个网站还有很多自己不满意的地方，希望大家一起交流一起进步<br /><br />哦，网站地址：www.cityxiu.com 大家可以去看看<br /><br />还有bang大哥，我把咱们jdon的logo放到我们论坛的下面了，算是做点贡献吧<br /></span>
		<p>
		</p>
		<div id="vgad2">
				<br />
				<br />
				<br />
				<br />///<font style="BACKGROUND-COLOR: #ffffff"><strong>老大回复<br /><br /></strong><span class="tpc_content">客气。整体设计把握了良好架构和优异性能两个点，作为经验不多的初学者实属难能可贵。<br /><br />如果你希望在现在架构上有所提高，下面提供几点建议：<br /><br />1.表现层的controller是通过class.forName来加载业务Service的，一般业务Service都比较大，在并发很大情况下，new Service尚且觉得耗时，所以这里是否需要优化一下？使用资源池pool来预先生成这些大的Service。当然，小型的代码少的service现在这样就可以了。<br /><br />2.安全架构使用了J2EE的容器验证，但是ACL除了URL资源、还有组件方法的ACL，提供了组件方法的ACL，基本杜绝了安全漏洞，否则，多个Jsp调用同一个组件方法，不同级别权限设置的Jsp资源必然导致这个组件方法访问权限的漏洞。<br /><br /><br />3.对你缓存分成读和写比较感兴趣，特别是缓存写专门做了一个接口，说明你充分认识到缓存重要性，缓存作为数据库一种临时替代，起到减少数据库连接池的占用等，象这个帖子中询问数据库连接池设置问题，当我们觉得数据库连接池设置再大都不能解决问题时，我们是需要象你这样考虑缓存了，原帖：<br /><a href="http://www.jdon.com/jive/thread.jsp?forum=46&amp;thread=27083">http://www.jdon.com/jive/thread.jsp?forum=46&amp;thread=27083</a><br /><br />但是使用缓存写需要考虑因素很多，比如两个用户同时写，如何解决资源争夺，如何解决死锁等问题，这些都要求写缓存质量相当高，所以一般在访问大情况下发生这样问题，我们还是依赖数据库强大的ACID事务机制来解决冲突；或者使用支持事务的缓存如JBossTreeCache等。<br /><br />一般应用下，读缓存就可以了，关键要做好读缓存的更新问题，特别是模型类的嵌套情况下，一个AModel嵌套BModel，那么如何保证AModel中的BModel就是读缓存中的那个BModel，也就是两者同一，这样，万一BModel更新时，只要更新缓存中BModel即可，否则就麻烦了，这些都是非常复杂的域模型缓存问题，这些在JiveJdon3中有些解决，当然还有待提高。<br /><br />我一直认为：缓存属于业务逻辑编写，因为数据库操作也属于业务逻辑部分，为什么不把等同于数据库的缓存也作为业务逻辑对待呢？正是缓存属于业务逻辑组件，所以，处理缓存是不能完全使用框架替代的，除非使用EJB，但是使用EJB不了解其缓存机制，也会走上使用误区，最后唾弃EJB，这是一些所谓高人经常范的毛病。<br /></span></font></div>
<img src ="http://www.blogjava.net/WshmAndLily/aggbug/103252.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/WshmAndLily/" target="_blank">semovy</a> 2007-03-12 11:35 <a href="http://www.blogjava.net/WshmAndLily/articles/103252.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JspSmart之upload组件源码及使用</title><link>http://www.blogjava.net/WshmAndLily/articles/88346.html</link><dc:creator>semovy</dc:creator><author>semovy</author><pubDate>Sun, 17 Dec 2006 08:25:00 GMT</pubDate><guid>http://www.blogjava.net/WshmAndLily/articles/88346.html</guid><wfw:comment>http://www.blogjava.net/WshmAndLily/comments/88346.html</wfw:comment><comments>http://www.blogjava.net/WshmAndLily/articles/88346.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/WshmAndLily/comments/commentRss/88346.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/WshmAndLily/services/trackbacks/88346.html</trackback:ping><description><![CDATA[
		<span id="ArticleContent1_ArticleContent1_lblContent">JspSmart之upload组件源码主要包括了5个java文件 
<p>File.java</p><span class="Code"><p>import java.io.ByteArrayInputStream;<br />import java.io.FileOutputStream;<br />import java.io.IOException;<br />import java.math.BigInteger;<br />import java.sql.ResultSet;<br />import java.sql.SQLException;<br />import javax.servlet.ServletException;</p><p>// Referenced classes of package com.jspsmart.upload:<br />// SmartUploadException, SmartUpload</p><p>public class File<br />{</p><p>private SmartUpload m_parent;<br />private int m_startData;<br />private int m_endData;<br />private int m_size;<br />private String m_fieldname;<br />private String m_filename;<br />private String m_fileExt;<br />private String m_filePathName;<br />private String m_contentType;<br />private String m_contentDisp;<br />private String m_typeMime;<br />private String m_subTypeMime;<br />private String m_contentString;<br />private boolean m_isMissing;<br />public static final int SAVEAS_AUTO = 0;<br />public static final int SAVEAS_VIRTUAL = 1;<br />public static final int SAVEAS_PHYSICAL = 2;</p><p>File()<br />{<br />m_startData = 0;<br />m_endData = 0;<br />m_size = 0;<br />m_fieldname = new String();<br />m_filename = new String();<br />m_fileExt = new String();<br />m_filePathName = new String();<br />m_contentType = new String();<br />m_contentDisp = new String();<br />m_typeMime = new String();<br />m_subTypeMime = new String();<br />m_contentString = new String();<br />m_isMissing = true;<br />}</p><p>public void saveAs(String s)<br />throws IOException, SmartUploadException<br />{<br />saveAs(s, 0);<br />}</p><p>public void saveAs(String s, int i)<br />throws IOException, SmartUploadException<br />{<br />String s1 = new String();<br />s1 = m_parent.getPhysicalPath(s, i);<br />if(s1 == null)<br />throw new IllegalArgumentException("There is no specified destination file (1140).");<br />try<br />{<br />java.io.File file = new java.io.File(s1);<br />FileOutputStream fileoutputstream = new FileOutputStream(file);<br />fileoutputstream.write(m_parent.m_binArray, m_startData, m_size);<br />fileoutputstream.close();<br />}<br />catch(IOException ioexception)<br />{<br />throw new SmartUploadException("File can't be saved (1120).");<br />}<br />}</p><p>public void fileToField(ResultSet resultset, String s)<br />throws ServletException, IOException, SmartUploadException, SQLException<br />{<br />long l = 0L;<br />int i = 0x10000;<br />int j = 0;<br />int k = m_startData;<br />if(resultset == null)<br />throw new IllegalArgumentException("The RecordSet cannot be null (1145).");<br />if(s == null)<br />throw new IllegalArgumentException("The columnName cannot be null (1150).");<br />if(s.length() == 0)<br />throw new IllegalArgumentException("The columnName cannot be empty (1155).");<br />l = BigInteger.valueOf(m_size).divide(BigInteger.valueOf(i)).longValue();<br />j = BigInteger.valueOf(m_size).mod(BigInteger.valueOf(i)).intValue();<br />try<br />{<br />for(int i1 = 1; (long)i1 &lt; l; i1++)<br />{<br />resultset.updateBinaryStream(s, new ByteArrayInputStream(m_parent.m_binArray, k, i), i);<br />k = k != 0 ? k : 1;<br />k = i1 * i + m_startData;<br />}</p><p>if(j &gt; 0)<br />resultset.updateBinaryStream(s, new ByteArrayInputStream(m_parent.m_binArray, k, j), j);<br />}<br />catch(SQLException sqlexception)<br />{<br />byte abyte0[] = new byte[m_size];<br />System.arraycopy(m_parent.m_binArray, m_startData, abyte0, 0, m_size);<br />resultset.updateBytes(s, abyte0);<br />}<br />catch(Exception exception)<br />{<br />throw new SmartUploadException("Unable to save file in the DataBase (1130).");<br />}<br />}</p><p>public boolean isMissing()<br />{<br />return m_isMissing;<br />}</p><p>public String getFieldName()<br />{<br />return m_fieldname;<br />}</p><p>public String getFileName()<br />{<br />return m_filename;<br />}</p><p>public String getFilePathName()<br />{<br />return m_filePathName;<br />}</p><p>public String getFileExt()<br />{<br />return m_fileExt;<br />}</p><p>public String getContentType()<br />{<br />return m_contentType;<br />}</p><p>public String getContentDisp()<br />{<br />return m_contentDisp;<br />}</p><p>public String getContentString()<br />{<br />String s = new String(m_parent.m_binArray, m_startData, m_size);<br />return s;<br />}</p><p>public String getTypeMIME()<br />throws IOException<br />{<br />return m_typeMime;<br />}</p><p>public String getSubTypeMIME()<br />{<br />return m_subTypeMime;<br />}</p><p>public int getSize()<br />{<br />return m_size;<br />}</p><p>protected int getStartData()<br />{<br />return m_startData;<br />}</p><p>protected int getEndData()<br />{<br />return m_endData;<br />}</p><p>protected void setParent(SmartUpload smartupload)<br />{<br />m_parent = smartupload;<br />}</p><p>protected void setStartData(int i)<br />{<br />m_startData = i;<br />}</p><p>protected void setEndData(int i)<br />{<br />m_endData = i;<br />}</p><p>protected void setSize(int i)<br />{<br />m_size = i;<br />}</p><p>protected void setIsMissing(boolean flag)<br />{<br />m_isMissing = flag;<br />}</p><p>protected void setFieldName(String s)<br />{<br />m_fieldname = s;<br />}</p><p>protected void setFileName(String s)<br />{<br />m_filename = s;<br />}</p><p>protected void setFilePathName(String s)<br />{<br />m_filePathName = s;<br />}</p><p>protected void setFileExt(String s)<br />{<br />m_fileExt = s;<br />}</p><p>protected void setContentType(String s)<br />{<br />m_contentType = s;<br />}</p><p>protected void setContentDisp(String s)<br />{<br />m_contentDisp = s;<br />}</p><p>protected void setTypeMIME(String s)<br />{<br />m_typeMime = s;<br />}</p><p>protected void setSubTypeMIME(String s)<br />{<br />m_subTypeMime = s;<br />}</p><p>public byte getBinaryData(int i)<br />{<br />if(m_startData + i &gt; m_endData)<br />throw new ArrayIndexOutOfBoundsException("Index Out of range (1115).");<br />if(m_startData + i &lt;= m_endData)<br />return m_parent.m_binArray[m_startData + i];<br />else<br />return 0;<br />}<br />}</p></span><p><br />Files.java</p><span class="Code"><p>import java.io.IOException;<br />import java.util.*;</p><p>// Referenced classes of package com.jspsmart.upload:<br />// File, SmartUpload</p><p>public class Files<br />{</p><p>private SmartUpload m_parent;<br />private Hashtable m_files;<br />private int m_counter;</p><p>Files()<br />{<br />m_files = new Hashtable();<br />m_counter = 0;<br />}</p><p>protected void addFile(File file)<br />{<br />if(file == null)<br />{<br />throw new IllegalArgumentException("newFile cannot be null.");<br />} else<br />{<br />m_files.put(new Integer(m_counter), file);<br />m_counter++;<br />return;<br />}<br />}</p><p>public File getFile(int i)<br />{<br />if(i &lt; 0)<br />throw new IllegalArgumentException("File's index cannot be a negative value (1210).");<br />File file = (File)m_files.get(new Integer(i));<br />if(file == null)<br />throw new IllegalArgumentException("Files' name is invalid or does not exist (1205).");<br />else<br />return file;<br />}</p><p>public int getCount()<br />{<br />return m_counter;<br />}</p><p>public long getSize()<br />throws IOException<br />{<br />long l = 0L;<br />for(int i = 0; i &lt; m_counter; i++)<br />l += getFile(i).getSize();</p><p>return l;<br />}</p><p>public Collection getCollection()<br />{<br />return m_files.values();<br />}</p><p>public Enumeration getEnumeration()<br />{<br />return m_files.elements();<br />}<br />}</p></span><p><br />Request.java</p><span class="Code"><p>import java.util.Enumeration;<br />import java.util.Hashtable;</p><p>public class Request<br />{</p><p>private Hashtable m_parameters;<br />private int m_counter;</p><p>Request()<br />{<br />m_parameters = new Hashtable();<br />m_counter = 0;<br />}</p><p>protected void putParameter(String s, String s1)<br />{<br />if(s == null)<br />throw new IllegalArgumentException("The name of an element cannot be null.");<br />if(m_parameters.containsKey(s))<br />{<br />Hashtable hashtable = (Hashtable)m_parameters.get(s);<br />hashtable.put(new Integer(hashtable.size()), s1);<br />} else<br />{<br />Hashtable hashtable1 = new Hashtable();<br />hashtable1.put(new Integer(0), s1);<br />m_parameters.put(s, hashtable1);<br />m_counter++;<br />}<br />}</p><p>public String getParameter(String s)<br />{<br />if(s == null)<br />throw new IllegalArgumentException("Form's name is invalid or does not exist (1305).");<br />Hashtable hashtable = (Hashtable)m_parameters.get(s);<br />if(hashtable == null)<br />return null;<br />else<br />return (String)hashtable.get(new Integer(0));<br />}</p><p>public Enumeration getParameterNames()<br />{<br />return m_parameters.keys();<br />}</p><p>public String[] getParameterValues(String s)<br />{<br />if(s == null)<br />throw new IllegalArgumentException("Form's name is invalid or does not exist (1305).");<br />Hashtable hashtable = (Hashtable)m_parameters.get(s);<br />if(hashtable == null)<br />return null;<br />String as[] = new String[hashtable.size()];<br />for(int i = 0; i &lt; hashtable.size(); i++)<br />as[i] = (String)hashtable.get(new Integer(i));</p><p>return as;<br />}<br />}</p></span><p><br />SmartUploadException .java</p><span class="Code"><p>public class SmartUploadException extends Exception<br />{</p><p>SmartUploadException(String s)<br />{<br />super(s);<br />}<br />}</p></span><p><br />SmartUpload.java</p><span class="Code"><p>import java.io.*;<br />import java.sql.ResultSet;<br />import java.sql.SQLException;<br />import java.util.Vector;<br />import javax.servlet.*;<br />import javax.servlet.http.*;<br />import javax.servlet.jsp.JspWriter;<br />import javax.servlet.jsp.PageContext;</p><p>// Referenced classes of package com.jspsmart.upload:<br />// Files, Request, SmartUploadException, File</p><p>public class SmartUpload<br />{</p><p>protected byte m_binArray[];<br />protected HttpServletRequest m_request;<br />protected HttpServletResponse m_response;<br />protected ServletContext m_application;<br />private int m_totalBytes;<br />private int m_currentIndex;<br />private int m_startData;<br />private int m_endData;<br />private String m_boundary;<br />private long m_totalMaxFileSize;<br />private long m_maxFileSize;<br />private Vector m_deniedFilesList;<br />private Vector m_allowedFilesList;<br />private boolean m_denyPhysicalPath;<br />private boolean m_forcePhysicalPath;<br />private String m_contentDisposition;<br />public static final int SAVE_AUTO = 0;<br />public static final int SAVE_VIRTUAL = 1;<br />public static final int SAVE_PHYSICAL = 2;<br />private Files m_files;<br />private Request m_formRequest;</p><p>public SmartUpload()<br />{<br />m_totalBytes = 0;<br />m_currentIndex = 0;<br />m_startData = 0;<br />m_endData = 0;<br />m_boundary = new String();<br />m_totalMaxFileSize = 0L;<br />m_maxFileSize = 0L;<br />m_deniedFilesList = new Vector();<br />m_allowedFilesList = new Vector();<br />m_denyPhysicalPath = false;<br />m_forcePhysicalPath = false;<br />m_contentDisposition = new String();<br />m_files = new Files();<br />m_formRequest = new Request();<br />}</p><p>public final void init(ServletConfig servletconfig)<br />throws ServletException<br />{<br />m_application = servletconfig.getServletContext();<br />}</p><p>public void service(HttpServletRequest httpservletrequest, HttpServletResponse httpservletresponse)<br />throws ServletException, IOException<br />{<br />m_request = httpservletrequest;<br />m_response = httpservletresponse;<br />}</p><p>public final void initialize(ServletConfig servletconfig, HttpServletRequest httpservletrequest, HttpServletResponse httpservletresponse)<br />throws ServletException<br />{<br />m_application = servletconfig.getServletContext();<br />m_request = httpservletrequest;<br />m_response = httpservletresponse;<br />}</p><p>public final void initialize(PageContext pagecontext)<br />throws ServletException<br />{<br />m_application = pagecontext.getServletContext();<br />m_request = (HttpServletRequest)pagecontext.getRequest();<br />m_response = (HttpServletResponse)pagecontext.getResponse();<br />}</p><p>public final void initialize(ServletContext servletcontext, HttpSession httpsession, HttpServletRequest httpservletrequest, HttpServletResponse httpservletresponse, JspWriter jspwriter)<br />throws ServletException<br />{<br />m_application = servletcontext;<br />m_request = httpservletrequest;<br />m_response = httpservletresponse;<br />}</p><p>public void upload()<br />throws ServletException, IOException, SmartUploadException<br />{<br />int i = 0;<br />boolean flag = false;<br />long l = 0L;<br />boolean flag1 = false;<br />String s = new String();<br />String s2 = new String();<br />String s4 = new String();<br />String s5 = new String();<br />String s6 = new String();<br />String s7 = new String();<br />String s8 = new String();<br />String s9 = new String();<br />String s10 = new String();<br />boolean flag2 = false;<br />m_totalBytes = m_request.getContentLength();<br />m_binArray = new byte[m_totalBytes];<br />int j;<br />for(; i &lt; m_totalBytes; i += j)<br />try<br />{<br />m_request.getInputStream();<br />j = m_request.getInputStream().read(m_binArray, i, m_totalBytes - i);<br />}<br />catch(Exception exception)<br />{<br />throw new SmartUploadException("Unable to upload.");<br />}</p><p>for(; !flag1 &amp;&amp; m_currentIndex &lt; m_totalBytes; m_currentIndex++)<br />if(m_binArray[m_currentIndex] == 13)<br />flag1 = true;<br />else<br />m_boundary = m_boundary + (char)m_binArray[m_currentIndex];</p><p>if(m_currentIndex == 1)<br />return;<br />for(m_currentIndex++; m_currentIndex &lt; m_totalBytes; m_currentIndex = m_currentIndex + 2)<br />{<br />String s1 = getDataHeader();<br />m_currentIndex = m_currentIndex + 2;<br />boolean flag3 = s1.indexOf("filename") &gt; 0;<br />String s3 = getDataFieldValue(s1, "name");<br />if(flag3)<br />{<br />s6 = getDataFieldValue(s1, "filename");<br />s4 = getFileName(s6);<br />s5 = getFileExt(s4);<br />s7 = getContentType(s1);<br />s8 = getContentDisp(s1);<br />s9 = getTypeMIME(s7);<br />s10 = getSubTypeMIME(s7);<br />}<br />getDataSection();<br />if(flag3 &amp;&amp; s4.length() &gt; 0)<br />{<br />if(m_deniedFilesList.contains(s5))<br />throw new SecurityException("The extension of the file is denied to be uploaded (1015).");<br />if(!m_allowedFilesList.isEmpty() &amp;&amp; !m_allowedFilesList.contains(s5))<br />throw new SecurityException("The extension of the file is not allowed to be uploaded (1010).");<br />if(m_maxFileSize &gt; 0L &amp;&amp; (long)((m_endData - m_startData) + 1) &gt; m_maxFileSize)<br />throw new SecurityException("Size exceeded for this file : " + s4 + " (1105).");<br />l += (m_endData - m_startData) + 1;<br />if(m_totalMaxFileSize &gt; 0L &amp;&amp; l &gt; m_totalMaxFileSize)<br />throw new SecurityException("Total File Size exceeded (1110).");<br />}<br />if(flag3)<br />{<br />com.facet.jspsmart.upload.File file = new com.facet.jspsmart.upload.File();<br />file.setParent(this);<br />file.setFieldName(s3);<br />file.setFileName(s4);<br />file.setFileExt(s5);<br />file.setFilePathName(s6);<br />file.setIsMissing(s6.length() == 0);<br />file.setContentType(s7);<br />file.setContentDisp(s8);<br />file.setTypeMIME(s9);<br />file.setSubTypeMIME(s10);<br />if(s7.indexOf("application/x-macbinary") &gt; 0)<br />m_startData = m_startData + 128;<br />file.setSize((m_endData - m_startData) + 1);<br />file.setStartData(m_startData);<br />file.setEndData(m_endData);<br />m_files.addFile(file);<br />} else<br />{<br />String s11 = new String(m_binArray, m_startData, (m_endData - m_startData) + 1);<br />m_formRequest.putParameter(s3, s11);<br />}<br />if((char)m_binArray[m_currentIndex + 1] == '-')<br />break;<br />}</p><p>}</p><p>public int save(String s)<br />throws ServletException, IOException, SmartUploadException<br />{<br />return save(s, 0);<br />}</p><p>public int save(String s, int i)<br />throws ServletException, IOException, SmartUploadException<br />{<br />int j = 0;<br />if(s == null)<br />s = m_application.getRealPath("/");<br />if(s.indexOf("/") != -1)<br />{<br />if(s.charAt(s.length() - 1) != '/')<br />s = s + "/";<br />} else<br />if(s.charAt(s.length() - 1) != '\\')<br />s = s + "\\";<br />for(int k = 0; k &lt; m_files.getCount(); k++)<br />if(!m_files.getFile(k).isMissing())<br />{<br />m_files.getFile(k).saveAs(s + m_files.getFile(k).getFileName(), i);<br />j++;<br />}</p><p>return j;<br />}</p><p>public int getSize()<br />{<br />return m_totalBytes;<br />}</p><p>public byte getBinaryData(int i)<br />{<br />byte byte0;<br />try<br />{<br />byte0 = m_binArray[i];<br />}<br />catch(Exception exception)<br />{<br />throw new ArrayIndexOutOfBoundsException("Index out of range (1005).");<br />}<br />return byte0;<br />}</p><p>public Files getFiles()<br />{<br />return m_files;<br />}</p><p>public Request getRequest()<br />{<br />return m_formRequest;<br />}</p><p>public void downloadFile(String s)<br />throws ServletException, IOException, SmartUploadException<br />{<br />downloadFile(s, null, null);<br />}</p><p>public void downloadFile(String s, String s1)<br />throws ServletException, IOException, SmartUploadException, SmartUploadException<br />{<br />downloadFile(s, s1, null);<br />}</p><p>public void downloadFile(String s, String s1, String s2)<br />throws ServletException, IOException, SmartUploadException<br />{<br />downloadFile(s, s1, s2, 65000);<br />}</p><p>public void downloadFile(String s, String s1, String s2, int i)<br />throws ServletException, IOException, SmartUploadException<br />{<br />if(s == null)<br />throw new IllegalArgumentException("File '" + s + "' not found (1040).");<br />if(s.equals(""))<br />throw new IllegalArgumentException("File '" + s + "' not found (1040).");<br />if(!isVirtual(s) &amp;&amp; m_denyPhysicalPath)<br />throw new SecurityException("Physical path is denied (1035).");<br />if(isVirtual(s))<br />s = m_application.getRealPath(s);<br />java.io.File file = new java.io.File(s);<br />FileInputStream fileinputstream = new FileInputStream(file);<br />long l = file.length();<br />boolean flag = false;<br />int k = 0;<br />byte abyte0[] = new byte[i];<br />if(s1 == null)<br />m_response.setContentType("application/x-msdownload");<br />else<br />if(s1.length() == 0)<br />m_response.setContentType("application/x-msdownload");<br />else<br />m_response.setContentType(s1);<br />m_response.setContentLength((int)l);<br />m_contentDisposition = m_contentDisposition != null ? m_contentDisposition : "attachment;";<br />if(s2 == null)<br />m_response.setHeader("Content-Disposition", m_contentDisposition + " filename=" + getFileName(s));<br />else<br />if(s2.length() == 0)<br />m_response.setHeader("Content-Disposition", m_contentDisposition);<br />else<br />m_response.setHeader("Content-Disposition", m_contentDisposition + " filename=" + s2);<br />while((long)k &lt; l)<br />{<br />int j = fileinputstream.read(abyte0, 0, i);<br />k += j;<br />m_response.getOutputStream().write(abyte0, 0, j);<br />}<br />fileinputstream.close();<br />}</p><p>public void downloadField(ResultSet resultset, String s, String s1, String s2)<br />throws ServletException, IOException, SQLException<br />{<br />if(resultset == null)<br />throw new IllegalArgumentException("The RecordSet cannot be null (1045).");<br />if(s == null)<br />throw new IllegalArgumentException("The columnName cannot be null (1050).");<br />if(s.length() == 0)<br />throw new IllegalArgumentException("The columnName cannot be empty (1055).");<br />byte abyte0[] = resultset.getBytes(s);<br />if(s1 == null)<br />m_response.setContentType("application/x-msdownload");<br />else<br />if(s1.length() == 0)<br />m_response.setContentType("application/x-msdownload");<br />else<br />m_response.setContentType(s1);<br />m_response.setContentLength(abyte0.length);<br />if(s2 == null)<br />m_response.setHeader("Content-Disposition", "attachment;");<br />else<br />if(s2.length() == 0)<br />m_response.setHeader("Content-Disposition", "attachment;");<br />else<br />m_response.setHeader("Content-Disposition", "attachment; filename=" + s2);<br />m_response.getOutputStream().write(abyte0, 0, abyte0.length);<br />}</p><p>public void fieldToFile(ResultSet resultset, String s, String s1)<br />throws ServletException, IOException, SmartUploadException, SQLException<br />{<br />try<br />{<br />if(m_application.getRealPath(s1) != null)<br />s1 = m_application.getRealPath(s1);<br />InputStream inputstream = resultset.getBinaryStream(s);<br />FileOutputStream fileoutputstream = new FileOutputStream(s1);<br />int i;<br />while((i = inputstream.read()) != -1)<br />fileoutputstream.write(i);<br />fileoutputstream.close();<br />}<br />catch(Exception exception)<br />{<br />throw new SmartUploadException("Unable to save file from the DataBase (1020).");<br />}<br />}</p><p>private String getDataFieldValue(String s, String s1)<br />{<br />String s2 = new String();<br />String s3 = new String();<br />int i = 0;<br />boolean flag = false;<br />boolean flag1 = false;<br />boolean flag2 = false;<br />s2 = s1 + "=" + '"';<br />i = s.indexOf(s2);<br />if(i &gt; 0)<br />{<br />int j = i + s2.length();<br />int k = j;<br />s2 = "\"";<br />int l = s.indexOf(s2, j);<br />if(k &gt; 0 &amp;&amp; l &gt; 0)<br />s3 = s.substring(k, l);<br />}<br />return s3;<br />}</p><p>private String getFileExt(String s)<br />{<br />String s1 = new String();<br />int i = 0;<br />int j = 0;<br />if(s == null)<br />return null;<br />i = s.lastIndexOf(46) + 1;<br />j = s.length();<br />s1 = s.substring(i, j);<br />if(s.lastIndexOf(46) &gt; 0)<br />return s1;<br />else<br />return "";<br />}</p><p>private String getContentType(String s)<br />{<br />String s1 = new String();<br />String s2 = new String();<br />int i = 0;<br />boolean flag = false;<br />s1 = "Content-Type:";<br />i = s.indexOf(s1) + s1.length();<br />if(i != -1)<br />{<br />int j = s.length();<br />s2 = s.substring(i, j);<br />}<br />return s2;<br />}</p><p>private String getTypeMIME(String s)<br />{<br />String s1 = new String();<br />int i = 0;<br />i = s.indexOf("/");<br />if(i != -1)<br />return s.substring(1, i);<br />else<br />return s;<br />}</p><p>private String getSubTypeMIME(String s)<br />{<br />String s1 = new String();<br />int i = 0;<br />boolean flag = false;<br />i = s.indexOf("/") + 1;<br />if(i != -1)<br />{<br />int j = s.length();<br />return s.substring(i, j);<br />} else<br />{<br />return s;<br />}<br />}</p><p>private String getContentDisp(String s)<br />{<br />String s1 = new String();<br />int i = 0;<br />int j = 0;<br />i = s.indexOf(":") + 1;<br />j = s.indexOf(";");<br />s1 = s.substring(i, j);<br />return s1;<br />}</p><p>private void getDataSection()<br />{<br />boolean flag = false;<br />String s = new String();<br />int i = m_currentIndex;<br />int j = 0;<br />int k = m_boundary.length();<br />m_startData = m_currentIndex;<br />m_endData = 0;<br />while(i &lt; m_totalBytes)<br />if(m_binArray[i] == (byte)m_boundary.charAt(j))<br />{<br />if(j == k - 1)<br />{<br />m_endData = ((i - k) + 1) - 3;<br />break;<br />}<br />i++;<br />j++;<br />} else<br />{<br />i++;<br />j = 0;<br />}<br />m_currentIndex = m_endData + k + 3;<br />}</p><p>private String getDataHeader()<br />{<br />int i = m_currentIndex;<br />int j = 0;<br />boolean flag = false;<br />for(boolean flag1 = false; !flag1;)<br />if(m_binArray[m_currentIndex] == 13 &amp;&amp; m_binArray[m_currentIndex + 2] == 13)<br />{<br />flag1 = true;<br />j = m_currentIndex - 1;<br />m_currentIndex = m_currentIndex + 2;<br />} else<br />{<br />m_currentIndex++;<br />}</p><p>String s = new String(m_binArray, i, (j - i) + 1);<br />return s;<br />}</p><p>private String getFileName(String s)<br />{<br />String s1 = new String();<br />String s2 = new String();<br />int i = 0;<br />boolean flag = false;<br />boolean flag1 = false;<br />boolean flag2 = false;<br />i = s.lastIndexOf(47);<br />if(i != -1)<br />return s.substring(i + 1, s.length());<br />i = s.lastIndexOf(92);<br />if(i != -1)<br />return s.substring(i + 1, s.length());<br />else<br />return s;<br />}</p><p>public void setDeniedFilesList(String s)<br />throws ServletException, IOException, SQLException<br />{<br />String s1 = "";<br />if(s != null)<br />{<br />String s2 = "";<br />for(int i = 0; i &lt; s.length(); i++)<br />if(s.charAt(i) == ',')<br />{<br />if(!m_deniedFilesList.contains(s2))<br />m_deniedFilesList.addElement(s2);<br />s2 = "";<br />} else<br />{<br />s2 = s2 + s.charAt(i);<br />}</p><p>if(s2 != "")<br />m_deniedFilesList.addElement(s2);<br />} else<br />{<br />m_deniedFilesList = null;<br />}<br />}</p><p>public void setAllowedFilesList(String s)<br />{<br />String s1 = "";<br />if(s != null)<br />{<br />String s2 = "";<br />for(int i = 0; i &lt; s.length(); i++)<br />if(s.charAt(i) == ',')<br />{<br />if(!m_allowedFilesList.contains(s2))<br />m_allowedFilesList.addElement(s2);<br />s2 = "";<br />} else<br />{<br />s2 = s2 + s.charAt(i);<br />}</p><p>if(s2 != "")<br />m_allowedFilesList.addElement(s2);<br />} else<br />{<br />m_allowedFilesList = null;<br />}<br />}</p><p>public void setDenyPhysicalPath(boolean flag)<br />{<br />m_denyPhysicalPath = flag;<br />}</p><p>public void setForcePhysicalPath(boolean flag)<br />{<br />m_forcePhysicalPath = flag;<br />}</p><p>public void setContentDisposition(String s)<br />{<br />m_contentDisposition = s;<br />}</p><p>public void setTotalMaxFileSize(long l)<br />{<br />m_totalMaxFileSize = l;<br />}</p><p>public void setMaxFileSize(long l)<br />{<br />m_maxFileSize = l;<br />}</p><p>protected String getPhysicalPath(String s, int i)<br />throws IOException<br />{<br />String s1 = new String();<br />String s2 = new String();<br />String s3 = new String();<br />boolean flag = false;<br />s3 = System.getProperty("file.separator");<br />if(s == null)<br />throw new IllegalArgumentException("There is no specified destination file (1140).");<br />if(s.equals(""))<br />throw new IllegalArgumentException("There is no specified destination file (1140).");<br />if(s.lastIndexOf("\\") &gt;= 0)<br />{<br />s1 = s.substring(0, s.lastIndexOf("\\"));<br />s2 = s.substring(s.lastIndexOf("\\") + 1);<br />}<br />if(s.lastIndexOf("/") &gt;= 0)<br />{<br />s1 = s.substring(0, s.lastIndexOf("/"));<br />s2 = s.substring(s.lastIndexOf("/") + 1);<br />}<br />s1 = s1.length() != 0 ? s1 : "/";<br />java.io.File file = new java.io.File(s1);<br />if(file.exists())<br />flag = true;<br />if(i == 0)<br />{<br />if(isVirtual(s1))<br />{<br />s1 = m_application.getRealPath(s1);<br />if(s1.endsWith(s3))<br />s1 = s1 + s2;<br />else<br />s1 = s1 + s3 + s2;<br />return s1;<br />}<br />if(flag)<br />{<br />if(m_denyPhysicalPath)<br />throw new IllegalArgumentException("Physical path is denied (1125).");<br />else<br />return s;<br />} else<br />{<br />throw new IllegalArgumentException("This path does not exist (1135).");<br />}<br />}<br />if(i == 1)<br />{<br />if(isVirtual(s1))<br />{<br />s1 = m_application.getRealPath(s1);<br />if(s1.endsWith(s3))<br />s1 = s1 + s2;<br />else<br />s1 = s1 + s3 + s2;<br />return s1;<br />}<br />if(flag)<br />throw new IllegalArgumentException("The path is not a virtual path.");<br />else<br />throw new IllegalArgumentException("This path does not exist (1135).");<br />}<br />if(i == 2)<br />{<br />if(flag)<br />if(m_denyPhysicalPath)<br />throw new IllegalArgumentException("Physical path is denied (1125).");<br />else<br />return s;<br />if(isVirtual(s1))<br />throw new IllegalArgumentException("The path is not a physical path.");<br />else<br />throw new IllegalArgumentException("This path does not exist (1135).");<br />} else<br />{<br />return null;<br />}<br />}</p><p>public void uploadInFile(String s)<br />throws IOException, SmartUploadException<br />{<br />int i = 0;<br />int j = 0;<br />boolean flag = false;<br />if(s == null)<br />throw new IllegalArgumentException("There is no specified destination file (1025).");<br />if(s.length() == 0)<br />throw new IllegalArgumentException("There is no specified destination file (1025).");<br />if(!isVirtual(s) &amp;&amp; m_denyPhysicalPath)<br />throw new SecurityException("Physical path is denied (1035).");<br />i = m_request.getContentLength();<br />m_binArray = new byte[i];<br />int k;<br />for(; j &lt; i; j += k)<br />try<br />{<br />k = m_request.getInputStream().read(m_binArray, j, i - j);<br />}<br />catch(Exception exception)<br />{<br />throw new SmartUploadException("Unable to upload.");<br />}</p><p>if(isVirtual(s))<br />s = m_application.getRealPath(s);<br />try<br />{<br />java.io.File file = new java.io.File(s);<br />FileOutputStream fileoutputstream = new FileOutputStream(file);<br />fileoutputstream.write(m_binArray);<br />fileoutputstream.close();<br />}<br />catch(Exception exception1)<br />{<br />throw new SmartUploadException("The Form cannot be saved in the specified file (1030).");<br />}<br />}</p><p>private boolean isVirtual(String s)<br />{<br />if(m_application.getRealPath(s) != null)<br />{<br />java.io.File file = new java.io.File(m_application.getRealPath(s));<br />return file.exists();<br />} else<br />{<br />return false;<br />}<br />}<br />}</p></span><p><br />jspsmart的使用</p><p>上传</p><span class="Code"><p>// 新建一个SmartUpload对象<br />SmartUpload su = new SmartUpload(); <br />// 上传初始化<br />su.initialize(pageContext); <br />// 限制每个上传文件的最大长度。<br />su.setMaxFileSize(10000); <br />// 限制总上传<a class="vLink1" id="vad_1" onmouseover="if(typeof(showTitle)!='undefined'){this.title='';window.clearTimeout(hideTO);showTitle(event, this, 1,'');}" title="" style="FONT-SIZE: 1em" onclick="" onmouseout="if(typeof(showTitle)!='undefined'){mouseIsOverLayer = false; mouseOverWhileLoad = false; hideTO = window.setTimeout('checkIfMouseOverLayer()',500);}" href="http://action.vogate.com/click/click.php?ads_id=868&amp;site_id=6235007045036250&amp;click=1&amp;url=http%3A//www.vogate.com&amp;v=0&amp;k=%u6570%u636E&amp;s=http%3A//www.newasp.net/tech/java/15704.html&amp;rn=610039" target="_blank">数据</a>的长度。<br />su.setTotalMaxFileSize(20000); <br />// 设定允许上传的文件（通过扩展名限制）,仅允许doc,txt文件。<br />su.setAllowedFilesList("doc,txt");<br />// 设定禁止上传的文件（通过扩展名限制）,禁止上传带有exe,bat,<br />//jsp,htm,html扩展名的文件和没有扩展名的文件。<br />su.setDeniedFilesList("exe,bat,jsp,htm,html,,");<br />// 上传文件<br />su.upload();<br />// 将上传文件全部<a class="vLink1" id="vad_4" onmouseover="if(typeof(showTitle)!='undefined'){this.title='';window.clearTimeout(hideTO);showTitle(event, this, 4,'');}" title="c183 @Vogate.com" style="FONT-SIZE: 1em" onclick="" onmouseout="if(typeof(showTitle)!='undefined'){mouseIsOverLayer = false; mouseOverWhileLoad = false; hideTO = window.setTimeout('checkIfMouseOverLayer()',500);}" href="http://action.vogate.com/click/click.php?ads_id=603&amp;site_id=6235007045036250&amp;click=1&amp;url=http%3A//rover.ebay.com/rover/1/4080-41052-15934-0/1%3Faid%3D65978%3Btext%3B104%26mpre%3Dhttp%253A//search.ebay.com.cn/search/search.dll%253Fsofocus%253Dbs%2526sbrftog%253D1%2526from%253DR10%2526satitle%253D%2525E4%2525BF%25259D%2525E5%2525AD%252598%2526sacat%253D-1%252526catref%25253DC6%2526floc%253D1%2526sargn%253D-1%252526saslc%25253D0&amp;v=0&amp;k=%u4FDD%u5B58&amp;s=http%3A//www.newasp.net/tech/java/15704.html&amp;rn=927031" target="_blank">保存</a>到指定目录<br />int count = su.save("/upload");</p></span><p><br />下载</p><span class="Code"><p>// 新建一个SmartUpload对象<br />SmartUpload su = new SmartUpload();<br />// 初始化<br />su.initialize(pageContext);<br />// 设定contentDisposition为null以禁止<a class="vLink1" id="vad_2" onmouseover="if(typeof(showTitle)!='undefined'){this.title='';window.clearTimeout(hideTO);showTitle(event, this, 2,'');}" title="VOGATE 广告4 @Vogate.com" style="FONT-SIZE: 1em" onclick="" onmouseout="if(typeof(showTitle)!='undefined'){mouseIsOverLayer = false; mouseOverWhileLoad = false; hideTO = window.setTimeout('checkIfMouseOverLayer()',500);}" href="http://action.vogate.com/click/click.php?ads_id=869&amp;site_id=6235007045036250&amp;click=1&amp;url=http%3A//www.vogate.com&amp;v=0&amp;k=%u6D4F%u89C8&amp;s=http%3A//www.newasp.net/tech/java/15704.html&amp;rn=188130" target="_blank">浏览</a>器自动打开文件，<br />//保证点击链接后是下载文件。若不设定，则下载的文件扩展名为<br />//doc时，浏览器将自动用word打开它。扩展名为pdf时，<br />//浏览器将用acrobat打开。<br />su.setContentDisposition(null);<br />// 下载文件<br />su.downloadFile("/upload/test.doc");</p></span></span>
<img src ="http://www.blogjava.net/WshmAndLily/aggbug/88346.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/WshmAndLily/" target="_blank">semovy</a> 2006-12-17 16:25 <a href="http://www.blogjava.net/WshmAndLily/articles/88346.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【spring+hibernate学习文档】---配置篇 </title><link>http://www.blogjava.net/WshmAndLily/articles/78956.html</link><dc:creator>semovy</dc:creator><author>semovy</author><pubDate>Fri, 03 Nov 2006 09:36:00 GMT</pubDate><guid>http://www.blogjava.net/WshmAndLily/articles/78956.html</guid><wfw:comment>http://www.blogjava.net/WshmAndLily/comments/78956.html</wfw:comment><comments>http://www.blogjava.net/WshmAndLily/articles/78956.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/WshmAndLily/comments/commentRss/78956.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/WshmAndLily/services/trackbacks/78956.html</trackback:ping><description><![CDATA[
		<p>&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;</p>
		<p>&lt;web-app xmlns="<a href="http://java.sun.com/xml/ns/j2ee">http://java.sun.com/xml/ns/j2ee</a>" xmlns:xsi="<a href="http://www.w3.org/2001/XMLSchema-instance">http://www.w3.org/2001/XMLSchema-instance</a>" xsi:schemaLocation="<a href="http://java.sun.com/xml/ns/j2ee">http://java.sun.com/xml/ns/j2ee</a><a href="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd</a>" version="2.4"&gt;<br /> &lt;display-name&gt;framework&lt;/display-name&gt;</p>
		<p> &lt;description&gt;framework sample application&lt;/description&gt;</p>
		<p> &lt;!--<br />   - Key of the system property that should specify the root directory of this<br />   - web app. Applied by WebAppRootListener or Log4jConfigListener.<br />   --&gt;<br /> &lt;context-param&gt;<br />  &lt;param-name&gt;webAppRootKey&lt;/param-name&gt;<br />  &lt;param-value&gt;framework.root&lt;/param-value&gt;<br /> &lt;/context-param&gt;</p>
		<p> &lt;!--<br />   - Location of the Log4J config file, for initialization and refresh checks.<br />   - Applied by Log4jConfigListener.<br />   --&gt;<br /> &lt;context-param&gt;<br />  &lt;param-name&gt;log4jConfigLocation&lt;/param-name&gt;<br />  &lt;param-value&gt;/WEB-INF/log4j.properties&lt;/param-value&gt;<br /> &lt;/context-param&gt;<br /> <br />        &lt;filter&gt;<br />           &lt;filter-name&gt;Set Character Encoding&lt;/filter-name&gt;<br />           &lt;filter-class&gt;cn.rhui.framework.common.filter.SetCharacterEncodingFilter&lt;/filter-class&gt;<br />           &lt;init-param&gt;<br />               &lt;param-name&gt;encoding&lt;/param-name&gt;<br />               &lt;param-value&gt;GBK&lt;/param-value&gt;<br />           &lt;/init-param&gt;<br />        &lt;/filter&gt;<br />        <br />        &lt;filter-mapping&gt;<br />           &lt;filter-name&gt;Set Character Encoding&lt;/filter-name&gt;<br />           &lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br />        &lt;/filter-mapping&gt;<br />    <br /> <br /> &lt;context-param&gt;<br />  &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;<br />  &lt;param-value&gt;/WEB-INF/applicationContext.xml<br />   /WEB-INF/dataAccessContext-local.xml<br />  &lt;/param-value&gt;   <br /> &lt;/context-param&gt;</p>
		<p> &lt;!--<br />   - Configures Log4J for this web app.<br />   - As this context specifies a context-param "log4jConfigLocation", its file path<br />   - is used to load the Log4J configuration, including periodic refresh checks.<br />   -<br />   - Would fall back to default Log4J initialization (non-refreshing) if no special<br />   - context-params are given.<br />   -<br />   - Exports a "web app root key", i.e. a system property that specifies the root<br />   - directory of this web app, for usage in log file paths.<br />   - This web app specifies "petclinic.root" (see log4j.properties file).<br />   --&gt;<br /> &lt;!-- Leave the listener commented-out if using JBoss --&gt;<br /> <br /> &lt;listener&gt;<br />  &lt;listener-class&gt;org.springframework.web.util.Log4jConfigListener&lt;/listener-class&gt;<br /> &lt;/listener&gt;<br /> <br />        &lt;servlet&gt;<br />  &lt;servlet-name&gt;context&lt;/servlet-name&gt;<br />  &lt;servlet-class&gt;org.springframework.web.context.ContextLoaderServlet&lt;/servlet-class&gt;<br />  &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;<br />        &lt;/servlet&gt;</p>
		<p>
				<br />  &lt;servlet&gt;<br />  &lt;servlet-name&gt;action&lt;/servlet-name&gt;<br />  &lt;servlet-class&gt;org.apache.struts.action.ActionServlet&lt;/servlet-class&gt;<br />  <br />  &lt;init-param&gt;<br />       &lt;param-name&gt;config&lt;/param-name&gt;<br />       &lt;param-value&gt;/WEB-INF/struts-config.xml&lt;/param-value&gt;<br />  &lt;/init-param&gt;<br />  <br />         &lt;init-param&gt;<br />                   &lt;param-name&gt;config/workflow&lt;/param-name&gt;<br />                   &lt;param-value&gt;/WEB-INF/workflow/struts-config.xml&lt;/param-value&gt;<br />         &lt;/init-param&gt; <br />           <br />         &lt;init-param&gt;<br />                   &lt;param-name&gt;config/testflow&lt;/param-name&gt;<br />                   &lt;param-value&gt;/WEB-INF/testflow/struts-config.xml&lt;/param-value&gt;<br />         &lt;/init-param&gt;                  <br />  &lt;load-on-startup&gt;2&lt;/load-on-startup&gt;<br /> &lt;/servlet&gt;</p>
		<p> &lt;!--<br />   - Maps the petclinic dispatcher to *.htm. All handler mappings in<br />   - petclinic-servlet.xml will by default be applied to this subpath.<br />   - If a mapping isn't a /* subpath, the handler mappings are considered<br />   - relative to the web app root.<br />   -<br />   - NOTE: A single dispatcher can be mapped to multiple paths, like any servlet.<br />   --&gt;<br /> &lt;servlet-mapping&gt;<br />  &lt;servlet-name&gt;action&lt;/servlet-name&gt;<br />  &lt;url-pattern&gt;*.do&lt;/url-pattern&gt;<br /> &lt;/servlet-mapping&gt;</p>
		<p> &lt;session-config&gt;<br />  &lt;session-timeout&gt;30&lt;/session-timeout&gt;<br /> &lt;/session-config&gt;</p>
		<p> &lt;welcome-file-list&gt;<br />  &lt;!-- Redirects to "welcome.htm" for dispatcher handling --&gt;<br />  &lt;!--welcome-file&gt;index.jsp&lt;/welcome-file--&gt;<br />  &lt;welcome-file&gt;default.jsp&lt;/welcome-file&gt;<br /> &lt;/welcome-file-list&gt;</p>
		<p> &lt;error-page&gt;<br />  &lt;exception-type&gt;java.lang.Exception&lt;/exception-type&gt;<br />  &lt;!-- Displays a stack trace --&gt;<br />  &lt;location&gt;/WEB-INF/jsp/uncaughtException.jsp&lt;/location&gt;<br /> &lt;/error-page&gt;<br /> &lt;jsp-config&gt;  <br />            &lt;taglib&gt;<br />               &lt;taglib-uri&gt;/WEB-INF/page-tag.tld&lt;/taglib-uri&gt;<br />               &lt;taglib-location&gt;/WEB-INF/tld/page-tag.tld&lt;/taglib-location&gt;<br />            &lt;/taglib&gt;  <br /> <br />    &lt;taglib&gt;<br />               &lt;taglib-uri&gt;core&lt;/taglib-uri&gt;<br />               &lt;taglib-location&gt;/WEB-INF/tld/c.tld&lt;/taglib-location&gt;<br />           &lt;/taglib&gt;<br />    <br />    &lt;taglib&gt;<br />        &lt;taglib-uri&gt;/WEB-INF/tld/struts-bean.tld&lt;/taglib-uri&gt;<br />        &lt;taglib-location&gt;/WEB-INF/tld/struts-bean.tld&lt;/taglib-location&gt;  <br />    &lt;/taglib&gt;<br /> <br />    &lt;taglib&gt;<br />  &lt;taglib-uri&gt;/WEB-INF/tld/struts-html.tld&lt;/taglib-uri&gt;<br />  &lt;taglib-location&gt;/WEB-INF/tld/struts-html.tld&lt;/taglib-location&gt;  <br />    &lt;/taglib&gt;<br /> <br />    &lt;taglib&gt;<br />  &lt;taglib-uri&gt;/WEB-INF/tld/struts-logic.tld&lt;/taglib-uri&gt;<br />  &lt;taglib-location&gt;/WEB-INF/tld/struts-logic.tld&lt;/taglib-location&gt;  <br />    &lt;/taglib&gt;<br />     &lt;taglib&gt;<br />  &lt;taglib-uri&gt;t&lt;/taglib-uri&gt;<br />  &lt;taglib-location&gt;/WEB-INF/tld/t.tld&lt;/taglib-location&gt;  <br />    &lt;/taglib&gt;<br /> &lt;/jsp-config&gt;</p>
		<p> &lt;!--<br />  - Reference to Petclinic database.<br />  - Only needed if not using a local DataSource but a JNDI one instead.<br />  --&gt;<br /> &lt;!--<br /> &lt;resource-ref&gt;<br />  &lt;res-ref-name&gt;jdbc/framework&lt;/res-ref-name&gt;<br />  &lt;res-type&gt;javax.sql.DataSource&lt;/res-type&gt;<br />  &lt;res-auth&gt;Container&lt;/res-auth&gt;<br /> &lt;/resource-ref&gt;<br /> --&gt;</p>
		<p>&lt;/web-app&gt;</p>
		<p>-----------------applicationContext.xml-------------------</p>
		<p>&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />&lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "<a href="http://www.springframework.org/dtd/spring-beans.dtd">http://www.springframework.org/dtd/spring-beans.dtd</a>"&gt;</p>
		<p>&lt;!--<br />  - Application context definition for framework.<br /> --&gt;<br />&lt;beans&gt;</p>
		<p> &lt;!-- ========================= RESOURCE DEFINITIONS ========================= --&gt;<br />  <br /> &lt;!-- Configurer that replaces ${...} placeholders with values from a properties file --&gt;<br /> &lt;!-- (in this case, JDBC-related settings for the dataSource definition below) --&gt;<br /> &lt;bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"&gt;<br />  &lt;property name="location"&gt;&lt;value&gt;/WEB-INF/jdbc.properties&lt;/value&gt;&lt;/property&gt;<br /> &lt;/bean&gt;</p>
		<p>
				<br /> &lt;!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) --&gt;<br /> &lt;bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"&gt;<br />  &lt;property name="sessionFactory"&gt;&lt;ref bean="sessionFactory"/&gt;&lt;/property&gt;<br /> &lt;/bean&gt;</p>
		<p> &lt;!-- Transaction manager that delegates to JTA (for a transactional JNDI DataSource) --&gt;<br /> &lt;!--<br /> &lt;bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/&gt;<br /> --&gt;<br /> &lt;!-- id generator --&gt;<br /> &lt;bean id="idGenerateService" parent="baseTransactionProxyFactoryBean"&gt;<br />  &lt;property name="target"&gt;<br />   &lt;bean class="cn.rhui.framework.idgenerator.service.IdGenerateServiceImpl" autowire="byName"/&gt;<br />  &lt;/property&gt; <br /> &lt;/bean&gt;<br /> &lt;bean id="generate" class="cn.rhui.framework.idgenerator.Generator"&gt;<br />  &lt;property name="idService"&gt;<br />   &lt;ref local="idGenerateService"&gt;&lt;/ref&gt;<br />  &lt;/property&gt;<br />  &lt;property name="path"&gt;&lt;value&gt;${generator.path}&lt;/value&gt;&lt;/property&gt;<br /> &lt;/bean&gt;<br /> &lt;!-- end id generator --&gt;<br /> &lt;!--<br />  - Transactional proxy for Petclinic's central data access object.<br />  -<br />  - Defines specific transaction attributes with "readOnly" markers,<br />  - which is an optimization that is particularly valuable with Hibernate<br />  - (to suppress unnecessary flush attempts for read-only operations).<br />  -<br />  - Note that in a real-life app with multiple transaction proxies,<br />  - you will probably want to use parent and child bean definitions<br />  - as described in the manual, to reduce duplication.<br />    --&gt;<br /> &lt;bean id="baseTransactionProxyFactoryBean" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true"&gt;<br />  &lt;property name="transactionManager"&gt;&lt;ref local="transactionManager"/&gt;&lt;/property&gt;<br />  &lt;property name="transactionAttributes"&gt;<br />   &lt;props&gt;<br />    &lt;prop key="find*"&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;<br />    &lt;prop key="select*"&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;<br />    &lt;prop key="get*"&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;<br />    &lt;prop key="remove*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />    &lt;prop key="save*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />    &lt;prop key="create*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />   &lt;/props&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;</p>
		<p>&lt;/beans&gt;<br /><br />------------dataAccessCotext-local.xml--------</p>
		<p>&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />&lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "<a href="http://www.springframework.org/dtd/spring-beans.dtd">http://www.springframework.org/dtd/spring-beans.dtd</a>"&gt;<br />&lt;beans&gt;</p>
		<p>    &lt;!-- ========================= owners bean ========================= --&gt;<br /> &lt;!-- Local DataSource that works in any environment --&gt;<br /> &lt;!-- Note that DriverManagerDataSource does not pool; it is not intended for production --&gt;<br /> &lt;!-- See JPetStore for an example of using Commons DBCP BasicDataSource as alternative --&gt;<br /> &lt;!-- See Image Database for an example of using C3P0 ComboPooledDataSource as alternative --&gt;<br /> &lt;bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"&gt;<br />  &lt;property name="driverClassName"&gt;&lt;value&gt;${jdbc.driverClassName}&lt;/value&gt;&lt;/property&gt;<br />  &lt;property name="url"&gt;&lt;value&gt;${jdbc.url}&lt;/value&gt;&lt;/property&gt;<br />  &lt;property name="username"&gt;&lt;value&gt;${jdbc.username}&lt;/value&gt;&lt;/property&gt;<br />  &lt;property name="password"&gt;&lt;value&gt;${jdbc.password}&lt;/value&gt;&lt;/property&gt;<br /> &lt;/bean&gt;</p>
		<p> &lt;!-- JNDI DataSource for J2EE environments --&gt;<br /> &lt;!--<br /> &lt;bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"&gt;<br />  &lt;property name="jndiName"&gt;&lt;value&gt;java:comp/env/jdbc/petclinic&lt;/value&gt;&lt;/property&gt;<br /> &lt;/bean&gt;<br /> --&gt;</p>
		<p> &lt;!-- Hibernate SessionFactory --&gt;<br /> &lt;bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"&gt;<br />  &lt;property name="dataSource"&gt;&lt;ref local="dataSource"/&gt;&lt;/property&gt;<br />   &lt;property name="schemaUpdate"&gt;<br />    &lt;value&gt;true&lt;/value&gt;<br />   &lt;/property&gt;<br />  &lt;property name="mappingResources"&gt;<br />   &lt;list&gt;<br />    &lt;value&gt;cn/rhui/framework/test/domain/Owners.hbm.xml&lt;/value&gt;<br />      &lt;value&gt;cn/rhui/framework/idgenerator/vo/SysGenerateId.hbm.xml&lt;/value&gt;</p>
		<p>   &lt;/list&gt;<br />  &lt;/property&gt;<br />  &lt;property name="hibernateProperties"&gt;<br />   &lt;props&gt;<br />          &lt;prop key="hibernate.query.factory_class"&gt;org.hibernate.hql.ast.ASTQueryTranslatorFactory&lt;/prop&gt;<br />                  &lt;prop key="hibernate.dbcp.maxActive"&gt;100&lt;/prop&gt;<br />    &lt;prop key="hibernate.dbcp.whenExhaustedAction"&gt;1&lt;/prop&gt;<br />    &lt;prop key="hibernate.dbcp.maxWait"&gt;120000&lt;/prop&gt;<br />    &lt;prop key="hibernate.dbcp.maxIdle"&gt;10&lt;/prop&gt;<br />    &lt;prop key="hibernate.dbcp.ps.maxActive"&gt;100&lt;/prop&gt;<br />    &lt;prop key="hibernate.dbcp.ps.whenExhaustedAction"&gt;1&lt;/prop&gt;<br />    &lt;prop key="hibernate.dbcp.ps.maxWait"&gt;120000&lt;/prop&gt;<br />    &lt;prop key="hibernate.dbcp.ps.maxIdle"&gt;10&lt;/prop&gt;<br />    &lt;!--prop key="hibernate.dbcp.validationQuery"&gt;select 1 from AclUser&lt;/prop--&gt;<br />    &lt;prop key="hibernate.dbcp.testOnBorrow"&gt;true&lt;/prop&gt;<br />    &lt;prop key="hibernate.dbcp.testOnReturn"&gt;false&lt;/prop&gt;<br />    &lt;prop key="hibernate.dialect"&gt;${hibernate.dialect}&lt;/prop&gt;<br />    &lt;prop key="hibernate.connection.pool_size"&gt;10&lt;/prop&gt;<br />    &lt;prop key="hibernate.cache.use_query_cache"&gt;true&lt;/prop&gt;<br />    &lt;!--prop key="hibernate.cache.provider_class"&gt;net.sf.ehcache.hibernate.Provider&lt;/prop--&gt;<br />    &lt;prop key="hibernate.use_outer_join"&gt;true&lt;/prop&gt;<br />    &lt;prop key="hibernate.max_fetch_depth"&gt;3&lt;/prop&gt;<br />    &lt;prop key="hibernate.jdbc.fetch_size"&gt;100&lt;/prop&gt;<br />    &lt;prop key="hibernate.jdbc.batch_size"&gt;30&lt;/prop&gt;<br />    &lt;prop key="hibernate.default_batch_fetch_size"&gt;50&lt;/prop&gt;<br />    &lt;prop key="hibernate.show_sql"&gt;true&lt;/prop&gt;<br />    &lt;prop key="hibernate.query.substitutions"&gt;true 1, false 0, yes 'Y', no 'N'&lt;/prop&gt;<br />   &lt;/props&gt;<br />  &lt;/property&gt;<br /> &lt;/bean&gt;</p>
		<p>    &lt;bean id="ownersDao" class="cn.rhui.framework.test.dao.impl.OwnersImpl" autowire="byName"/&gt;</p>
		<p>&lt;/beans&gt;</p>
		<br />
<img src ="http://www.blogjava.net/WshmAndLily/aggbug/78956.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/WshmAndLily/" target="_blank">semovy</a> 2006-11-03 17:36 <a href="http://www.blogjava.net/WshmAndLily/articles/78956.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>你能过关吗?J2EE面试题集锦(附答案)</title><link>http://www.blogjava.net/WshmAndLily/articles/75240.html</link><dc:creator>semovy</dc:creator><author>semovy</author><pubDate>Sun, 15 Oct 2006 03:28:00 GMT</pubDate><guid>http://www.blogjava.net/WshmAndLily/articles/75240.html</guid><wfw:comment>http://www.blogjava.net/WshmAndLily/comments/75240.html</wfw:comment><comments>http://www.blogjava.net/WshmAndLily/articles/75240.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/WshmAndLily/comments/commentRss/75240.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/WshmAndLily/services/trackbacks/75240.html</trackback:ping><description><![CDATA[**<br /> * By metaphy 2005-11-12<br /> * Version: 0.01<br /> * 注:题目答案来源于metaphy过去的知识或网络,metaphy不能保证其正确或完整性,仅供参考<br />**/<br /><strong>一、基础问答</strong><p>　　<strong>1.下面哪些类可以被继承?</strong></p><p>　　　java.lang.Thread (T)<br />　　　java.lang.Number (T)<br />　　　java.lang.Double (F)<br />　　　java.lang.Math  (F)<br />　　　java.lang.Void  (F)<br />　　　java.lang.Class  (F)<br />　　　java.lang.ClassLoader (T)</p><p>　　<strong>2.抽象类和接口的区别</strong></p><p>　　(1)接口可以被多重implements,抽象类只能被单一extends<br />　　(2)接口只有定义,抽象类可以有定义和实现<br />　　(3)接口的字段定义默认为:public static final, 抽象类字段默认是"friendly"(本包可见)</p><p>　　<strong>3.Hashtable的原理,并说出HashMap与Hashtable的区别</strong></p><p>　　HashTable的原理:通过节点的关键码确定节点的存储位置,即给定节点的关键码k,通过一定的函数关系H(散列函数),得到函数值H(k),将此值解释为该节点的存储地址.<br />HashMap 与Hashtable很相似,但HashMap 是非同步(unsynchronizded)和可以以null为关键码的.</p><p>　　<strong>4.forward和redirect的区别</strong></p><p>　　forward: an internal transfer in servlet<br />　　redirect: 重定向,有2次request,第2次request将丢失第一次的attributs/parameters等</p><p>　　<strong>5.什么是Web容器?</strong></p><p>　　实现J2EE规范中web协议的应用.该协议定义了web程序的运行时环境,包括:并发性,安全性,生命周期管理等等.</p><p>　　6.解释下面关于J2EE的名词</p><p>　　(1)JNDI:Java Naming &amp; Directory Interface,JAVA命名目录服务.主要提供的功能是：提供一个目录系统，让其它各地的应用程序在其上面留下自己的索引，从而满足快速查找和定位分布式应用程序的功能.<br />　　(2)JMS：Java Message Service,JAVA消息服务.主要实现各个应用程序之间的通讯.包括点对点和广播.<br />　　(3)JTA：Java Transaction API,JAVA事务服务.提供各种分布式事务服务.应用程序只需调用其提供的接口即可.<br />　　(4)JAF: Java Action FrameWork,JAVA安全认证框架.提供一些安全控制方面的框架.让开发者通过各种部署和自定义实现自己的个性安全控制策略.<br />　　(5)RMI:Remote Method Interface,远程方法调用</p><p>　　<strong>7.EJB是基于哪些技术实现的？并说 出SessionBean和EntityBean的区别，StatefulBean和StatelessBean的区别.</strong></p><p>　　EJB包括Session Bean、Entity Bean、Message Driven Bean，基于JNDI、RMI、JAT等技术实现.</p><p>　　SessionBean在J2EE应用程序中被用来完成一些服务器端的业务操作，例如访问数据库、调用其他EJB组件.EntityBean被用来代表应用系统中用到的数据.对于客户机，SessionBean是一种非持久性对象，它实现某些在服务器上运行的业务逻辑;EntityBean是一种持久性对象，它代表一个存储在持久性存储器中的实体的对象视图，或是一个由现有企业应用程序实现的实体.</p><p>　　Session Bean 还可以再细分为 Stateful Session Bean 与 Stateless Session Bean .这两种的 Session Bean都可以将系统逻辑放在 method之中执行，不同的是 Stateful Session Bean 可以记录呼叫者的状态，因此通常来说，一个使用者会有一个相对应的 Stateful Session Bean 的实体.Stateless Session Bean 虽然也是逻辑组件，但是他却不负责记录使用者状态，也就是说当使用者呼叫 Stateless Session Bean 的时候，EJB Container 并不会找寻特定的 Stateless Session Bean 的实体来执行这个 method.换言之，很可能数个使用者在执行某个 Stateless Session Bean 的 methods 时，会是同一个 Bean 的 Instance 在执行.从内存方面来看， Stateful Session Bean 与 Stateless Session Bean 比较， Stateful Session Bean 会消耗 J2EE Server 较多的内存，然而 Stateful Session Bean 的优势却在于他可以维持使用者的状态.</p><p>　　<strong>8.XML的解析方法</strong></p><p>　　Sax,DOM,JDOM</p><p>　　<strong>9.什么是Web Service?</strong></p><p>　　Web Service就是为了使原来各孤立的站点之间的信息能够相互通信、共享而提出的一种接口。<br />Web Service所使用的是Internet上统一、开放的标准，如HTTP、XML、SOAP（简单对象访问协议）、WSDL等，所以Web Service可以在任何支持这些标准的环境（Windows,Linux）中使用。</p><p>　　注：SOAP协议（Simple Object Access Protocal,简单对象访问协议）,它是一个用于分散和分布式环境下网络信息交换的基于XML的通讯协议。在此协议下，软件组件或应用程序能够通过标准的HTTP协议进行通讯。它的设计目标就是简单性和扩展性，这有助于大量异构程序和平台之间的互操作性，从而使存在的应用程序能够被广泛的用户访问。</p><p>　　优势：</p><p>　　(1).跨平台。<br />　　(2).SOAP协议是基于XML和HTTP这些业界的标准的，得到了所有的重要公司的支持。<br />　　(3).由于使用了SOAP，数据是以ASCII文本的方式而非二进制传输，调试很方便；并且由于这样，它的数据容易通过防火墙，不需要防火墙为了程序而单独开一个“漏洞”。<br />　　(4).此外，WebService实现的技术难度要比CORBA和DCOM小得多。<br />　　(5).要实现B2B集成，EDI比较完善与比较复杂；而用WebService则可以低成本的实现，小公司也可以用上。<br />　　(6).在C/S的程序中，WebService可以实现网页无整体刷新的与服务器打交道并取数。</p><p>　　缺点：</p><p>　　(1).WebService使用了XML对数据封装，会造成大量的数据要在网络中传输。<br />　　(2).WebService规范没有规定任何与实现相关的细节，包括对象模型、编程语言，这一点，它不如CORBA。</p><p>　　<strong>10.多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么?</strong></p><p>　　答：多线程有两种实现方法，分别是继承Thread类与实现Runnable接口<br />　　同步的实现方面有两种，分别是synchronized,wait与notify</p><p>　　<strong>11.JSP中动态INCLUDE与静态INCLUDE的区别？</strong></p><p>　　动态INCLUDE用jsp:include动作实现</p><p>&lt;jsp:include page="included.jsp" flush="true"/&gt;</p><p>　　它总是会检查所含文件中的变化，适合用于包含动态页面，并且可以带参数</p><p>　　静态INCLUDE用include伪码实现,定不会检查所含文件的变化，适用于包含静态页面</p><p>　　&lt;%@ include file="included.htm" %&gt;<br /><br /></p><p><strong>二、Java编程与程序运行结果</strong></p><p>　　<strong>1.Java编程,打印昨天的当前时刻</strong></p><p class="code">public class YesterdayCurrent{<br />  public void main(String[] args){<br />    Calendar cal = Calendar.getInstance();<br />    cal.add(Calendar.DATE, -1);<br />    System.out.println(cal.getTime());<br />  }<br />}</p><p>　　<strong>2.文件读写,实现一个计数器</strong></p><p class="code">  public int getNum(){<br />        int i = -1;<br />        try{<br />            String stri="";<br />            BufferedReader in = new BufferedReader(new FileReader(f));<br />            while((stri=in.readLine())!=null){<br />                i = Integer.parseInt(stri.trim());<br />            }<br />            in.close();<br />        }catch(Exception e){<br />            e.printStackTrace();<br />        }<br />        return i;<br />    }<br />    public void setNum(){<br />        int i = getNum();<br />        i++;        <br />        try{<br />            PrintWriter out=new PrintWriter(new BufferedWriter(new FileWriter(f,false)));  <br />            out.write(String.valueOf(i));            //可能是编码的原因，如果直接写入int的话，将出现java编码和windows编码的混乱，因此此处写入的是String<br />            out.close() ;<br />        }catch(Exception e){<br />            e.printStackTrace();<br />        }<br />    }</p><p>　　<strong>3. 指出下面程序的运行结果:</strong></p><p class="code">class A{<br />    static{<br />        System.out.print("1");<br />    }<br />    public A(){<br />        System.out.print("2");<br />    }<br />}<br />class B extends A{<br />    static{<br />        System.out.print("a");<br />    }<br />    public B(){<br />        System.out.print("b");<br />    }   <br />}<br />public class Hello{<br />    public static void main(String[] ars){<br />        A ab = new B(); //执行到此处,结果: 1a2b<br /> ab = new B(); //执行到此处,结果: 1a2bab<br />    }<br />}</p><p>　　注:类的static 代码段,可以看作是类首次加载(被虚拟机加载)执行的代码,而对于类的加载,首先要执行其基类的构造,再执行其本身的构造</p><p>　　<strong>4.写一个Singleton模式的例子</strong></p><p class="code">public class Singleton{<br /> private static Singleton single = new Singleton();<br /> private Singleton(){}<br /> public Singleton getInstance(){<br />  return single;<br /> }<br />}</p><p><strong>三、数据库</strong></p><p>　　<strong>1.删除表的重复记录</strong></p><p>　　如果记录完全相同才算重复记录,那么:  (sql server2000下测试通过)</p><p class="code">select distinct * into #tmpp from tid<br />delete from tid     <br />insert into tid select * from #tmpp<br />drop table #tmpp</p><p>　　如果有id主键(数字,自增1的那种),那么:(sql server2000下测试通过)</p><p class="code">delete from tableA where id not in<br />(select id = min(id) from tableA group by name)</p><p>　　<strong>2.delete from tablea &amp; truncate table tablea的区别</strong></p><p>　　truncate 语句执行速度快,占资源少,并且只记录页删除的日志；<br />　　delete 对每条记录的删除均需要记录日志</p><img src ="http://www.blogjava.net/WshmAndLily/aggbug/75240.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/WshmAndLily/" target="_blank">semovy</a> 2006-10-15 11:28 <a href="http://www.blogjava.net/WshmAndLily/articles/75240.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>