﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-java open source</title><link>http://www.blogjava.net/nogocn/</link><description>转变思维观念:人是群体生活的.需要沟通与理解.</description><language>zh-cn</language><lastBuildDate>Wed, 15 Apr 2026 11:57:56 GMT</lastBuildDate><pubDate>Wed, 15 Apr 2026 11:57:56 GMT</pubDate><ttl>60</ttl><item><title>保存引用JBPM4</title><link>http://www.blogjava.net/nogocn/archive/2009/11/24/303479.html</link><dc:creator>NG</dc:creator><author>NG</author><pubDate>Tue, 24 Nov 2009 07:48:00 GMT</pubDate><guid>http://www.blogjava.net/nogocn/archive/2009/11/24/303479.html</guid><wfw:comment>http://www.blogjava.net/nogocn/comments/303479.html</wfw:comment><comments>http://www.blogjava.net/nogocn/archive/2009/11/24/303479.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nogocn/comments/commentRss/303479.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nogocn/services/trackbacks/303479.html</trackback:ping><description><![CDATA[<div style="layout-grid:  15.6pt none">
<p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 16pt"><span style="font-family: Calibri">jBPM3 vs jBPM4</span> </span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: small"><span style="font-family: Calibri">JBoss Goup </span><span style="font-family: 宋体">目前已经发布了</span> <span style="font-family: Calibri">jBPM4 Alpha1 </span><span style="font-family: 宋体">版本，在版本</span> <span style="font-family: Calibri">4 </span><span style="font-family: 宋体">中最大的变化就是引入</span> <span style="font-family: Calibri">PVM </span><span style="font-family: 宋体">（流程虚拟机）的概念，而引擎内部的调度算法中重要的</span> <span style="font-family: Calibri">Token </span><span style="font-family: 宋体">机制，在新版中也去掉了，纵观整个代码，变化可以说非常的大，笔者接下来就试着来比较一下这种变化，让大家能有个直观的认识。当然</span> <span style="font-family: Calibri">Jbpm4 </span><span style="font-family: 宋体">在</span> <span style="font-family: Calibri">JBoss </span><span style="font-family: 宋体">的官方网站上的</span> <span style="font-family: Calibri">Road map </span><span style="font-family: 宋体">中，在今年的</span> <span style="font-family: Calibri">7 </span><span style="font-family: 宋体">月</span> <span style="font-family: Calibri">1 </span><span style="font-family: 宋体">号才会发布第一个正式版本，因此后续可能还会有变化。</span> </span></p>
<p style="margin: 0cm 0cm 0pt 18pt; text-indent: -18pt; text-align: left" align="left"><span style="font-size: small; font-family: Calibri">1、 &nbsp;</span><span style="font-size: small"><span style="font-family: 宋体">流程定义对象的变化：</span> </span></p>
<p style="margin: 0cm 0cm 0pt 18pt; text-indent: 0cm; text-align: left" align="left"><span style="font-size: small"><span style="font-family: Calibri">Jbpm3 </span><span style="font-family: 宋体">流程定义对象关系图：</span> </span></p>
<p style="margin: 0cm 0cm 0pt 18pt; text-indent: 0cm; text-align: left" align="left"><span style="font-size: small"><span style="font-family: 宋体"><img height="95" alt="" src="http://www.blogjava.net/images/blogjava_net/nogocn/de3c6652-ff9b-3fc6-ac1b-3676bd389b23-thumb.gif" width="201" border="0" /> </span></span></p>
<p style="margin: 0cm 0cm 0pt 18pt; text-indent: 0cm; text-align: center"><span style="font-size: x-small"><span style="font-family: 宋体"><span style="font-size: small"><span style="font-family: 宋体">图一 jbpm3流程定义对象关系图</span> </span></span></span></p>
<p style="margin: 0cm 0cm 0pt 18pt; text-indent: 0cm; text-align: left" align="left"><span style="font-size: small"><span style="font-family: 宋体">从上图我们可以看出这</span> <span style="font-family: Calibri">jbpm3 </span><span style="font-family: 宋体">中，</span> <span style="font-family: Calibri">GraphElement </span><span style="font-family: 宋体">是流程图中所有流程元素的父对象，而整个流程是由</span> <span style="font-family: Calibri">ProcessDefinition </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">Node </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">Transition </span><span style="font-family: 宋体">三个主要对象构成；</span> </span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: small; font-family: Calibri">&nbsp; <img height="150" alt="" src="http://www.blogjava.net/images/blogjava_net/nogocn/945ef59e-9462-352f-97b9-e186353826ba-thumb.png" width="143" border="0" /></span></p>
<p style="margin: 0cm 0cm 0pt; text-align: center"><span style="font-size: small"><span style="font-family: Calibri">&nbsp;<span style="font-size: small"><span style="font-size: x-small"><span style="font-family: Calibri">图二 PVM <span style="font-family: 宋体">实体对象关系图 </span></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: small"><span style="font-family: 宋体">从上图可以看出，由于</span> <span style="font-family: Calibri">PVM </span><span style="font-family: 宋体">概念的引入，所以在</span> <span style="font-family: Calibri">jbpm3 </span><span style="font-family: 宋体">中的</span> <span style="font-family: Calibri">Graph </span><span style="font-family: 宋体">包在</span> <span style="font-family: Calibri">jbpm4 </span><span style="font-family: 宋体">中被移除了。在</span> <span style="font-family: Calibri">pvm </span><span style="font-family: 宋体">中，在设计期，所有节点元素的父类为</span> <span style="font-family: Calibri">ProcessElementImpl </span><span style="font-family: 宋体">，流程的主要组成元素</span> <span style="font-family: Calibri">Nodelmpl </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">TransitionImpl </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">ProcessDefinitionImpl </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">EventImpl </span><span style="font-family: 宋体">则都直接或间接继承自</span> <span style="font-family: Calibri">ProcessElementImpl </span><span style="font-family: 宋体">。在运行期：</span> <span style="font-family: Calibri">jbpm4 </span><span style="font-family: 宋体">把流程的运行期行为定义为执行行为（</span> <span style="font-family: Calibri">ExecutionImpl </span><span style="font-family: 宋体">）及原子操作行为（</span> <span style="font-family: Calibri">AtomicOperation </span><span style="font-family: 宋体">，其具体实现为</span> <span style="font-family: Calibri">ExecuteNode </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">ProceedToDestination </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">TakeTranstion </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">MoveToParentNode </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">MoveToChildNode </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">signal </span><span style="font-family: 宋体">），其中</span> <span style="font-family: Calibri">ExecutionImpl </span><span style="font-family: 宋体">是流程实例、活动实例、事件监听器的所有执行期行为的实现类。</span> </span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: small">&nbsp;<img height="149" alt="" src="http://www.blogjava.net/images/blogjava_net/nogocn/fd92ee88-654f-3e2e-804d-67cb891ba813-thumb.png" width="200" border="0" /></span></p>
<p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: small"><span style="font-family: Calibri">图三 jpdl </span><span style="font-family: 宋体">运行期活动实体对象关系图</span> </span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left">&nbsp; <span style="font-size: small"><span style="font-family: 宋体">上图是</span> <span style="font-family: Calibri">jbpm4 </span><span style="font-family: 宋体">在运行期的活动实例对象关系图，从图中我们可以看出，在运行期，</span> <span style="font-family: Calibri">jbpm4 </span><span style="font-family: 宋体">中定义了两个活动接口</span> <span style="font-family: Calibri">Activity </span><span style="font-family: 宋体">和</span> <span style="font-family: Calibri">ExternalActivity </span><span style="font-family: 宋体">，其中</span> <span style="font-family: Calibri">ExternalActivity </span><span style="font-family: 宋体">继承自</span> <span style="font-family: Calibri">Activity </span><span style="font-family: 宋体">。</span> <span style="font-family: Calibri">Activity </span><span style="font-family: 宋体">是所有自动活动节点的父接口，其实现类为</span> <span style="font-family: Calibri">JpdlActivity </span><span style="font-family: 宋体">，而</span> <span style="font-family: Calibri">JpdlActivity </span><span style="font-family: 宋体">又衍生出了、</span> <span style="font-family: Calibri">StartActivity </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">JoinActivity </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">ForkActivity </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">EndActivity </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">CreateTimerActivity </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">JavaActivity </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">EsbActivity </span><span style="font-family: 宋体">等实例活动对象。而</span> <span style="font-family: Calibri">ExternalActivity </span><span style="font-family: 宋体">是具有等待状态的活动（</span> <span style="font-family: Calibri">StateActivity </span><span style="font-family: 宋体">）父接口，像人工活动</span> <span style="font-family: Calibri">TaskActivity </span><span style="font-family: 宋体">就是实现了此接口。</span> </span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left">&nbsp; <span style="font-size: small; font-family: Calibri">2、 &nbsp;</span><span style="font-size: small"><span style="font-family: 宋体">核心引擎的调度算法</span> </span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: small"><span style="font-family: Calibri">Jbpm3 </span><span style="font-family: 宋体">的核心调度算法是基于</span> <span style="font-family: Calibri">Token </span><span style="font-family: 宋体">机制的，在运行期这个</span> <span style="font-family: Calibri">Token </span><span style="font-family: 宋体">在</span> <span style="font-family: Calibri">Node Instance </span><span style="font-family: 宋体">之间流转，依靠</span> <span style="font-family: Calibri">Token </span><span style="font-family: 宋体">的触发来推进流程。具体的调度机制，可参加胡长城的文章（</span> <a href="http://blog.csdn.net/james999/archive/2007/09/02/1769592.aspx"><span style="color: #800080; font-family: Calibri">http://blog.csdn.net/james999/archive/2007/09/02/1769592.aspx </a></span><span style="font-family: 宋体">）；其实这个</span> <span style="font-family: Calibri">Token </span><span style="font-family: 宋体">来自于</span> <span style="font-family: Calibri">Pertri-net </span><span style="font-family: 宋体">，感兴趣的读者可以去看</span> <span style="font-family: Calibri">Pertri-net </span><span style="font-family: 宋体">中的</span> <span style="font-family: Calibri">Token </span><span style="font-family: 宋体">及</span> <span style="font-family: Calibri">Place </span><span style="font-family: 宋体">。</span> </span></p>
<p style="margin: 0cm 0cm 0pt; text-align: center"><span style="font-size: small; font-family: Calibri">&nbsp;&nbsp; <img height="142" alt="" src="http://www.blogjava.net/images/blogjava_net/nogocn/c394c2ba-4994-3a41-bb5d-da3aefaad52a-thumb.png" width="200" border="0" /></span></p>
<p style="margin: 0cm 0cm 0pt; text-align: center"><span style="font-size: small; font-family: Calibri"><span style="font-size: small"><span style="font-family: Calibri"><span style="font-size: x-small">图四 jbpm3引擎调度图 </span></span></span></span>&nbsp; </p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: small"><span style="font-family: Calibri">Jbpm4 </span><span style="font-family: 宋体">则去掉了</span> <span style="font-family: Calibri">Token </span><span style="font-family: 宋体">，那么它的核心调度机制是怎样实现的呢？</span> </span></p>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><a href="http://www.javaeye.com/upload/attachment/75939/e4bec602-bf0e-3c82-a5b5-9a366ebf4225.png">&nbsp;</a><img height="104" alt="" src="http://www.blogjava.net/images/blogjava_net/nogocn/e4bec602-bf0e-3c82-a5b5-9a366ebf4225-thumb.png" width="200" border="0" /></p>
<p style="margin: 0cm 0cm 0pt; text-align: center"><span style="font-size: small; font-family: Calibri">&nbsp;<span style="font-size: small; font-family: Calibri"><span style="font-size: x-small">图五 jbpm4流程启动序列图 </span></span></span></p>
<p style="margin: 0cm 0cm 0pt; text-align: center"><a href="http://www.javaeye.com/upload/attachment/75940/b3827a55-277e-322b-b8ab-500ddc2d6c5b.png">&nbsp;</a></p>
<p style="margin: 0cm 0cm 0pt; text-align: center"><span style="font-size: x-small; font-family: Calibri"><span style="font-size: small; font-family: Calibri"><span style="font-size: small"><span style="font-family: 宋体">图六 jbpm4 流程推进序列图 </span></span></span></span><span style="font-size: 10.5pt; font-family: 'Calibri','sans-serif'"><br style="page-break-before: always" />
</span></p>
</div>
<p style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span style="font-size: small"><span style="font-family: 宋体">图五是在</span> <span style="font-family: Calibri">jbpm4 </span><span style="font-family: 宋体">中启动一个流程实例的执行序列图，图六是节点推进的执行序列图，从上面两个图中我们可以看到核心的调度是依据</span> <span style="font-family: Calibri">Execution </span><span style="font-family: 宋体">的转移来实现的（</span> <span style="font-family: Calibri">ExecutionImpl </span><span style="font-family: 宋体">可以是</span> <span style="font-family: Calibri">ActivityExecution </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">ClientProcessInstance </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">EventListenerExecution </span><span style="font-family: 宋体">的实例），</span> <span style="font-family: Calibri">Execution </span><span style="font-family: 宋体">实际上就是取代了</span> <span style="font-family: Calibri">Jbpm3 </span><span style="font-family: 宋体">中的</span> <span style="font-family: Calibri">Token </span><span style="font-family: 宋体">，</span> <span style="font-family: Calibri">Execution </span><span style="font-family: 宋体">的转移实际上就是根据状态机的变迁（</span> <span style="font-family: Calibri">ActivityExecution </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">ClientProcessInstance </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">EventListenerExecution </span><span style="font-family: 宋体">实例之间的切换）加上调用相应的原子操作：</span> <span style="font-family: Calibri">ExecuteNode </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">MoveToChildNode </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">MoveToParentNode </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">ProceedToDesitination </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">Signal </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">TakeTransition </span><span style="font-family: 宋体">（详见</span> <span style="font-family: Calibri">pvm/internal/model/op </span><span style="font-family: 宋体">包下的相关类）来实现的。所以</span> <span style="font-family: Calibri">Execution </span><span style="font-family: 宋体">实例的集合及有向图实际上就是运行期的路径。</span> </span></p>
<p style="margin: 0cm 0cm 0pt 18pt; text-indent: -18pt; text-align: left" align="left"><span style="font-size: small; font-family: Calibri">3、 &nbsp;</span><span style="font-size: small"><span style="font-family: Calibri">Event-Action </span><span style="font-family: 宋体">机制的变化</span> </span></p>
<p style="margin: 0cm 0cm 0pt 18pt; text-indent: 0cm; text-align: left" align="left"><span style="font-size: small"><span style="font-family: 宋体">在</span> <span style="font-family: Calibri">jbpm3 </span><span style="font-family: 宋体">中是基于</span> <span style="font-family: Calibri">Event-Action </span><span style="font-family: 宋体">机制来实现事件与动作的触发的，但是在</span> <span style="font-family: Calibri">jbpm4 </span><span style="font-family: 宋体">中则采用观察者模式来触发事件的。所有用户自己定义的动作，全部要实现</span> <span style="font-family: Calibri">EventListener </span><span style="font-family: 宋体">接口，这些动作作为监听者（就是事件</span> <span style="font-family: Calibri">Event </span><span style="font-family: 宋体">的观察者</span> <span style="font-family: Calibri">Observer </span><span style="font-family: 宋体">）注册到相应的流程定义对象上（</span> <span style="font-family: Calibri">ProcessElement </span><span style="font-family: 宋体">或者</span> <span style="font-family: Calibri">Node </span><span style="font-family: 宋体">），而事件</span> <span style="font-family: Calibri">Event </span><span style="font-family: 宋体">则作为被观察的对象（实际上就是</span> <span style="font-family: Calibri">Observerable </span><span style="font-family: 宋体">），实际上在</span> <span style="font-family: Calibri">jbpm4 </span><span style="font-family: 宋体">中专门定义出了一个对象</span> <span style="font-family: Calibri">ObservableElementImpl </span><span style="font-family: 宋体">，流程定义中的</span> <span style="font-family: Calibri">NodeImpl </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">TransitionImpl </span><span style="font-family: 宋体">、</span> <span style="font-family: Calibri">ProcessDefinitionImpl </span><span style="font-family: 宋体">均继承自此对象，因此这些元素本身就可以作为</span> <span style="font-family: Calibri">Observerable </span><span style="font-family: 宋体">而被观察者来监控。</span> </span></p>
<p style="margin: 0cm 0cm 0pt 18pt; text-indent: -18pt; text-align: left" align="left"><span style="font-size: small; font-family: Calibri">4、 &nbsp;</span><span style="font-size: small"><span style="font-family: 宋体">客户端接口的变化</span> </span></p>
<p style="margin-left: 18pt; text-indent: 0cm; text-align: left" align="left"><span style="font-family: 宋体">在</span>jbpm4<span style="font-family: 宋体">中对客户端的接口统一为</span>7<span style="font-family: 宋体">个服务接口：</span>ProcessService<span style="font-family: 宋体">、</span>ExecutionService<span style="font-family: 宋体">、</span>CommandService <span style="font-family: 宋体">、</span>TaskService <span style="font-family: 宋体">、</span>ManagementService<span style="font-family: 宋体">、</span><span style="font-size: 11pt; color: black">HistoryService</span><span style="font-size: 11pt; color: black; font-family: 宋体">、</span><span style="font-size: 11pt; color: black">IdentityService</span><span style="font-family: 宋体">，这</span>7<span style="font-family: 宋体">个接口可以从</span>ProcessEngine<span style="font-family: 宋体">接口中获得，</span>jbpm4<span style="font-family: 宋体">在启动的过程中由</span>JbpmConfiguration<span style="font-family: 宋体">负责构建引擎。</span></p>
<p style="margin-left: 39pt; text-indent: -21pt; text-align: left" align="left"><span style="font-family: Wingdings">&#216;&nbsp;</span>ProcessService-<span style="font-family: 宋体">流程定义的服务接口，包括对流程定义的部署、查询、删除操作；</span></p>
<p style="margin-left: 39pt; text-indent: -21pt; text-align: left" align="left"><span style="font-family: Wingdings">&#216;&nbsp;</span>ExecutionService-<span style="font-family: 宋体">执行服务接口，包括启动流程、实例推进、设置变量等操作；</span></p>
<p style="margin-left: 39pt; text-indent: -21pt; text-align: left" align="left"><span style="font-family: Wingdings">&#216;&nbsp;</span>CommandService-Command<span style="font-family: 宋体">模式的服务接口，实际上就是将客户端的请求全部封装在一个调用接口中，然后由这个接口去调用</span>Command<span style="font-family: 宋体">接口的众多实现（</span>StartExecutionCmd<span style="font-family: 宋体">、</span>SignalCmd<span style="font-family: 宋体">、</span>SetVariablesCmd<span style="font-family: 宋体">、</span>GetTimersCmd<span style="font-family: 宋体">、</span>DeployCmd<span style="font-family: 宋体">、</span>NewTaskCmd<span style="font-family: 宋体">、</span>SubmitTask<span style="font-family: 宋体">、</span>ExecuteJobCmd<span style="font-family: 宋体">等等，具体可参加</span>pvm/internal/cmd<span style="font-family: 宋体">，</span>task/internal/cmd<span style="font-family: 宋体">包及其它包下实现</span>Command<span style="font-family: 宋体">接口的类），这是典型的</span>Command<span style="font-family: 宋体">模式的应用，感兴趣的读者可以去了解设计模式中的</span>Command<span style="font-family: 宋体">模式；</span></p>
<p style="margin-left: 39pt; text-indent: -21pt; text-align: left" align="left"><span style="font-family: Wingdings">&#216;&nbsp;</span>TaskService-<span style="font-family: 宋体">人工活动的服务接口，包括对任务的创建、提交、查询、保存、删除等操作；</span></p>
<p style="margin-left: 39pt; text-indent: -21pt; text-align: left" align="left"><span style="font-family: Wingdings">&#216;&nbsp;</span><span style="font-family: 宋体">ManagementService-web</span><span style="font-family: 宋体">管理控制台的服务接口，目前只有获得消息及计时器的接口实现；</span></p>
<p style="margin-left: 39pt; text-indent: -21pt; text-align: left" align="left"><span style="font-family: Wingdings">&#216;&nbsp;</span><span style="color: black; font-family: 宋体">HistoryService-</span><span style="color: black; font-family: 宋体">目前有对历史库中的流程实例、活动实例进行查询、某个流程定义中的所有活动的平均持续时间、某个流程定义中的某个活动实例的转移的执行次数</span></p>
<p style="margin-left: 39pt; text-indent: -21pt; text-align: left" align="left"><span style="font-family: Wingdings">&#216;&nbsp;</span><span style="color: black; font-family: 宋体">IdentityService-</span><span style="color: black; font-family: 宋体">用户、组、成员关系的相关操作方法</span></p>
<p style="margin-left: 18pt; text-indent: -18pt; text-align: left" align="left"><span style="color: black; font-family: 'Verdana','sans-serif'">5、</span><span style="color: black; font-family: 宋体">历史库的加入</span></p>
<p><span style="font-size: 10.5pt; color: black; font-family: 宋体"><span style="font-size: small">jBPM3</span></span><span style="font-size: 10.5pt; color: black; font-family: 宋体"><span style="font-size: small">中数据库设计一直是我比较诟病的地方，尤其是其实例数据库没有设计历史库的概念并按照办结状态将运行结束的实例数据归入历史库，在这种情况下它的实例数据库就会随着时间而无限膨胀，这就阻碍了它的真实应用，而在</span><span style="font-size: small">jBPM4</span><span style="font-size: small">的最新代码中（注意</span><span style="font-size: small">Alpha1</span><span style="font-size: small">还没有出现），历史库的相关功能代码竟然出现了！详见</span></span><span style="font-size: 10.5pt; color: black; font-family: 'Times New Roman','serif'"><span style="font-size: small">ExecutionImpl</span></span><span style="font-size: 10.5pt; color: black; font-family: 宋体"><span style="font-size: small">最新代码中的</span></span><span style="font-size: 10.5pt; color: black; font-family: 'Times New Roman','serif'"><span style="font-size: small">fireHistoryEvent</span></span><span style="font-size: 10.5pt; color: black; font-family: 宋体"><span style="font-size: small">方法及一系列的</span></span><span style="font-size: 10.5pt; color: black; font-family: 'Times New Roman','serif'"><span style="font-size: small">historyXXX</span></span><span style="font-size: 10.5pt; color: black; font-family: 宋体"><span style="font-size: small">方法。在</span></span><span style="font-size: 10.5pt; color: black; font-family: 'Times New Roman','serif'"><span style="font-size: small">ActivityBehaviour</span></span><span style="font-size: 10.5pt; color: black; font-family: 宋体"><span style="font-size: small">的</span></span><span style="font-size: 10.5pt; color: black; font-family: 'Times New Roman','serif'"><span style="font-size: small">execute</span></span><span style="font-size: 10.5pt; color: black; font-family: 宋体"><span style="font-size: small">方法中加入了</span></span><span style="font-size: 10.5pt; color: black; font-family: 'Times New Roman','serif'"><span style="font-size: small">historyTaskStart</span></span><span style="font-size: 10.5pt; color: black; font-family: 宋体"><span style="font-size: small">方法的调用、</span></span><span style="font-size: 10.5pt; color: black; font-family: 'Times New Roman','serif'"><span style="font-size: small">signal</span></span><span style="font-size: 10.5pt; color: black; font-family: 宋体"><span style="font-size: small">方法中加入了</span></span><span style="font-size: 10.5pt; color: black; font-family: 'Times New Roman','serif'"><span style="font-size: small">historyTaskEnd</span></span><span style="font-size: 10.5pt; color: black; font-family: 宋体"><span style="font-size: small">方法的调用，而以上</span></span><span style="font-size: 10.5pt; color: black; font-family: 'Times New Roman','serif'"><span style="font-size: small">2</span></span><span style="font-size: 10.5pt; color: black; font-family: 宋体"><span style="font-size: small">个方法在</span></span><span style="font-size: 10.5pt; color: black; font-family: 'Times New Roman','serif'"><span style="font-size: small">ExecutionImpl</span></span><span style="font-size: 10.5pt; color: black; font-family: 宋体"><span style="font-size: small">中都是以历史事件（</span><span style="font-size: small">HistoryEvent</span><span style="font-size: small">有</span><span style="font-size: small">4</span><span style="font-size: small">个实现子类</span><span style="font-size: small">ProcessInstanceStart</span><span style="font-size: small">、</span><span style="font-size: small">ProcessInstanceEnd</span><span style="font-size: small">、</span><span style="font-size: small">ActivityStart</span><span style="font-size: small">、</span><span style="font-size: small">ActivityEnd</span><span style="font-size: small">分别用作流程实例的创建结束期、活动实例的创建结束期的历史数据处理）的触发机制来实现的，也就是在整个流程实例执行的过程中，都加入了对将运行数据存入历史库的历史事件（</span><span style="font-size: small">HistoryEvent</span><span style="font-size: small">）的触发。这样实例列表的查询可以只查询历史库。不过这里很遗憾的是，这个事件没有同时清除运行库的数据，这样还是会造成运行库的无限膨胀问题。</span></span></p>
<img src ="http://www.blogjava.net/nogocn/aggbug/303479.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nogocn/" target="_blank">NG</a> 2009-11-24 15:48 <a href="http://www.blogjava.net/nogocn/archive/2009/11/24/303479.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>eclipse 快捷键</title><link>http://www.blogjava.net/nogocn/archive/2009/10/09/297532.html</link><dc:creator>NG</dc:creator><author>NG</author><pubDate>Fri, 09 Oct 2009 06:24:00 GMT</pubDate><guid>http://www.blogjava.net/nogocn/archive/2009/10/09/297532.html</guid><wfw:comment>http://www.blogjava.net/nogocn/comments/297532.html</wfw:comment><comments>http://www.blogjava.net/nogocn/archive/2009/10/09/297532.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nogocn/comments/commentRss/297532.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nogocn/services/trackbacks/297532.html</trackback:ping><description><![CDATA[<p>下面的这些是我最常用的快捷键： <br />
CTRL+SHIFT+T：根据名字查找类，可以使用通配符，只能查找类，可以是工程引用的包中的类 <br />
CTRL+SHIFT+R：根据名字查找资源，可以是jsp，xml，js等任何文件 <br />
F11：以DEBUG模式运行上次运行的类 <br />
F5：单步进入，进入当前调试的代码行执行 <br />
F6：单步执行当前行 <br />
F8：执行到下一个断点 <br />
ALT+SHIFT+R：重命名选择的文件名，如果是类的话，将进行重构，同时修改相关的引用 <br />
ALT+上下箭头：将当前行或者选中的行上移或者下移一行 <br />
ALT+/：代码自动补全 <br />
CTRL+SHIFT+O：自动导入需要的类 <br />
CTRL+SHIFT+F：格式化当前文件或者选中的行 <br />
CTRL+L：定位到指定的行 <br />
CTRL+/：注释/取消注释 <br />
CTRL+ALT+H：打开调用层次，如果要知道一个方法的调用入口时很有用 <br />
CTRL+Z：取消上次修改（Undo） <br />
CTRL+Y：重复上次修改（Redo) <br />
快捷键大全<br />
作用域 功能 快捷键 <br />
　　全局 查找并替换 Ctrl+F <br />
　　文本编辑器 查找上一个 Ctrl+Shift+K <br />
　　文本编辑器 查找下一个 Ctrl+K <br />
　　全局 撤销 Ctrl+Z <br />
　　全局 复制 Ctrl+C <br />
　　全局 恢复上一个选择 Alt+Shift+&#8595; <br />
　　全局 剪切 Ctrl+X <br />
　　全局 快速修正 Ctrl1+1 <br />
　　全局 内容辅助 Alt+/ <br />
　　全局 全部选中 Ctrl+A <br />
　　全局 删除 Delete <br />
　　全局 上下文信息 Alt+？<br />
　　Alt+Shift+?<br />
　　Ctrl+Shift+Space <br />
　　Java编辑器 显示工具提示描述 F2 <br />
　　Java编辑器 选择封装元素 Alt+Shift+&#8593; <br />
　　Java编辑器 选择上一个元素 Alt+Shift+&#8592; <br />
　　Java编辑器 选择下一个元素 Alt+Shift+&#8594; <br />
　　文本编辑器 增量查找 Ctrl+J <br />
　　文本编辑器 增量逆向查找 Ctrl+Shift+J <br />
　　全局 粘贴 Ctrl+V <br />
　　全局 重做 Ctrl+Y </p>
<p>　　查看<br />
　　作用域 功能 快捷键 <br />
　　全局 放大 Ctrl+= <br />
　　全局 缩小 Ctrl+- </p>
<p>　　窗口<br />
　　作用域 功能 快捷键 <br />
　　全局 激活编辑器 F12 <br />
　　全局 切换编辑器 Ctrl+Shift+W <br />
　　全局 上一个编辑器 Ctrl+Shift+F6 <br />
　　全局 上一个视图 Ctrl+Shift+F7 <br />
　　全局 上一个透视图 Ctrl+Shift+F8 <br />
　　全局 下一个编辑器 Ctrl+F6 <br />
　　全局 下一个视图 Ctrl+F7 <br />
　　全局 下一个透视图 Ctrl+F8 <br />
　　文本编辑器 显示标尺上下文菜单 Ctrl+W <br />
　　全局 显示视图菜单 Ctrl+F10 <br />
　　全局 显示系统菜单 Alt+- </p>
<p>　　导航<br />
　　作用域 功能 快捷键 <br />
　　Java编辑器 打开结构 Ctrl+F3 <br />
　　全局 打开类型 Ctrl+Shift+T <br />
　　全局 打开类型层次结构 F4 <br />
　　全局 打开声明 F3 <br />
　　全局 打开外部javadoc Shift+F2 <br />
　　全局 打开资源 Ctrl+Shift+R <br />
　　全局 后退历史记录 Alt+&#8592; <br />
　　全局 前进历史记录 Alt+&#8594; <br />
　　全局 上一个 Ctrl+, <br />
　　全局 下一个 Ctrl+. <br />
　　Java编辑器 显示大纲 Ctrl+O <br />
　　全局 在层次结构中打开类型 Ctrl+Shift+H <br />
　　全局 转至匹配的括号 Ctrl+Shift+P <br />
　　全局 转至上一个编辑位置 Ctrl+Q <br />
　　Java编辑器 转至上一个成员 Ctrl+Shift+&#8593; <br />
　　Java编辑器 转至下一个成员 Ctrl+Shift+&#8595; <br />
　　文本编辑器 转至行 Ctrl+L </p>
<p>　　搜索<br />
　　作用域 功能 快捷键 <br />
　　全局 出现在文件中 Ctrl+Shift+U <br />
　　全局 打开搜索对话框 Ctrl+H <br />
　　全局 工作区中的声明 Ctrl+G <br />
　　全局 工作区中的引用 Ctrl+Shift+G </p>
<p>　　文本编辑<br />
　　作用域 功能 快捷键 <br />
　　文本编辑器 改写切换 Insert <br />
　　文本编辑器 上滚行 Ctrl+&#8593; <br />
　　文本编辑器 下滚行 Ctrl+&#8595; </p>
<p>　　文件<br />
　　作用域 功能 快捷键 <br />
　　全局 保存 Ctrl+X <br />
　　Ctrl+S <br />
　　全局 打印 Ctrl+P <br />
　　全局 关闭 Ctrl+F4 <br />
　　全局 全部保存 Ctrl+Shift+S <br />
　　全局 全部关闭 Ctrl+Shift+F4 <br />
　　全局 属性 Alt+Enter <br />
　　全局 新建 Ctrl+N </p>
<p>　　项目<br />
　　作用域 功能 快捷键 <br />
　　全局 全部构建 Ctrl+B </p>
<p>　　源代码<br />
　　作用域 功能 快捷键 <br />
　　Java编辑器 格式化 Ctrl+Shift+F <br />
　　Java编辑器 取消注释 Ctrl+\ <br />
　　Java编辑器 注释 Ctrl+/ <br />
　　Java编辑器 添加导入 Ctrl+Shift+M <br />
　　Java编辑器 组织导入 Ctrl+Shift+O <br />
　　Java编辑器 使用try/catch块来包围 未设置，太常用了，所以在这里列出,建议自己设置。<br />
　　也可以使用Ctrl+1自动修正。</p>
<p>　　运行<br />
　　作用域 功能 快捷键 <br />
　　全局 单步返回 F7 <br />
　　全局 单步跳过 F6 <br />
　　全局 单步跳入 F5 <br />
　　全局 单步跳入选择 Ctrl+F5 <br />
　　全局 调试上次启动 F11 <br />
　　全局 继续 F8 <br />
　　全局 使用过滤器单步执行 Shift+F5 <br />
　　全局 添加/去除断点 Ctrl+Shift+B <br />
　　全局 显示 Ctrl+D <br />
　　全局 运行上次启动 Ctrl+F11 <br />
　　全局 运行至行 Ctrl+R <br />
　　全局 执行 Ctrl+U </p>
<p>　　重构<br />
　　作用域 功能 快捷键 <br />
　　全局 撤销重构 Alt+Shift+Z <br />
　　全局 抽取方法 Alt+Shift+M <br />
　　全局 抽取局部变量 Alt+Shift+L <br />
　　全局 内联 Alt+Shift+I <br />
　　全局 移动 Alt+Shift+V <br />
　　全局 重命名 Alt+Shift+R <br />
　　全局 重做 Alt+Shift+Y</p>
<p>Eclipse启动参数大全 - -<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
Eclipse 运行命令行参数大全 <br />
包括英文版本和中文版本两种的说明, 特别需要值得一提的是那个 -nl 参数, 可以指定程序启动时所使用的语言. 例如:<br />
eclipse -nl en_US<br />
将启动英文语言, 这个特性在安装了国际化语言包以后特别有用, 可以方便的切换各个语言的版本. 注意 IBM WSAD v5.1 也支持这个功能. </p>
<p>运行 Eclipse<br />
将 Eclipse 驱动程序安装（解压缩）到某个目录（例如，c:\eclipse）中之后，通过运行顶级安装目录中的 Eclipse 可执行文件来启动"工作台"。在 Windows 系统上，该可执行文件称为 eclipse.exe，而在 Linux 系统上称为 eclipse。注意：下列讨论描述 Windows 系统上的设置。Linux 上的设置是相似的。</p>
<p>如果您没有另行指定，则平台将缺省工作区目录创建为可执行文件的兄弟目录（例如 c:\eclipse\workspace）。此工作区目录用作项目的缺省内容区，还用于保存任何必需的元数据。要进行共享安装或多工作区安装，应明确指 出工作区的位置而不是使用缺省值。有两种控制工作区位置的方法：使用当前工作目录或使用 -data 命令行自变量。</p>
<p>将工作区位置设置为在当前工作目录内<br />
在此方案中，工作区位置将是当前工作目录中称为 workspace 的目录。</p>
<p>实现此目的最容易的方法可能是使用下列步骤来创建快捷方式：</p>
<p>导航到 Windows 资源管理器中的 eclipse.exe 并使用右键拖动来创建 eclipse.exe 的快捷方式。 <br />
编辑快捷方式的属性，以使启动位置：字段标识工作区位置的父目录（例如，c:\users\robert）。 <br />
关闭属性对话框并双击快捷方式（如果提供的目录为 c:\users\robert，则工作区位置将为 c:\users\robert\workspace）。 <br />
当然，您也可以使用命令提示符（通过将目录切换为工作区父目录然后运行 eclipse.exe）来获得同样的效果。</p>
<p>使用 -data 设置工作区的特定位置<br />
要使用 -data 命令行自变量，只要将 -data your_workspace_location（例如，-data c:\users\robert\myworkspace）添加至快捷方式属性中的目标字段或显式地将它包括在命令行上。</p>
<p>使用 -vm 设置 java VM<br />
建议显式指定在运行 Eclipse 时要使用哪个 Java VM。使用 -vm 命令行自变量（例如，-vm c:\jre\bin\javaw.exe）可以实现此目的。如果不使用 -vm，则 Eclipse 将使用在 O/S 路径上找到的一个 Java VM。当安装其它产品时，它们可更改您的路径，导致在下一次启动 Eclipse 时使用另一 Java VM。</p>
<p>运行 Eclipse 中的高级主题<br />
Eclipse 可执行文件及平台本身提供了人们感兴趣的开发或调试 Eclipse 各部件的许多执行选项。运行 Eclipse 可执行文件的一般格式是：</p>
<p>eclipse [platform options] [-vmargs [Java VM arguments]]<br />
Eclipse 启动参数 命令 描述 原因 <br />
-arch architecture<br />
定义 Eclipse 平台在其上运行的处理器体系结构。Eclipse 平台通常使用 Java os.arch 属性的常用值来计算最佳设置。如果在此处指定该项，则这是 Eclipse 平台使用的值。此处指定的值可作为 BootLoader.getOSArch() 用于插件。示例值有："x86"、"sparc"、"PA-RISC"和"ppc"。 2.0 <br />
-application applicationId<br />
要运行的应用程序。应用程序由向 org.eclipse.core.runtime.applications 扩展点提供扩展的插件来声明。通常不需要此自变量。如果指定了此项，则该值会覆盖配置提供的值。如果不指定此项，则会运行"Eclipse 工作台"。 1.0 <br />
-boot bootJarURL<br />
（建议不使用；用 -configuration 代替；支持 1.0 兼容）。Eclipse 平台的引导插件代码（boot.jar）的位置，表示为 URL。如果指定此项，则会用它来为装入 Eclipse 平台引导程序类装入器的类装入器设置类路径。仅当更改 startup.jar 和 boot.jar 的相对位置时才需要它。注意，不允许使用相对 URL。 *1.0 <br />
-classloaderproperties [file]<br />
如果指定的话，则使用给定位置处的类装入器属性文件来激活平台类类装入器增强。文件自变量可以是文件路径或 URL。注意，不允许使用相对 URL。单击此处以获得更多详细信息。 2.0.2 <br />
-configuration configurationFileURL<br />
Eclipse 平台配置文件的位置，表示为 URL。配置文件确定 Eclipse 平台、可用插件集和主要功能部件的位置。注意，不允许使用相对 URL。当安装或更新 Eclipse 平台时配置文件被写至此位置。 2.0 <br />
-consolelog<br />
将 Eclipse 平台的错误日志镜像到用来运行 Eclipse 的控制台。与 -debug 组合时很方便使用。 1.0 <br />
-data workspacePath<br />
要运行 Eclipse 平台的工作区的路径。工作区位置也是项目的缺省位置。相对于从中启动 eclipse 的目录来解释相对路径。 1.0 <br />
-debug [optionsFile]<br />
将平台置于调试方式，并从给定位置处的文件装入调试选项（如果指定的话）。此文件指示哪些调试点可用于插件以及是否已启用它们。如果未给出文件位置，则平 台在启动 eclipse 的目录中查找称为".options"的文件。URL 和文件系统路径都可作为文件位置。 1.0 <br />
-dev [classpathEntries]<br />
将平台置于开发方式。将可选类路径条目（用逗号分隔的列表）添加至每个插件的运行时类路径。例如，当工作区包含要开发的插件时，指定 -dev bin 会为每个插件项目的名为 bin 的目录添加类路径条目，允许在其中存储最新生成的类文件。除去了冗余或不存在的类路径条目。 1.0 <br />
-endsplash params<br />
用于在 Eclipse 平台启动并运行时关闭闪屏的内部选项。此选项在闪屏处理链中不同的位置有不同的语法和语义。 2.0 <br />
-feature featureId<br />
主要功能部件的标识。主要功能部件为 Eclipse 的已启动实例提供了产品个性，并确定使用的产品定制信息。 2.0 <br />
-keyring keyringFilePath<br />
磁盘上授权数据库（或"密钥环"文件）的位置。此自变量必须与 -password 选项配合使用。相对于从中启动 eclipse 的目录来解释相对路径。 1.0 <br />
-nl local</p>
<p>本文来自CSDN博客，转载请标明出处：http://blog.csdn.net/JefferyLee/articles/1760821.aspx</p>
<img src ="http://www.blogjava.net/nogocn/aggbug/297532.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nogocn/" target="_blank">NG</a> 2009-10-09 14:24 <a href="http://www.blogjava.net/nogocn/archive/2009/10/09/297532.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA得到网卡物理地址(windows和Linux)</title><link>http://www.blogjava.net/nogocn/archive/2009/09/14/294971.html</link><dc:creator>NG</dc:creator><author>NG</author><pubDate>Mon, 14 Sep 2009 02:00:00 GMT</pubDate><guid>http://www.blogjava.net/nogocn/archive/2009/09/14/294971.html</guid><wfw:comment>http://www.blogjava.net/nogocn/comments/294971.html</wfw:comment><comments>http://www.blogjava.net/nogocn/archive/2009/09/14/294971.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nogocn/comments/commentRss/294971.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nogocn/services/trackbacks/294971.html</trackback:ping><description><![CDATA[<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">.&nbsp;</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;java.io.BufferedReader;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;">.&nbsp;</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;java.io.IOException;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">3</span><span style="color: #000000;">.&nbsp;</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;java.io.InputStreamReader;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">4</span><span style="color: #000000;">.&nbsp;</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;java.util.Properties;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">5</span><span style="color: #000000;">.&nbsp;</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;java.util.logging.Level;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">6</span><span style="color: #000000;">.&nbsp;</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;java.util.logging.Logger;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">7</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">8</span><span style="color: #000000;">.&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Test&nbsp;{&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">9</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">10</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;String&nbsp;getMACAddress()&nbsp;{&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">11</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">12</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;address&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">""</span><span style="color: #000000;">;&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">13</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;os&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;System.getProperty(</span><span style="color: #000000;">"</span><span style="color: #000000;">os.name</span><span style="color: #000000;">"</span><span style="color: #000000;">);&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">14</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(os);&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">15</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(os&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">)&nbsp;{&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">16</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(os.startsWith(</span><span style="color: #000000;">"</span><span style="color: #000000;">Windows</span><span style="color: #000000;">"</span><span style="color: #000000;">))&nbsp;{&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">17</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;">&nbsp;{&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">18</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ProcessBuilder&nbsp;pb&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;ProcessBuilder(</span><span style="color: #000000;">"</span><span style="color: #000000;">ipconfig</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">/all</span><span style="color: #000000;">"</span><span style="color: #000000;">);&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">19</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Process&nbsp;p&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;pb.start();&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">20</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BufferedReader&nbsp;br&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;BufferedReader(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;InputStreamReader(p.getInputStream()));&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">21</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;line;&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">22</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;((line&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;br.readLine())&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">)&nbsp;{&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">23</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(line.indexOf(</span><span style="color: #000000;">"</span><span style="color: #000000;">Physical&nbsp;Address</span><span style="color: #000000;">"</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">)&nbsp;{&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">24</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;index&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;line.indexOf(</span><span style="color: #000000;">"</span><span style="color: #000000;">:</span><span style="color: #000000;">"</span><span style="color: #000000;">);&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">25</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;address&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;line.substring(index&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">);&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">26</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">break</span><span style="color: #000000;">;&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">27</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">28</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">29</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;br.close();&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">30</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;address.trim();&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">31</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;(IOException&nbsp;e)&nbsp;{&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">32</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">33</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">34</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><span style="color: #0000ff;">else</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(os.startsWith(</span><span style="color: #000000;">"</span><span style="color: #000000;">Linux</span><span style="color: #000000;">"</span><span style="color: #000000;">)){&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">35</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;">&nbsp;{&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">36</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ProcessBuilder&nbsp;pb&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;ProcessBuilder(</span><span style="color: #000000;">"</span><span style="color: #000000;">ifconfig</span><span style="color: #000000;">"</span><span style="color: #000000;">);&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">37</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Process&nbsp;p&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;pb.start();&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">38</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BufferedReader&nbsp;br&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;BufferedReader(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;InputStreamReader(p.getInputStream()));&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">39</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;line;&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">40</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">((line</span><span style="color: #000000;">=</span><span style="color: #000000;">br.readLine())</span><span style="color: #000000;">!=</span><span style="color: #0000ff;">null</span><span style="color: #000000;">){&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">41</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;index</span><span style="color: #000000;">=</span><span style="color: #000000;">line.indexOf(</span><span style="color: #000000;">"</span><span style="color: #000000;">硬件地址</span><span style="color: #000000;">"</span><span style="color: #000000;">);&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">42</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(index</span><span style="color: #000000;">!=-</span><span style="color: #000000;">1</span><span style="color: #000000;">){&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">43</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;address</span><span style="color: #000000;">=</span><span style="color: #000000;">line.substring(index</span><span style="color: #000000;">+</span><span style="color: #000000;">4</span><span style="color: #000000;">);&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">44</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">break</span><span style="color: #000000;">;&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">45</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">46</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">47</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;br.close();&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">48</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;address.trim();&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">49</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;(IOException&nbsp;ex)&nbsp;{&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">50</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Logger.getLogger(Test.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">.getName()).log(Level.SEVERE,&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">,&nbsp;ex);&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">51</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">52</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">53</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">54</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">55</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;address;&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">56</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">57</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">58</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;main(String[]&nbsp;args)&nbsp;{&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">59</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">""</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;Test.getMACAddress());&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">60</span><span style="color: #000000;">.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #000000;">61</span><span style="color: #000000;">.&nbsp;}&nbsp; <br />
</span></div>
<img src ="http://www.blogjava.net/nogocn/aggbug/294971.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nogocn/" target="_blank">NG</a> 2009-09-14 10:00 <a href="http://www.blogjava.net/nogocn/archive/2009/09/14/294971.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java获取CPU序列号和网卡Mac地址</title><link>http://www.blogjava.net/nogocn/archive/2009/09/14/294969.html</link><dc:creator>NG</dc:creator><author>NG</author><pubDate>Mon, 14 Sep 2009 01:51:00 GMT</pubDate><guid>http://www.blogjava.net/nogocn/archive/2009/09/14/294969.html</guid><wfw:comment>http://www.blogjava.net/nogocn/comments/294969.html</wfw:comment><comments>http://www.blogjava.net/nogocn/archive/2009/09/14/294969.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nogocn/comments/commentRss/294969.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nogocn/services/trackbacks/294969.html</trackback:ping><description><![CDATA[//Java获得CPU序列号和网卡Mac地址<br />
/*<br />
利用Runtime
call操作系统的命令，具体的命令取决于不同的操作系统，注意不要调用Runtime.getRuntime().exec(String)接口，要用Runtime.getRuntime().exec(String[])这个接口，不然复杂命令的执行会有问题。例子如下（拿cpu个数，其他类似）：<br />
定义命令：<br />
WindowsCmd
="cmd.exe /c echo %NUMBER_OF_PROCESSORS%";//windows的特殊<br />
SolarisCmd =
{"/bin/sh", "-c", "/usr/sbin/psrinfo | wc -l"};<br />
AIXCmd = {"/bin/sh", "-c",
"/usr/sbin/lsdev -Cc processor | wc -l"};<br />
HPUXCmd = {"/bin/sh", "-c", "echo
\"map\" | /usr/sbin/cstm | grep CPU | wc -l "};<br />
LinuxCmd = {"/bin/sh", "-c",
"cat /proc/cpuinfo | grep ^process | wc -l"};<br />
<br />
然后判断系统：<br />
os =
System.getProperty("os.name").toLowerCase();<br />
<br />
根据不同的操作系统call不同的命令。<br />
*/<br />
import
java.io.IOException;<br />
import java.io.InputStream;<br />
import
java.io.InputStreamReader;<br />
import java.io.LineNumberReader;<br />
<br />
public
class GetMACAddress<br />
{<br />
public String getMACAddress(String
ipAddress)<br />
{<br />
String str = "",strMAC = "",macAddress =
"";<br />
try<br />
{<br />
Process pp = Runtime.getRuntime().exec("nbtstat -a " +
ipAddress);<br />
InputStreamReader ir = new
InputStreamReader(pp.getInputStream());<br />
LineNumberReader input = new
LineNumberReader(ir);<br />
for(int i = 1;i &lt; 100;i++)<br />
{<br />
str =
input.readLine();<br />
if(str != null)<br />
{<br />
if(str.indexOf("MAC Address") &gt;
1)<br />
{<br />
strMAC = str.substring(str.indexOf("MAC Address") +
14,str.length());<br />
break;<br />
}<br />
}<br />
}<br />
}<br />
catch(IOException
ex)<br />
{<br />
return "Can't Get MAC Address!";<br />
}<br />
//<br />
if(strMAC.length()
&lt; 17)<br />
{<br />
return "Error!";<br />
}<br />
macAddress = strMAC.substring(0,2) +
":"<br />
+ strMAC.substring(3,5) + ":"<br />
+ strMAC.substring(6,8) + ":"<br />
+
strMAC.substring(9,11) + ":"<br />
+ strMAC.substring(12,14) + ":"<br />
+
strMAC.substring(15,17);<br />
//<br />
return macAddress;<br />
}<br />
<br />
public static
void main(String[] args)<br />
{<br />
GetMACAddress getMACAddress = new
GetMACAddress();<br />
System.out.println(getMACAddress.getMACAddress("172.18.8.225"));<br />
<br />
try<br />
{<br />
java.lang.Process
proc = Runtime.getRuntime().exec("ipconfig /all");<br />
InputStream istr =
proc.getInputStream();<br />
byte[] data = new
byte[1024];<br />
istr.read(data);<br />
String netdata = new
String(data);<br />
System.out.println("Your Mac Address=" +
procAll(netdata));<br />
}<br />
catch(IOException
e)<br />
{<br />
System.out.println("error=" + e);<br />
}<br />
}<br />
<br />
public static
String procAll(String str)<br />
{<br />
return
procStringEnd(procFirstMac(procAddress(str)));<br />
}<br />
<br />
public static String
procAddress(String str)<br />
{<br />
int indexof = str.indexOf("Physical
Address");<br />
if(indexof &gt; 0)<br />
{<br />
return
str.substring(indexof,str.length());<br />
}<br />
return str;<br />
}<br />
<br />
public
static String procFirstMac(String str)<br />
{<br />
int indexof =
str.indexOf(":");<br />
if(indexof &gt; 0)<br />
{<br />
return str.substring(indexof +
1,str.length()).trim();<br />
}<br />
return str;<br />
}<br />
<br />
public static String
procStringEnd(String str)<br />
{<br />
int indexof = str.indexOf("\r");<br />
if(indexof
&gt; 0)<br />
{<br />
return str.substring(0,indexof).trim();<br />
}<br />
return
str;<br />
}<br />
}<br />
<br />
<br />
<br />
import java.util.Vector;<br />
<br />
class
GetNetMAC<br />
{<br />
//网卡物理地址长度<br />
static private final int _physicalLength =
16;<br />
<br />
public static void main(String[] args)<br />
{<br />
//output you computer
phycail ip address<br />
System.out.println("The MAC Addressis:\t" +
getPhysicalAddress());<br />
}<br />
<br />
static public String
getPhysicalAddress()<br />
{<br />
GetNetMACShell shell = new
GetNetMACShell();<br />
String cmd = "cmd.exe /c ipconfig/all";<br />
Vector
result;<br />
result = shell.execute(cmd);<br />
return
parseCmd(result.toString());<br />
}<br />
<br />
//从字符串中解析出所需要获得的字符串<br />
static private
String parseCmd(String s)<br />
{<br />
String find = "Physical Address. . . . . . . .
. :";<br />
int findIndex = s.indexOf(find);<br />
if(findIndex == -1)<br />
{<br />
return
"not find";<br />
}<br />
else<br />
{<br />
return s.substring(findIndex + find.length() +
1,findIndex + find.length() + 1 +
_physicalLength);<br />
}<br />
}<br />
}<br />
<br />
<br />
<br />
<img src ="http://www.blogjava.net/nogocn/aggbug/294969.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nogocn/" target="_blank">NG</a> 2009-09-14 09:51 <a href="http://www.blogjava.net/nogocn/archive/2009/09/14/294969.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Dom4j的使用(全而好的文章)</title><link>http://www.blogjava.net/nogocn/archive/2009/08/31/293303.html</link><dc:creator>NG</dc:creator><author>NG</author><pubDate>Mon, 31 Aug 2009 05:49:00 GMT</pubDate><guid>http://www.blogjava.net/nogocn/archive/2009/08/31/293303.html</guid><wfw:comment>http://www.blogjava.net/nogocn/comments/293303.html</wfw:comment><comments>http://www.blogjava.net/nogocn/archive/2009/08/31/293303.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nogocn/comments/commentRss/293303.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nogocn/services/trackbacks/293303.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 关键字: dom4jDom4j 使用简介作者：冰云 icecloud(AT)sina.com时间：2003.12.15                                    &nbsp;            版权声明：            本文由冰云完成，首发于CSDN，未经许可，不得使用于任何商业用途。           ...&nbsp;&nbsp;<a href='http://www.blogjava.net/nogocn/archive/2009/08/31/293303.html'>阅读全文</a><img src ="http://www.blogjava.net/nogocn/aggbug/293303.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nogocn/" target="_blank">NG</a> 2009-08-31 13:49 <a href="http://www.blogjava.net/nogocn/archive/2009/08/31/293303.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用反射机制动态将XML信息设置入对象</title><link>http://www.blogjava.net/nogocn/archive/2009/08/31/293258.html</link><dc:creator>NG</dc:creator><author>NG</author><pubDate>Mon, 31 Aug 2009 01:23:00 GMT</pubDate><guid>http://www.blogjava.net/nogocn/archive/2009/08/31/293258.html</guid><wfw:comment>http://www.blogjava.net/nogocn/comments/293258.html</wfw:comment><comments>http://www.blogjava.net/nogocn/archive/2009/08/31/293258.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nogocn/comments/commentRss/293258.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nogocn/services/trackbacks/293258.html</trackback:ping><description><![CDATA[引言：XML和J2EE密切的程度是不用说的了，由于我们的接口程序需要将别人发过来的XML文档信息进行处理，并持久化到数据库中。由于业务的不同，xml的格式也有所不同，不过执行的过程都是类似的，我们获得xml字符串信息并解析我们需要的信息，将这些信息持久化就ok了，这里存在的问题是随着业务的不同，xml格式不同需要将xml中的信息首先保存到不同的vo中，然后将vo持久化。这样反射机制就起了很大的作用。 <br />
<br />
1. 主函数 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://verran.javaeye.com/blog/146176#"><img alt="复制代码" src="http://verran.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;main(String[]&nbsp;args)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;TODO&nbsp;Auto-generated&nbsp;method&nbsp;stub </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PaserXML&nbsp;p=</span><span class="keyword">new</span><span>&nbsp;PaserXML(); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;xml=</span><span class="string">"&lt;?xml&nbsp;version='1.0'&nbsp;encoding='UTF-8'?&gt;&nbsp;&lt;root&gt;&lt;Customer&gt;&lt;id&gt;1&lt;/id&gt;&lt;name&gt;ddd&lt;/name&gt;&lt;/Customer&gt;"</span><span>+ &nbsp;&nbsp;</span></span></li>
    <li><span class="string">"&lt;order&gt;&lt;orderId&gt;2&lt;/orderId&gt;&lt;orderName&gt;nnmnmnmn&lt;/orderName&gt;&lt;/order&gt;&lt;/root&gt;"</span><span>; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p.parserByXpath2(xml); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">	public static void main(String[] args) {
// TODO Auto-generated method stub
PaserXML p=new PaserXML();
String xml="&lt;?xml version='1.0' encoding='UTF-8'?&gt; &lt;root&gt;&lt;Customer&gt;&lt;id&gt;1&lt;/id&gt;&lt;name&gt;ddd&lt;/name&gt;&lt;/Customer&gt;"+
"&lt;order&gt;&lt;orderId&gt;2&lt;/orderId&gt;&lt;orderName&gt;nnmnmnmn&lt;/orderName&gt;&lt;/order&gt;&lt;/root&gt;";
p.parserByXpath2(xml);
}
</pre>
<br />
<br />
2. 利用XPath获得节点信息 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://verran.javaeye.com/blog/146176#"><img alt="复制代码" src="http://verran.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span class="comment">/** </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;&nbsp;利用反射机制实现的&nbsp;将xml中的相关信息付给Vo </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;&nbsp;输入：String&nbsp;XML </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;&nbsp;返回：&nbsp;void </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;&nbsp;执行中---将XML数据&nbsp;付给对应的VO&nbsp;:这里需要对命名进行规范 </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;*/</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;parserByXpath2(String&nbsp;xml){ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Reader&nbsp;in=</span><span class="keyword">new</span><span>&nbsp;StringReader(xml); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Document&nbsp;document=builder.build(in); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Element&nbsp;root=document.getRootElement(); &nbsp;&nbsp;</span></li>
    <li><span>/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(root.getName()); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Element&nbsp;o=(Element)org.jdom.xpath.XPath.selectSingleNode(root,&nbsp;</span><span class="string">"/root/order"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OrderVO&nbsp;vo=</span><span class="keyword">new</span><span>&nbsp;OrderVO(); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">this</span><span>.ElementTOVO(o,&nbsp;vo);</span><span class="comment">//真正执行将通过Xpath解析出来的节点下的&nbsp;信息&nbsp;&nbsp;付给&nbsp;VO </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span class="string">"vo.getOrderId()"</span><span>+vo.getOrderId()); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span class="string">"vo.getOrderName()"</span><span>+vo.getOrderName()); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>&nbsp;(JDOMException&nbsp;e)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;TODO&nbsp;Auto-generated&nbsp;catch&nbsp;block </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace(); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>&nbsp;(IOException&nbsp;e)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;TODO&nbsp;Auto-generated&nbsp;catch&nbsp;block </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace(); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">	/**
*  利用反射机制实现的 将xml中的相关信息付给Vo
*  输入：String XML
*  返回： void
*  执行中---将XML数据 付给对应的VO :这里需要对命名进行规范
* */
public void parserByXpath2(String xml){
try {
Reader in=new StringReader(xml);
Document document=builder.build(in);
Element root=document.getRootElement();
//				System.out.println(root.getName());
Element o=(Element)org.jdom.xpath.XPath.selectSingleNode(root, "/root/order");
OrderVO vo=new OrderVO();
this.ElementTOVO(o, vo);//真正执行将通过Xpath解析出来的节点下的 信息  付给 VO
System.out.println("vo.getOrderId()"+vo.getOrderId());
System.out.println("vo.getOrderName()"+vo.getOrderName());
} catch (JDOMException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
</pre>
<br />
<br />
3. 反射机制实现set方法的动态调用 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://verran.javaeye.com/blog/146176#"><img alt="复制代码" src="http://verran.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span class="comment">/** </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;输入：&nbsp;Element&nbsp;利用Xpath解析出来要做处理的&nbsp;Docuemnt&nbsp;文档树中的阶段信息 </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;输出：&nbsp;Void </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;思路：&nbsp;读取XML文件中要做处理的值信息，将值赋给相应的VO的字段，这里需要调用其set方法实现 </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;由于不同的VO会有不同数量，不同值得字段和set方法，这里采用反射机制. </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;*/</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;ElementTOVO(Element&nbsp;e,Object&nbsp;vo){ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class&nbsp;clazz=vo.getClass(); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Field&nbsp;fd=</span><span class="keyword">null</span><span>; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Method&nbsp;m=</span><span class="keyword">null</span><span>; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class&nbsp;fType=</span><span class="keyword">null</span><span>; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;fName=</span><span class="string">""</span><span>; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Element&nbsp;element=</span><span class="keyword">null</span><span>; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;xmlValue=</span><span class="string">""</span><span>; &nbsp;&nbsp;</span></span></li>
    <li><span>java.lang.reflect.Method[]&nbsp;method=clazz.getDeclaredMethods();</span><span class="comment">//获得所有的声明方法 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;java.lang.reflect.Field[]&nbsp;field=clazz.getDeclaredFields();</span><span class="comment">//获得所有的声明字段 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">for</span><span>(</span><span class="keyword">int</span><span>&nbsp;i=</span><span class="number">0</span><span>;i&lt;field.length;i++){ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fd=field[i]; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fName=fd.getName();</span><span class="comment">//&nbsp;获得字段的名称 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fType=fd.getType();</span><span class="comment">//&nbsp;获得字段的类型 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>(</span><span class="string">"java.lang.String"</span><span>.equals(fType.getName())){</span><span class="comment">//判断字段类型是否为String型，由于这里需要利用反射机制调用方法而且为了统一实现 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//将VO中的字段都定义为String&nbsp;型 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;element=e.getChild(fName);</span><span class="comment">//获得e（即传过来的Element）下的制定名称的Element&nbsp;fName&nbsp; </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>(element==</span><span class="keyword">null</span><span>){ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xmlValue=</span><span class="keyword">null</span><span>; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">else</span><span>{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xmlValue=element.getValue();</span><span class="comment">//获得指定元素下的值信息 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fName=fName.substring(</span><span class="number">0</span><span>,</span><span class="number">1</span><span>).toUpperCase()+fName.substring(</span><span class="number">1</span><span>,fName.length());</span><span class="comment">//由于属性名第一个字母为小写 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//为了调用set方法，将第一个字母大写&nbsp;以便构造set方法名。&nbsp;比如&nbsp;orderId---&gt;OrderId----&gt;setOrderId </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>(fName!=</span><span class="keyword">null</span><span>){</span><span class="comment">//如果方法名存在 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m=clazz.getMethod(</span><span class="string">"set"</span><span>+fName,&nbsp;</span><span class="keyword">new</span><span>&nbsp;Class[]{fType});</span><span class="comment">//通过方法名获得&nbsp;指定的方法参数类型&nbsp;比如String </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//第一个参数指定要调用方法的名称、第二个指定调用方法的参数类型 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>&nbsp;(SecurityException&nbsp;e1)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;TODO&nbsp;Auto-generated&nbsp;catch&nbsp;block </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e1.printStackTrace(); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>&nbsp;(NoSuchMethodException&nbsp;e1)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;TODO&nbsp;Auto-generated&nbsp;catch&nbsp;block </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e1.printStackTrace(); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>(xmlValue!=</span><span class="keyword">null</span><span>){ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(xmlValue); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m.invoke(vo,&nbsp;</span><span class="keyword">new</span><span>&nbsp;Object[]{xmlValue});</span><span class="comment">//调用动态生成的方法 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//参数一指定方法所在的类，参数二制定&nbsp;参数的值 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>&nbsp;(IllegalArgumentException&nbsp;e1)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;TODO&nbsp;Auto-generated&nbsp;catch&nbsp;block </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e1.printStackTrace(); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>&nbsp;(IllegalAccessException&nbsp;e1)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;TODO&nbsp;Auto-generated&nbsp;catch&nbsp;block </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e1.printStackTrace(); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>&nbsp;(InvocationTargetException&nbsp;e1)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;TODO&nbsp;Auto-generated&nbsp;catch&nbsp;block </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e1.printStackTrace(); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
</ol>
</div>
<img src ="http://www.blogjava.net/nogocn/aggbug/293258.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nogocn/" target="_blank">NG</a> 2009-08-31 09:23 <a href="http://www.blogjava.net/nogocn/archive/2009/08/31/293258.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WebWork2.2工作原理总结</title><link>http://www.blogjava.net/nogocn/archive/2009/07/08/285921.html</link><dc:creator>NG</dc:creator><author>NG</author><pubDate>Wed, 08 Jul 2009 03:09:00 GMT</pubDate><guid>http://www.blogjava.net/nogocn/archive/2009/07/08/285921.html</guid><wfw:comment>http://www.blogjava.net/nogocn/comments/285921.html</wfw:comment><comments>http://www.blogjava.net/nogocn/archive/2009/07/08/285921.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nogocn/comments/commentRss/285921.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nogocn/services/trackbacks/285921.html</trackback:ping><description><![CDATA[<div style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt; line-height: 150%"><span>一、</span>WebWork的框架初始化过程</div>
<div style="margin: 0cm 0cm 0pt 21pt; line-height: 150%">利用WebWork做的项目，在服务器启动时完成WebWork的框架初始化。具体是通过</div>
<div style="line-height: 150%">Web.xml中配置好的FilterDispatcher过滤器中的init(FilterConfig filterConfig)方法完成。</div>
<div style="line-height: 150%">并且web.xml中配置好FilterDispatcher的映射，当用户用映射好的结尾资源请求浏览器时，FillterDispather会进行请求处理.</div>
<div style="line-height: 150%"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>具体实现是通过以下步骤：</div>
<div style="margin: 0cm 0cm 0pt 36.75pt; text-indent: -21.75pt; line-height: 150%"><span style="line-height: 150%">1、<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal"><font size="3">&nbsp;&nbsp;&nbsp; </font></span></span>通过<span style="font-size: 10pt; background: silver 0% 50%; color: black; line-height: 150%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">FilterDispatcher</span><span style="font-size: 10pt; color: black; line-height: 150%">中的</span></div>
<div style="margin: 0cm 0cm 0pt 15pt; line-height: 150%"><span style="font-size: 10pt; color: black; line-height: 150%">public void init(FilterConfig filterConfig) throws ServletException</span><span style="font-size: 10pt; color: black; line-height: 150%">方法，进行框架的初始化</span></div>
<div style="margin: 0cm 0cm 0pt 36.75pt; text-indent: -21.75pt; line-height: 150%"><span style="line-height: 150%">2、<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp; </span></span><span style="font-size: 10pt; color: black; line-height: 150%">Init</span><span style="font-size: 10pt; color: black; line-height: 150%">方法又同过调用</span><span style="font-size: 10pt; background: silver 0% 50%; color: black; line-height: 150%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">DispatcherUtils</span><span style="font-size: 10pt; color: black; line-height: 150%">类的</span></div>
<div style="margin: 0cm 0cm 0pt 15pt; line-height: 150%"><span style="font-size: 10pt; color: black; line-height: 150%">public static void initialize(ServletContext servletContext)</span><span style="font-size: 10pt; color: black; line-height: 150%">方法创建</span></div>
<div style="text-indent: 15pt; line-height: 150%"><span style="font-size: 10pt; background: silver 0% 50%; color: black; line-height: 150%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">DispatcherUtils</span><span style="font-size: 10pt; color: black; line-height: 150%">实例，同时间接调用</span><span style="font-size: 10pt; background: silver 0% 50%; color: black; line-height: 150%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">DispatcherUtils</span><span style="font-size: 10pt; background: silver 0% 50%; color: black; line-height: 150%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">类的</span></div>
<div style="text-indent: 15pt; line-height: 150%"><span style="font-size: 10pt; color: black; line-height: 150%">protected void init(ServletContext servletContext)</span><span style="font-size: 9pt; line-height: 150%">方法初始化</span><span style="font-size: 9pt; line-height: 150%">Configuration</span></div>
<div style="text-indent: 13.5pt; line-height: 150%"><span style="font-size: 9pt; line-height: 150%">配置，创建对象创建的工厂</span><span style="font-size: 9pt; line-height: 150%">ObjectFactory</span><span style="font-size: 9pt; line-height: 150%">和</span><span style="font-size: 9pt; line-height: 150%">ObjectTypeDeterminer</span><span style="font-size: 9pt; line-height: 150%">。</span></div>
<div style="line-height: 150%"><span style="font-size: 10pt; color: black; line-height: 150%">至此完成</span><span style="font-size: 10pt; color: black; line-height: 150%">WebWork</span><span style="font-size: 10pt; color: black; line-height: 150%">框架的初始化。</span></div>
<div style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt; line-height: 150%"><span>二、</span>WebWork的用户请求处理过程</div>
<div style="margin: 0cm 0cm 0pt 21pt; line-height: 150%">所有以web.xml中映射FilterDispatcher结尾的服务请求将由FilterDispatcher进行处理。 1、从用户请求的服务名中解析出对应Action的名称。</div>
<div style="margin: 0cm 0cm 0pt 21pt; line-height: 150%"><span>&nbsp;&nbsp; </span>具体完成是：户按webwork规则请求时，服务器会调用FilterDispatcher的<span style="font-size: 10pt; background: silver 0% 50%; color: black; line-height: 150%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">doFilter</span><span style="font-size: 10pt; background: silver 0% 50%; color: black; line-height: 150%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">方法，完成第二步的内容。</span></div>
<div style="line-height: 150%"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2</span>、遍历 HttpServletRequest、HttpSession、ServletContext 中的数据，并将其复制到</div>
<div style="line-height: 150%" align="left">Webwork的Map中，为下一步创建Action事例打下基础。</div>
<div style="text-indent: 21pt; line-height: 150%" align="left">具体完成是：过调用DispatcherUtils的<span style="font-size: 10pt; background: silver 0% 50%; color: black; line-height: 150%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">serviceAction</span><span style="font-size: 10pt; background: silver 0% 50%; color: black; line-height: 150%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">方法中的</span></div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; background: silver 0% 50%; color: black; line-height: 150%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">Map</span><span style="font-size: 10pt; color: black; line-height: 150%"> extraContext = createContextMap(request, response, mapping, context);</span><span style="font-size: 10pt; color: black; line-height: 150%">完成以上信息的封装。</span></div>
<div style="line-height: 150%"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3</span>、以上一步封装好的信息为参数，调用 ActionProxyFactory创建对应的 ActionProxy实例。ActionProxyFactory 将根据 Xwork 配置文件（xwork.xml）中的设定，创建ActionProxy实例，ActionProxy中包含了 Action的配置信息（包括 Action名称，对应实现类等等）。</div>
<div style="line-height: 150%"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>具体完成是：通过</div>
<div style="line-height: 150%">ActionProxy proxy = ActionProxyFactory.getFactory().createActionProxy(namespace, name, extraContext, true, false);//创建动态代理</div>
<div style="line-height: 150%"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10pt; background: silver 0% 50%; color: black; line-height: 150%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">DefaultActionProxyFactory</span><span style="font-size: 10pt; background: silver 0% 50%; color: black; line-height: 150%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">实现</span>ActionProxyFactory的createActionProxy方法，返回new DefaultActionProxy(namespace, actionName, extraContext, true, true)；</div>
<div style="line-height: 150%"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DefaultActionProxy</span>是对<span style="font-size: 10pt; background: silver 0% 50%; color: black; line-height: 150%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">ActionProxy</span><span style="font-size: 10pt; background: silver 0% 50%; color: black; line-height: 150%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">的默认实现，</span></div>
<div style="line-height: 150%"><span style="font-size: 10pt; color: black; line-height: 150%">通过</span>DefaultActionProxy类的DefaultActionProxy(namespace, actionName, extraContext, true, true)构造方法实例化DefaultActionProxy，同时得到用户请求的actionName及namespace，</div>
<div style="line-height: 150%" align="left">并通过</div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: rgb(0,0,192); line-height: 150%">config</span><span style="font-size: 10pt; color: black; line-height: 150%"> = ConfigurationManager.<em>getConfiguration</em>().getRuntimeConfiguration().getActionConfig(<span style="background: silver 0% 50%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">namespace</span>, actionName);</span></div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; background: silver 0% 50%; color: black; line-height: 150%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">ConfigurationManager</span><span style="font-size: 10pt; background: silver 0% 50%; color: black; line-height: 150%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">的</span></div>
<div style="line-height: 150%" align="left"><strong><span style="font-size: 10pt; color: rgb(127,0,85); line-height: 150%">public</span></strong><strong><span style="font-size: 10pt; color: rgb(127,0,85); line-height: 150%">static</span></strong><strong><span style="font-size: 10pt; color: rgb(127,0,85); line-height: 150%">synchronized</span></strong><span style="font-size: 10pt; color: black; line-height: 150%"> Configuration getConfiguration() {</span></div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: black; line-height: 150%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong><span style="font-size: 10pt; color: rgb(127,0,85); line-height: 150%">if</span></strong><span style="font-size: 10pt; color: black; line-height: 150%"> (</span><em><span style="font-size: 10pt; color: rgb(0,0,192); line-height: 150%">configurationInstance</span></em><span style="font-size: 10pt; color: black; line-height: 150%"> == </span><strong><span style="font-size: 10pt; color: rgb(127,0,85); line-height: 150%">null</span></strong><span style="font-size: 10pt; color: black; line-height: 150%">) {</span></div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: black; line-height: 150%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><em><span style="font-size: 10pt; color: rgb(0,0,192); line-height: 150%">configurationInstance</span></em><span style="font-size: 10pt; color: black; line-height: 150%"> = </span><strong><span style="font-size: 10pt; color: rgb(127,0,85); line-height: 150%">new</span></strong><span style="font-size: 10pt; color: black; line-height: 150%"> DefaultConfiguration();</span></div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: black; line-height: 150%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong><span style="font-size: 10pt; color: rgb(127,0,85); line-height: 150%">try</span></strong><span style="font-size: 10pt; color: black; line-height: 150%"> {</span></div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: black; line-height: 150%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><em><span style="font-size: 10pt; color: rgb(0,0,192); line-height: 150%">configurationInstance</span></em><span style="font-size: 10pt; color: black; line-height: 150%">.<span style="background: silver 0% 50%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">reload</span>();</span></div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: black; line-height: 150%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </span><strong><span style="font-size: 10pt; color: rgb(127,0,85); line-height: 150%">catch</span></strong><span style="font-size: 10pt; color: black; line-height: 150%"> (ConfigurationException e) {</span></div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: black; line-height: 150%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><em><span style="font-size: 10pt; color: rgb(0,0,192); line-height: 150%">configurationInstance</span></em><span style="font-size: 10pt; color: black; line-height: 150%"> = </span><strong><span style="font-size: 10pt; color: rgb(127,0,85); line-height: 150%">null</span></strong><span style="font-size: 10pt; color: black; line-height: 150%">;</span></div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: black; line-height: 150%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong><span style="font-size: 10pt; color: rgb(127,0,85); line-height: 150%">throw</span></strong><span style="font-size: 10pt; color: black; line-height: 150%"> e;</span></div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: black; line-height: 150%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: black; line-height: 150%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </span><strong><span style="font-size: 10pt; color: rgb(127,0,85); line-height: 150%">else</span></strong><span style="font-size: 10pt; color: black; line-height: 150%"> {</span></div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: black; line-height: 150%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <em>conditionalReload</em>();</span></div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: black; line-height: 150%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div style="line-height: 150%" align="left">&nbsp;</div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: black; line-height: 150%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong><span style="font-size: 10pt; color: rgb(127,0,85); line-height: 150%">return</span></strong><em><span style="font-size: 10pt; color: rgb(0,0,192); line-height: 150%">configurationInstance</span></em><span style="font-size: 10pt; color: black; line-height: 150%">;</span></div>
<div><span style="font-size: 10pt; color: black">}</span><span>&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div style="margin: 0cm 0cm 0pt 18pt; text-indent: -18pt"><span style="font-size: 9pt">1．<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp; </span></span>完成对xwork.xml（具体操作类是XmlConfigurationProvider）配置信息的读取。<span style="font-size: 9pt">获得与此次请求相关的</span><span style="font-size: 9pt">ActionConfig</span></div>
<div style="line-height: 150%">&nbsp;</div>
<div style="line-height: 150%"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4</span>、ActionProxy创建对应的Action实例，并根据配置进行一系列的处理程序。</div>
<div style="line-height: 150%"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>通过<span style="font-size: 10pt; background: silver 0% 50%; color: black; line-height: 150%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">DefaultActionProxy</span><span style="font-size: 10pt; background: silver 0% 50%; color: black; line-height: 150%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">类的</span></div>
<div style="line-height: 150%">invocation = ActionProxyFactory.getFactory().createActionInvocation(this, extraContext);</div>
<div>//<span style="font-size: 9pt">通过</span>createActionInvocation<span style="font-size: 9pt">方法创建动作调用类</span><span style="font-size: 9pt">ActionInvocation</span><span style="font-size: 9pt">，处理被</span><span style="font-size: 9pt">Action</span><span style="font-size: 9pt">调用的方法</span></div>
<div><strong><span style="font-size: 10pt; color: rgb(127,0,85)">private</span></strong><strong><span style="font-size: 10pt; color: rgb(127,0,85)">void</span></strong><span style="font-size: 10pt; color: black"> <span style="background: silver 0% 50%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">resolveMethod</span>() {</span></div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: black; line-height: 150%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10pt; color: rgb(63,127,95); line-height: 150%">// if the method is set to null, use the one from the configuration</span></div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: black; line-height: 150%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10pt; color: rgb(63,127,95); line-height: 150%">// if the one from the configuration is also null, use "execute"</span></div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: black; line-height: 150%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong><span style="font-size: 10pt; color: rgb(127,0,85); line-height: 150%">if</span></strong><span style="font-size: 10pt; color: black; line-height: 150%"> (!TextUtils.<em>stringSet</em>(</span><strong><span style="font-size: 10pt; color: rgb(127,0,85); line-height: 150%">this</span></strong><span style="font-size: 10pt; color: black; line-height: 150%">.</span><span style="font-size: 10pt; color: rgb(0,0,192); line-height: 150%">method</span><span style="font-size: 10pt; color: black; line-height: 150%">)) {</span></div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: black; line-height: 150%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong><span style="font-size: 10pt; color: rgb(127,0,85); line-height: 150%">this</span></strong><span style="font-size: 10pt; color: black; line-height: 150%">.</span><span style="font-size: 10pt; color: rgb(0,0,192); line-height: 150%">method</span><span style="font-size: 10pt; color: black; line-height: 150%"> = </span><span style="font-size: 10pt; color: rgb(0,0,192); line-height: 150%">config</span><span style="font-size: 10pt; color: black; line-height: 150%">.getMethodName();</span></div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: black; line-height: 150%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong><span style="font-size: 10pt; color: rgb(127,0,85); line-height: 150%">if</span></strong><span style="font-size: 10pt; color: black; line-height: 150%"> (!TextUtils.<em>stringSet</em>(</span><strong><span style="font-size: 10pt; color: rgb(127,0,85); line-height: 150%">this</span></strong><span style="font-size: 10pt; color: black; line-height: 150%">.</span><span style="font-size: 10pt; color: rgb(0,0,192); line-height: 150%">method</span><span style="font-size: 10pt; color: black; line-height: 150%">)) {</span></div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: black; line-height: 150%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong><span style="font-size: 10pt; color: rgb(127,0,85); line-height: 150%">this</span></strong><span style="font-size: 10pt; color: black; line-height: 150%">.</span><span style="font-size: 10pt; color: rgb(0,0,192); line-height: 150%">method</span><span style="font-size: 10pt; color: black; line-height: 150%"> = </span><span style="font-size: 10pt; color: rgb(42,0,255); line-height: 150%">"execute"</span><span style="font-size: 10pt; color: black; line-height: 150%">;</span></div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: black; line-height: 150%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: black; line-height: 150%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: black; line-height: 150%">}</span></div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: black; line-height: 150%">然后调用</span><span style="font-size: 10pt; color: black; line-height: 150%">DispatcherUtils</span><span style="font-size: 10pt; color: black; line-height: 150%">的</span><span style="font-size: 10pt; background: silver 0% 50%; color: black; line-height: 150%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">serviceAction</span><span style="font-size: 10pt; background: silver 0% 50%; color: black; line-height: 150%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">方法中的</span></div>
<div align="left"><strong><span style="font-size: 10pt; color: rgb(127,0,85)">if</span></strong><span style="font-size: 10pt; color: black"> (mapping.getResult() != </span><strong><span style="font-size: 10pt; color: rgb(127,0,85)">null</span></strong><span style="font-size: 10pt; color: black">) {</span></div>
<div align="left"><span style="font-size: 10pt; color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Result result = mapping.getResult();</span></div>
<div align="left"><span style="font-size: 10pt; color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result.execute(proxy.getInvocation());</span></div>
<div align="left"><span style="font-size: 10pt; color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </span><strong><span style="font-size: 10pt; color: rgb(127,0,85)">else</span></strong><span style="font-size: 10pt; color: black"> {</span></div>
<div align="left"><span style="font-size: 10pt; color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proxy.execute();</span></div>
<div><span style="font-size: 10pt; color: black">}</span></div>
<div style="line-height: 150%" align="left">&nbsp;</div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: black; line-height: 150%">完成用户的最终要执行的</span><span style="font-size: 10pt; color: black; line-height: 150%">action</span><span style="font-size: 10pt; color: black; line-height: 150%">方法。</span></div>
<div align="left"><strong><span style="font-size: 10pt; color: rgb(127,0,85)">public</span></strong><span style="font-size: 10pt; color: black"> String execute() </span><strong><span style="font-size: 10pt; color: rgb(127,0,85)">throws</span></strong><span style="font-size: 10pt; color: black"> Exception {</span></div>
<div align="left"><span style="font-size: 10pt; color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ActionContext nestedContext = ActionContext.<em>getContext</em>();</span></div>
<div align="left"><span style="font-size: 10pt; color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ActionContext.<em>setContext</em>(</span><span style="font-size: 10pt; color: rgb(0,0,192)">invocation</span><span style="font-size: 10pt; color: black">.getInvocationContext());</span></div>
<div align="left">&nbsp;</div>
<div align="left"><span style="font-size: 10pt; color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String retCode = </span><strong><span style="font-size: 10pt; color: rgb(127,0,85)">null</span></strong><span style="font-size: 10pt; color: black">;</span></div>
<div align="left">&nbsp;</div>
<div align="left"><span style="font-size: 10pt; color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong><span style="font-size: 10pt; color: rgb(127,0,85)">try</span></strong><span style="font-size: 10pt; color: black"> {</span></div>
<div align="left"><span style="font-size: 10pt; color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retCode = </span><span style="font-size: 10pt; color: rgb(0,0,192)">invocation</span><span style="font-size: 10pt; color: black">.invoke();</span></div>
<div align="left"><span style="font-size: 10pt; color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </span><strong><span style="font-size: 10pt; color: rgb(127,0,85)">finally</span></strong><span style="font-size: 10pt; color: black"> {</span></div>
<div align="left"><span style="font-size: 10pt; color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong><span style="font-size: 10pt; color: rgb(127,0,85)">if</span></strong><span style="font-size: 10pt; color: black"> (</span><span style="font-size: 10pt; color: rgb(0,0,192)">cleanupContext</span><span style="font-size: 10pt; color: black">) {</span></div>
<div align="left"><span style="font-size: 10pt; color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ActionContext.<em>setContext</em>(nestedContext);</span></div>
<div align="left"><span style="font-size: 10pt; color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div align="left"><span style="font-size: 10pt; color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div align="left">&nbsp;</div>
<div align="left"><span style="font-size: 10pt; color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong><span style="font-size: 10pt; color: rgb(127,0,85)">return</span></strong><span style="font-size: 10pt; color: black"> retCode;</span></div>
<div style="line-height: 150%" align="left"><span style="font-size: 10pt; color: black; line-height: 150%">&nbsp;&nbsp;&nbsp; }</span></div>
<div><span style="font-size: 10pt; color: black">最终</span><span style="font-size: 9pt">处理</span><span style="font-size: 9pt">ActionContext</span><span style="font-size: 9pt">对象</span></div>
<div><span style="font-size: 9pt">将</span><span style="font-size: 9pt">Action</span><span style="font-size: 9pt">调用提交给</span><span style="font-size: 9pt">ActionInvocation</span><span style="font-size: 9pt">处理</span></div>
<div style="line-height: 150%" align="left">&nbsp;</div>
<div style="line-height: 150%">三、WebWork的执行流程图</div>
<div style="line-height: 150%"><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'"><V:SHAPETYPE id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f">&nbsp;<img alt="" src="http://www.zhuoda.org/fck/UserFiles/Image/image002.jpg" /><V:STROKE joinstyle="miter"></V:STROKE><V:FORMULAS><V:F eqn="if lineDrawn pixelLineWidth 0"></V:F><V:F eqn="sum @0 1 0"></V:F><V:F eqn="sum 0 0 @1"></V:F><V:F eqn="prod @2 1 2"></V:F><V:F eqn="prod @3 21600 pixelWidth"></V:F><V:F eqn="prod @3 21600 pixelHeight"></V:F><V:F eqn="sum @0 0 1"></V:F><V:F eqn="prod @6 1 2"></V:F><V:F eqn="prod @7 21600 pixelWidth"></V:F><V:F eqn="sum @8 21600 0"></V:F><V:F eqn="prod @7 21600 pixelHeight"></V:F><V:F eqn="sum @10 21600 0"></V:F></V:FORMULAS><V:PATH o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"></V:PATH><O:LOCK v:ext="edit" aspectratio="t"></O:LOCK></V:SHAPETYPE></span></div>
<img src ="http://www.blogjava.net/nogocn/aggbug/285921.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nogocn/" target="_blank">NG</a> 2009-07-08 11:09 <a href="http://www.blogjava.net/nogocn/archive/2009/07/08/285921.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>忘记李刚，一步一步跟我学Struts2 —— OGNL，数据运转的催化剂 </title><link>http://www.blogjava.net/nogocn/archive/2009/07/08/285920.html</link><dc:creator>NG</dc:creator><author>NG</author><pubDate>Wed, 08 Jul 2009 03:07:00 GMT</pubDate><guid>http://www.blogjava.net/nogocn/archive/2009/07/08/285920.html</guid><wfw:comment>http://www.blogjava.net/nogocn/comments/285920.html</wfw:comment><comments>http://www.blogjava.net/nogocn/archive/2009/07/08/285920.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nogocn/comments/commentRss/285920.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nogocn/services/trackbacks/285920.html</trackback:ping><description><![CDATA[<h3 class="type_original" title="原创"><a href="http://downpour.javaeye.com/blog/308896"></a>&nbsp;</h3>
<strong>关键字: struts2 ognl valuestack</strong>
<div class="blog_content"><strong><span style="color: blue">专栏地址：</span><a href="http://www.javaeye.com/wiki/struts2/1353-ognl-catalyst-for-data-operation-in-struts2" target="_blank">http://www.javaeye.com/wiki/struts2/1353-ognl-catalyst-for-data-operation-in-struts2</a></strong> <br />
<br />
首先让我们花费1分钟的时间来简单思考一个问题，MVC这3者之间，到底是通过什么真正融合起来的？ <br />
<br />
有人说是Controller，因为它是核心控制器，没有Controller，MVC就无从谈起，失去了职责划分的原本初衷。也有人说是View，因为所有的需求都是页面驱动的，没有页面，就没有请求，没有请求，也谈不上控制器和数据模型。 <br />
<br />
<strong><span style="color: red">个人观点</span>：贯穿MVC模型之间起到粘合剂作用的是数据。数据在View层成为了展示的内容，而在Controller层，成为了操作的载体，所以数据是整个MVC的核心。</strong> <br />
<br />
<strong><span style="font-size: medium">流转的数据</span></strong> <br />
<br />
无论MVC三者之间的粘合剂到底是什么，数据在各个层次之间进行流转是一个不争的事实。而这种流转，也就会面临一些困境，这些困境，是由于数据在不同世界中的表现形式不同而造成的： <br />
<br />
<strong>1. 数据在页面上是一个扁平的，不带数据类型的字符串，无论你的数据结构有多复杂，数据类型有多丰富，到了展示的时候，全都一视同仁的成为字符串在页面上展现出来。</strong> <br />
<br />
<strong>2. 数据在Java世界中可以表现为丰富的数据结构和数据类型，你可以自行定义你喜欢的类，在类与类之间进行继承、嵌套。我们通常会把这种模型称之为复杂的对象树。</strong> <br />
<br />
此时，如果数据在页面和Java世界中互相流转传递，就会显得不匹配。所以也就引出了几个需要解决的问题： <br />
<br />
<strong>1. 当数据从View层传递到Controller层时，我们应该保证一个扁平而分散在各处的数据集合能以一定的规则设置到Java世界中的对象树中去。同时，能够聪明的进行由字符串类型到Java中各个类型的转化。</strong> <br />
<br />
<strong>2. 当数据从Controller层传递到View层时，我们应该保证在View层能够以某些简易的规则对对象树进行访问。同时，在一定程度上控制对象树中的数据的显示格式。</strong> <br />
<br />
如果我们稍微深入一些来思考这个问题，我们就会发现，解决数据由于表现形式的不同而发生流转不匹配的问题对我们来说其实并不陌生。同样的问题会发生在Java世界与数据库世界中，面对这种对象与关系模型的不匹配，我们采用的解决方法是使用ORM框架，例如Hibernate，iBatis等等。那么现在，在Web层同样也发生了不匹配，所以我们也需要使用一些工具来帮助我们解决问题。 <br />
<br />
在这里，我们主要讨论的，是数据从View层传递到Controller层时的解决方案，而数据从Controller层传递到View层的解决方案，我们将在Struts2的Result章节重点讨论。 <br />
<br />
<strong><span style="font-size: medium">OGNL —— 完美的催化剂</span></strong> <br />
<br />
为了解决数据从View层传递到Controller层时的不匹配性，Struts2采纳了XWork的OGNL方案。并且在OGNL的基础上，构建了OGNLValueStack的机制，从而比较完美的解决了数据流转中的不匹配性。 <br />
<br />
OGNL（Object Graph Navigation Language），是一种表达式语言。使用这种表达式语言，你可以通过某种表达式语法，存取Java对象树中的任意属性、调用Java对象树的方法、同时能够自动实现必要的类型转化。如果我们把表达式看做是一个带有语义的字符串，那么OGNL无疑成为了这个语义字符串与Java对象之间沟通的桥梁。 <br />
<br />
<strong>如何使用OGNL</strong> <br />
<br />
让我们先研究一下OGNL的API，他来自于Ognl的静态方法： <br />
<br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://downpour.javaeye.com/blog/308896#"><img alt="复制代码" src="http://downpour.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="comment">/** </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;Evaluates&nbsp;the&nbsp;given&nbsp;OGNL&nbsp;expression&nbsp;tree&nbsp;to&nbsp;extract&nbsp;a&nbsp;value&nbsp;from&nbsp;the&nbsp;given&nbsp;root </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;object.&nbsp;The&nbsp;default&nbsp;context&nbsp;is&nbsp;set&nbsp;for&nbsp;the&nbsp;given&nbsp;context&nbsp;and&nbsp;root&nbsp;via </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;&lt;CODE&gt;addDefaultContext()&lt;/CODE&gt;. </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;* </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@param&nbsp;tree&nbsp;the&nbsp;OGNL&nbsp;expression&nbsp;tree&nbsp;to&nbsp;evaluate,&nbsp;as&nbsp;returned&nbsp;by&nbsp;parseExpression() </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@param&nbsp;context&nbsp;the&nbsp;naming&nbsp;context&nbsp;for&nbsp;the&nbsp;evaluation </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@param&nbsp;root&nbsp;the&nbsp;root&nbsp;object&nbsp;for&nbsp;the&nbsp;OGNL&nbsp;expression </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@return&nbsp;the&nbsp;result&nbsp;of&nbsp;evaluating&nbsp;the&nbsp;expression </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@throws&nbsp;MethodFailedException&nbsp;if&nbsp;the&nbsp;expression&nbsp;called&nbsp;a&nbsp;method&nbsp;which&nbsp;failed </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@throws&nbsp;NoSuchPropertyException&nbsp;if&nbsp;the&nbsp;expression&nbsp;referred&nbsp;to&nbsp;a&nbsp;nonexistent&nbsp;property </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@throws&nbsp;InappropriateExpressionException&nbsp;if&nbsp;the&nbsp;expression&nbsp;can't&nbsp;be&nbsp;used&nbsp;in&nbsp;this&nbsp;context </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@throws&nbsp;OgnlException&nbsp;if&nbsp;there&nbsp;is&nbsp;a&nbsp;pathological&nbsp;environmental&nbsp;problem </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*/</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;Object&nbsp;getValue(&nbsp;Object&nbsp;tree,&nbsp;Map&nbsp;context,&nbsp;Object&nbsp;root&nbsp;)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;OgnlException; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="comment">/** </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;Evaluates&nbsp;the&nbsp;given&nbsp;OGNL&nbsp;expression&nbsp;tree&nbsp;to&nbsp;insert&nbsp;a&nbsp;value&nbsp;into&nbsp;the&nbsp;object&nbsp;graph </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;rooted&nbsp;at&nbsp;the&nbsp;given&nbsp;root&nbsp;object.&nbsp;&nbsp;The&nbsp;default&nbsp;context&nbsp;is&nbsp;set&nbsp;for&nbsp;the&nbsp;given </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;context&nbsp;and&nbsp;root&nbsp;via&nbsp;&lt;CODE&gt;addDefaultContext()&lt;/CODE&gt;. </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;* </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@param&nbsp;tree&nbsp;the&nbsp;OGNL&nbsp;expression&nbsp;tree&nbsp;to&nbsp;evaluate,&nbsp;as&nbsp;returned&nbsp;by&nbsp;parseExpression() </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@param&nbsp;context&nbsp;the&nbsp;naming&nbsp;context&nbsp;for&nbsp;the&nbsp;evaluation </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@param&nbsp;root&nbsp;the&nbsp;root&nbsp;object&nbsp;for&nbsp;the&nbsp;OGNL&nbsp;expression </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@param&nbsp;value&nbsp;the&nbsp;value&nbsp;to&nbsp;insert&nbsp;into&nbsp;the&nbsp;object&nbsp;graph </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@throws&nbsp;MethodFailedException&nbsp;if&nbsp;the&nbsp;expression&nbsp;called&nbsp;a&nbsp;method&nbsp;which&nbsp;failed </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@throws&nbsp;NoSuchPropertyException&nbsp;if&nbsp;the&nbsp;expression&nbsp;referred&nbsp;to&nbsp;a&nbsp;nonexistent&nbsp;property </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@throws&nbsp;InappropriateExpressionException&nbsp;if&nbsp;the&nbsp;expression&nbsp;can't&nbsp;be&nbsp;used&nbsp;in&nbsp;this&nbsp;context </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@throws&nbsp;OgnlException&nbsp;if&nbsp;there&nbsp;is&nbsp;a&nbsp;pathological&nbsp;environmental&nbsp;problem </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*/</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;setValue(&nbsp;Object&nbsp;tree,&nbsp;Map&nbsp;context,&nbsp;Object&nbsp;root,&nbsp;Object&nbsp;value&nbsp;)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;OgnlException&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">/**
* Evaluates the given OGNL expression tree to extract a value from the given root
* object. The default context is set for the given context and root via
* &lt;CODE&gt;addDefaultContext()&lt;/CODE&gt;.
*
* @param tree the OGNL expression tree to evaluate, as returned by parseExpression()
* @param context the naming context for the evaluation
* @param root the root object for the OGNL expression
* @return the result of evaluating the expression
* @throws MethodFailedException if the expression called a method which failed
* @throws NoSuchPropertyException if the expression referred to a nonexistent property
* @throws InappropriateExpressionException if the expression can't be used in this context
* @throws OgnlException if there is a pathological environmental problem
*/
public static Object getValue( Object tree, Map context, Object root ) throws OgnlException;
/**
* Evaluates the given OGNL expression tree to insert a value into the object graph
* rooted at the given root object.  The default context is set for the given
* context and root via &lt;CODE&gt;addDefaultContext()&lt;/CODE&gt;.
*
* @param tree the OGNL expression tree to evaluate, as returned by parseExpression()
* @param context the naming context for the evaluation
* @param root the root object for the OGNL expression
* @param value the value to insert into the object graph
* @throws MethodFailedException if the expression called a method which failed
* @throws NoSuchPropertyException if the expression referred to a nonexistent property
* @throws InappropriateExpressionException if the expression can't be used in this context
* @throws OgnlException if there is a pathological environmental problem
*/
public static void setValue( Object tree, Map context, Object root, Object value ) throws OgnlException
</pre>
<br />
<br />
我们可以看到，OGNL的API其实相当简单，你可以通过传递三个参数来实现OGNL的一切操作。而这三个参数，被我称为OGNL的三要素。 <br />
<br />
那么运用这个API，我们能干点什么呢？跑个测试看看结果： <br />
<br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://downpour.javaeye.com/blog/308896#"><img alt="复制代码" src="http://downpour.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="comment">/** </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@author&nbsp;Downpour </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*/</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;User&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;Integer&nbsp;id; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;String&nbsp;name; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;Department&nbsp;department&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;Department(); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;User()&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;setter&nbsp;and&nbsp;getters </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="comment">//========================================================================= </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="comment">/** </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@author&nbsp;Downpour </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*/</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;Department&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;Integer&nbsp;id; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;String&nbsp;name; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;Department()&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;setter&nbsp;and&nbsp;getters </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="comment">//========================================================================= </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="comment">/** </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@author&nbsp;Downpour </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*/</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;OGNLTestCase&nbsp;</span><span class="keyword">extends</span><span>&nbsp;TestCase&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/** </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp; </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@throws&nbsp;Exception </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="annotation">@SuppressWarnings</span><span>(</span><span class="string">"unchecked"</span><span>) &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="annotation">@Test</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;testGetValue()&nbsp;</span><span class="keyword">throws</span><span>&nbsp;Exception&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Create&nbsp;root&nbsp;object </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;User&nbsp;user&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;User(); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;user.setId(</span><span class="number">1</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;user.setName(</span><span class="string">"downpour"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Create&nbsp;context </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Map&nbsp;context&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;HashMap(); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;context.put(</span><span class="string">"introduction"</span><span>,</span><span class="string">"My&nbsp;name&nbsp;is&nbsp;"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Test&nbsp;to&nbsp;directly&nbsp;get&nbsp;value&nbsp;from&nbsp;root&nbsp;object,&nbsp;with&nbsp;no&nbsp;context </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;name&nbsp;=&nbsp;Ognl.getValue(Ognl.parseExpression(</span><span class="string">"name"</span><span>),&nbsp;user); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertEquals(</span><span class="string">"downpour"</span><span>,name); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Test&nbsp;to&nbsp;get&nbsp;value(parameter)&nbsp;from&nbsp;context </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;contextValue&nbsp;=&nbsp;Ognl.getValue(Ognl.parseExpression(</span><span class="string">"#introduction"</span><span>),&nbsp;context,&nbsp;user); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertEquals(</span><span class="string">"My&nbsp;name&nbsp;is&nbsp;"</span><span>,&nbsp;contextValue); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Test&nbsp;to&nbsp;get&nbsp;value&nbsp;and&nbsp;parameter&nbsp;from&nbsp;root&nbsp;object&nbsp;and&nbsp;context </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;hello&nbsp;=&nbsp;Ognl.getValue(Ognl.parseExpression(</span><span class="string">"#introduction&nbsp;+&nbsp;name"</span><span>),&nbsp;context,&nbsp;user); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertEquals(</span><span class="string">"My&nbsp;name&nbsp;is&nbsp;downpour"</span><span>,hello); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/** </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp; </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@throws&nbsp;Exception </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="annotation">@SuppressWarnings</span><span>(</span><span class="string">"unchecked"</span><span>) &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="annotation">@Test</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;testSetValue()&nbsp;</span><span class="keyword">throws</span><span>&nbsp;Exception&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Create&nbsp;root&nbsp;object </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;User&nbsp;user&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;User(); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;user.setId(</span><span class="number">1</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;user.setName(</span><span class="string">"downpour"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Set&nbsp;value&nbsp;according&nbsp;to&nbsp;the&nbsp;expression </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Ognl.setValue(</span><span class="string">"department.name"</span><span>,&nbsp;user,&nbsp;</span><span class="string">"dev"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertEquals(</span><span class="string">"dev"</span><span>,&nbsp;user.getDepartment().getName()); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">/**
* @author Downpour
*/
public class User {
private Integer id;
private String name;
private Department department = new Department();
public User() {
}
// setter and getters
}
//=========================================================================
/**
* @author Downpour
*/
public class Department {
private Integer id;
private String name;
public Department() {
}
// setter and getters
}
//=========================================================================
/**
* @author Downpour
*/
public class OGNLTestCase extends TestCase {
/**
*
* @throws Exception
*/
@SuppressWarnings("unchecked")
@Test
public void testGetValue() throws Exception {
// Create root object
User user = new User();
user.setId(1);
user.setName("downpour");
// Create context
Map context = new HashMap();
context.put("introduction","My name is ");
// Test to directly get value from root object, with no context
Object name = Ognl.getValue(Ognl.parseExpression("name"), user);
assertEquals("downpour",name);
// Test to get value(parameter) from context
Object contextValue = Ognl.getValue(Ognl.parseExpression("#introduction"), context, user);
assertEquals("My name is ", contextValue);
// Test to get value and parameter from root object and context
Object hello = Ognl.getValue(Ognl.parseExpression("#introduction + name"), context, user);
assertEquals("My name is downpour",hello);
}
/**
*
* @throws Exception
*/
@SuppressWarnings("unchecked")
@Test
public void testSetValue() throws Exception {
// Create root object
User user = new User();
user.setId(1);
user.setName("downpour");
// Set value according to the expression
Ognl.setValue("department.name", user, "dev");
assertEquals("dev", user.getDepartment().getName());
}
}
</pre>
<br />
<br />
我们可以看到，简单的API，就已经能够完成对各种对象树的读取和设值工作了。这也体现出OGNL的学习成本非常低。 <br />
<br />
在上面的测试用例中，需要特别强调进行区分的，是在针对不同内容进行取值或者设值时，OGNL表达式的不同。 <br />
<br />
<div class="quote_title">Struts2 Reference 写道</div>
<div class="quote_div">The framework uses a standard naming context to evaluate OGNL expressions. The top level object dealing with OGNL is a Map (usually referred as a context map or context). OGNL has a notion of there being a root (or default) object within the context. In expression, the properties of the root object can be referenced without any special "marker" notion. References to other objects are marked with a pound sign (#).</div>
<br />
<br />
上面这段内容摘自Struts2的Reference，我把这段话总结为以下2条规则： <br />
<br />
<strong>A） 针对根对象（Root Object）的操作，表达式是自根对象到被访问对象的某个链式操作的字符串表示。</strong> <br />
<strong>B） 针对上下文环境（Context）的操作，表达式是自上下文环境（Context）到被访问对象的某个链式操作的字符串表示，但是必须在这个字符串的前面加上#符号，以表示与访问根对象的区别。</strong> <br />
<br />
<br />
上面的这点区别咋看起来非常容易理解，不过一旦放到特定的环境中，就会显示出其重要性，它可以解释很多Struts2在页面展示上取值的各种复杂的表达式的现象。这一点在下一篇文章中会进行具体的分析。 <br />
<br />
<strong>OGNL三要素</strong> <br />
<br />
我把传入OGNL的API的三个参数，称之为OGNL的三要素。OGNL的操作实际上就是围绕着这三个参数而进行的。 <br />
<br />
1. 表达式（Expression） <br />
<br />
表达式是整个OGNL的核心，所有的OGNL操作都是针对表达式的解析后进行的。表达式会规定此次OGNL操作到底要<strong><span style="color: red">干什么</span></strong>。 <br />
<br />
我们可以看到，在上面的测试中，name、department.name等都是表达式，表示取name或者department中的name的值。OGNL支持很多类型的表达式，之后我们会看到更多。 <br />
<br />
2. 根对象（Root Object） <br />
<br />
根对象可以理解为OGNL的<strong><span style="color: red">操作对象</span></strong>。在表达式规定了&#8220;干什么&#8221;以后，你还需要指定到底<strong><span style="color: red">&#8220;对谁干&#8221;</span></strong>。 <br />
<br />
在上面的测试代码中，user就是根对象。这就意味着，我们需要对user这个对象去取name这个属性的值（对user这个对象去设置其中的department中的name属性值）。 <br />
<br />
3. 上下文环境（Context） <br />
<br />
有了表达式和根对象，我们实际上已经可以使用OGNL的基本功能。例如，根据表达式对根对象进行取值或者设值工作。 <br />
<br />
不过实际上，在OGNL的内部，所有的操作都会在一个特定的环境中运行，这个环境就是OGNL的上下文环境（Context）。说得再明白一些，就是这个上下文环境（Context），将规定OGNL的操作<strong><span style="color: red">&#8220;在哪里干&#8221;</span></strong>。 <br />
<br />
OGNL的上下文环境是一个Map结构，称之为OgnlContext。上面我们提到的根对象（Root Object），事实上也会被加入到上下文环境中去，并且这将作为一个特殊的变量进行处理，具体就表现为针对根对象（Root Object）的存取操作的表达式是不需要增加#符号进行区分的。 <br />
<br />
OgnlContext不仅提供了OGNL的运行环境。在这其中，我们还能设置一些自定义的parameter到Context中，以便我们在进行OGNL操作的时候能够方便的使用这些parameter。不过正如我们上面反复强调的，我们在访问这些parameter时，需要使用#作为前缀才能进行。 <br />
<br />
<strong>OGNL与模板</strong> <br />
<br />
我们在尝试了OGNL的基本操作并了解了OGNL的三要素之后，或许很容易把OGNL的操作与模板联系起来进行比较。在很多方面，他们也的确有着相似之处。 <br />
<br />
对于模板，会有一些普通的输出元素，也有一些模板语言特殊的符号构成的元素，这些元素一旦与具体的Java对象融合起来，就会得到我们需要的输出结果。 <br />
<br />
而OGNL看起来也是非常的类似，OGNL中的表达式就雷同于模板语言的特殊符号，目的是针对某些Java对象进行存取。而OGNL与模板都将数据与展现分开，将数据放到某个特定的地方，具体来说，就是Java对象。只是OGNL与模板的语法结构不完全相同而已。 <br />
<br />
<strong><span style="font-size: medium">深入浅出OGNL</span></strong> <br />
<br />
在了解了OGNL的API和基本操作以后，我们来深入到OGNL的内部来看看，挖掘一些更加深入的知识。 <br />
<br />
<strong>OGNL表达式</strong> <br />
<br />
OGNL支持各种纷繁复杂的表达式。但是最最基本的表达式的原型，是将对象的引用值用点串联起来，从左到右，每一次表达式计算返回的结果成为当前对象，后面部分接着在当前对象上进行计算，一直到全部表达式计算完成，返回最后得到的对象。OGNL则针对这条基本原则进行不断的扩充，从而使之支持对象树、数组、容器的访问，甚至是类似SQL中的投影选择等操作。 <br />
<br />
接下来我们就来看看一些常用的OGNL表达式： <br />
<br />
1. 基本对象树的访问 <br />
<br />
对象树的访问就是通过使用点号将对象的引用串联起来进行。 <br />
<br />
例如：name，department.name，user.department.factory.manager.name <br />
<br />
2. 对容器变量的访问 <br />
<br />
对容器变量的访问，通过#符号加上表达式进行。 <br />
<br />
例如：#name，#department.name，#user.department.factory.manager.name <br />
<br />
3. 使用操作符号 <br />
<br />
OGNL表达式中能使用的操作符基本跟Java里的操作符一样，除了能使用 +, -, *, /, ++, --, ==, !=, = 等操作符之外，还能使用 mod, in, not in等。 <br />
<br />
4. 容器、数组、对象 <br />
<br />
OGNL支持对数组和ArrayList等容器的顺序访问： <br />
<br />
例如：group.users[0] <br />
<br />
同时，OGNL支持对Map的按键值查找： <br />
<br />
例如：#session['mySessionPropKey'] <br />
<br />
不仅如此，OGNL还支持容器的构造的表达式： <br />
<br />
例如：{"green", "red", "blue"}构造一个List，#{"key1" : "value1", "key2" : "value2", "key3" : "value3"}构造一个Map <br />
<br />
你也可以通过任意类对象的构造函数进行对象新建： <br />
<br />
例如：new java.net.URL("http://localhost/") <br />
<br />
5. 对静态方法或变量的访问 <br />
<br />
要引用类的静态方法和字段，他们的表达方式是一样的@class@member或者@class@method(args)： <br />
<br />
例如：@com.javaeye.core.Resource@ENABLE，@com.javaeye.core.Resource@getAllResources <br />
<br />
6. 方法调用 <br />
<br />
直接通过类似Java的方法调用方式进行，你甚至可以传递参数： <br />
<br />
例如：user.getName()，group.users.size()，group.containsUser(#requestUser) <br />
<br />
7. 投影和选择 <br />
<br />
<br />
<br />
OGNL支持类似数据库中的投影（projection） 和选择（selection）。 <br />
<br />
投影就是选出集合中每个元素的相同属性组成新的集合，类似于关系数据库的字段操作。投影操作语法为 collection.{XXX}，其中XXX 是这个集合中每个元素的公共属性。 <br />
<br />
例如：group.userList.{username}将获得某个group中的所有user的name的列表。 <br />
<br />
选择就是过滤满足selection 条件的集合元素，类似于关系数据库的纪录操作。选择操作的语法为：collection.{X YYY}，其中X 是一个选择操作符，后面则是选择用的逻辑表达式。而选择操作符有三种： <br />
? 选择满足条件的所有元素 <br />
^ 选择满足条件的第一个元素 <br />
$ 选择满足条件的最后一个元素 <br />
<br />
例如：group.userList.{? #this.name != null}将获得某个group中user的name不为空的user的列表。 <br />
<br />
上述的所有的表达式，只是对OGNL所有表达式的大概的一个概括，除此之外，OGNL还有更多的表达式，例如lamba表达式等等。最具体的表达式的文档，大家可以参考OGNL自带的文档： <br />
<br />
<a href="http://www.ognl.org/2.6.9/Documentation/html/LanguageGuide/apa.html" target="_blank">http://www.ognl.org/2.6.9/Documentation/html/LanguageGuide/apa.html</a> <br />
<br />
在撰写时，我也参考了potain同学的XWork教程以及一些网络上的一些文章，特此列出： <br />
<br />
<a href="http://www.lifevv.com/java/doc/20071018173750030.html" target="_blank">http://www.lifevv.com/java/doc/20071018173750030.html</a> <br />
<br />
<a href="http://blog.csdn.net/ice_fire2008/archive/2008/05/12/2438817.aspx" target="_blank">http://blog.csdn.net/ice_fire2008/archive/2008/05/12/2438817.aspx</a> <br />
<br />
<strong>OGNLContext</strong> <br />
<br />
OGNLContext就是OGNL的运行上下文环境。OGNLContext其实是一个Map结构，如果查看一下它的源码，就会发现，它其实实现了java.utils.Map的接口。当你在调用OGNL的取值或者设值的方法时，你可能会自己定义一个Context，并且将它传递给方法。事实上，你所传递进去的这个Context，会在OGNL内部被转化成OGNLContext，而你传递进去的所有的键值对，也会被OGNLContext接管维护，这里有点类似一个装饰器，向你屏蔽了一些其内部的实现机理。 <br />
<br />
在OGNLContext的内部维护的东西很多，其中，我挑选2个比较重要的提一下。一个是你在调用方法时传入的Context，它会被维护在OGNL内部，并且作为存取变量的基础依据。另外一个，是在Context内部维护了一个key为root的值，它将规定在OGNLContext进行计算时，哪个元素被指定为根对象。其在进行存取时，将会被特殊对待。 <br />
<br />
<strong>this指针</strong> <br />
<br />
我们知道，OGNL表达式是以点进行串联的一个字符串链式表达式。而这个表达式在进行计算的时候，从左到右，每一次表达式计算返回的结果成为当前对象，并继续进行计算，直到得到计算结果。每次计算的中间对象都会放在一个叫做this的变量里面这个this变量就称之为this指针。 <br />
<br />
例如：group.userList.size().(#this+1).toString() <br />
<br />
在这个例子中，#this其实就是group.userList.size()的计算结构。 <br />
<br />
使用this指针，我们就可以在OGNL表达式中进行一些简单的计算，从而完成我们的计算逻辑，而this指针在lamba表达式的引用中尤为广泛，有兴趣的读者可以深入研究OGNL自带的文档中lamba表达式的章节。 <br />
<br />
<strong>默认行为和类型转化</strong> <br />
<br />
在我们所讲述的所有的OGNL的操作中，实际上，全部都忽略了OGNL内部帮助你完成的很多默认行为和类型转化方面的工作。 <br />
<br />
我们来看一下OGNL在进行操作初始化时候的一个函数签名： <br />
<br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://downpour.javaeye.com/blog/308896#"><img alt="复制代码" src="http://downpour.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="comment">/** </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;Appends&nbsp;the&nbsp;standard&nbsp;naming&nbsp;context&nbsp;for&nbsp;evaluating&nbsp;an&nbsp;OGNL&nbsp;expression </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;into&nbsp;the&nbsp;context&nbsp;given&nbsp;so&nbsp;that&nbsp;cached&nbsp;maps&nbsp;can&nbsp;be&nbsp;used&nbsp;as&nbsp;a&nbsp;context. </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;* </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@param&nbsp;root&nbsp;the&nbsp;root&nbsp;of&nbsp;the&nbsp;object&nbsp;graph </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@param&nbsp;context&nbsp;the&nbsp;context&nbsp;to&nbsp;which&nbsp;OGNL&nbsp;context&nbsp;will&nbsp;be&nbsp;added. </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;@return&nbsp;Context&nbsp;Map&nbsp;with&nbsp;the&nbsp;keys&nbsp;&lt;CODE&gt;root&lt;/CODE&gt;&nbsp;and&nbsp;&lt;CODE&gt;context&lt;/CODE&gt; </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set&nbsp;appropriately </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;*/</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;Map&nbsp;addDefaultContext(&nbsp;Object&nbsp;root,&nbsp;ClassResolver&nbsp;classResolver,&nbsp;TypeConverter&nbsp;converter,&nbsp;MemberAccess&nbsp;memberAccess,&nbsp;Map&nbsp;context&nbsp;);&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">/**
* Appends the standard naming context for evaluating an OGNL expression
* into the context given so that cached maps can be used as a context.
*
* @param root the root of the object graph
* @param context the context to which OGNL context will be added.
* @return Context Map with the keys &lt;CODE&gt;root&lt;/CODE&gt; and &lt;CODE&gt;context&lt;/CODE&gt;
*         set appropriately
*/
public static Map addDefaultContext( Object root, ClassResolver classResolver, TypeConverter converter, MemberAccess memberAccess, Map context );
</pre>
<br />
<br />
可以看到，在初始化时，OGNL还需要额外初始化一个类型转化的接口和一些其他的信息。只不过这些默认行为，由OGNL的内部屏蔽了。 <br />
<br />
一旦需要自己定义针对某个特定类型的类型转化方式，你就需要实现TypeConverter接口，并且在OGNL中进行注册。 <br />
<br />
同时，如果需要对OGNL的许多默认行为做出改变，则需要通过设置OGNL的全局环境变量进行。 <br />
<br />
上述的这些内容，有些会在后面的章节涉及，有兴趣的读者，也可以参阅OGNL的源码和OGNL的文档寻求帮助。 </div>
<img src ="http://www.blogjava.net/nogocn/aggbug/285920.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nogocn/" target="_blank">NG</a> 2009-07-08 11:07 <a href="http://www.blogjava.net/nogocn/archive/2009/07/08/285920.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>spring优秀工具类，文件资源操作和 Web 相关工具类(备用)</title><link>http://www.blogjava.net/nogocn/archive/2009/07/08/285918.html</link><dc:creator>NG</dc:creator><author>NG</author><pubDate>Wed, 08 Jul 2009 03:06:00 GMT</pubDate><guid>http://www.blogjava.net/nogocn/archive/2009/07/08/285918.html</guid><wfw:comment>http://www.blogjava.net/nogocn/comments/285918.html</wfw:comment><comments>http://www.blogjava.net/nogocn/archive/2009/07/08/285918.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nogocn/comments/commentRss/285918.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nogocn/services/trackbacks/285918.html</trackback:ping><description><![CDATA[<blockquote>Spring 不但提供了一个功能全面的应用开发框架，本身还拥有众多可以在程序编写时直接使用的工具类，您不但可以在 Spring 应用中使用这些工具类，也可以在其它的应用中使用，这些工具类中的大部分是可以在脱离 Spring 框架时使用的。了解 Spring 中有哪些好用的工具类并在程序编写时适当使用，将有助于提高开发效率、增强代码质量。在这个分为两部分的文章中，我们将从众多的 Spring 工具类中遴选出那些好用的工具类介绍给大家。第 1 部分将介绍与文件资源操作和 Web 相关的工具类。</blockquote><!--start RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--end RESERVED FOR FUTURE USE INCLUDE FILES-->
<p><a name="N10058"><span class="atitle">文件资源操作</span></a></p>
<p>文件资源的操作是应用程序中常见的功能，如当上传一个文件后将其保存在特定目录下，从指定地址加载一个配置文件等等。我们一般使用 JDK 的 I/O 处理类完成这些操作，但对于一般的应用程序来说，JDK 的这些操作类所提供的方法过于底层，直接使用它们进行文件操作不但程序编写复杂而且容易产生错误。相比于 JDK 的 File，Spring 的 Resource 接口（资源概念的描述接口）抽象层面更高且涵盖面更广，Spring 提供了许多方便易用的资源操作工具类，它们大大降低资源操作的复杂度，同时具有更强的普适性。这些工具类不依赖于 Spring 容器，这意味着您可以在程序中象一般普通类一样使用它们。</p>
<p><a name="N10061"><span class="smalltitle">加载文件资源</span></a></p>
<p>Spring 定义了一个 org.springframework.core.io.Resource 接口，Resource 接口是为了统一各种类型不同的资源而定义的，Spring 提供了若干 Resource 接口的实现类，这些实现类可以轻松地加载不同类型的底层资源，并提供了获取文件名、URL 地址以及资源内容的操作方法。</p>
<p><strong>访问文件资源</strong> </p>
<p>假设有一个文件地位于 Web 应用的类路径下，您可以通过以下方式对这个文件资源进行访问：</p>
<ul>
    <li>通过 FileSystemResource 以文件系统绝对路径的方式进行访问；
    <li>通过 ClassPathResource 以类路径的方式进行访问；
    <li>通过 ServletContextResource 以相对于Web应用根目录的方式进行访问。 </li>
</ul>
<p>相比于通过 JDK 的 File 类访问文件资源的方式，Spring 的 Resource 实现类无疑提供了更加灵活的操作方式，您可以根据情况选择适合的 Resource 实现类访问资源。下面，我们分别通过 FileSystemResource 和 ClassPathResource 访问同一个文件资源：</p>
<br />
<a name="N10082"><strong>清单 1. FileSourceExample</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">package com.baobaotao.io;
            import java.io.IOException;
            import java.io.InputStream;
            import org.springframework.core.io.ClassPathResource;
            import org.springframework.core.io.FileSystemResource;
            import org.springframework.core.io.Resource;
            public class FileSourceExample {
            public static void main(String[] args) {
            try {
            String filePath =
            "D:/masterSpring/chapter23/webapp/WEB-INF/classes/conf/file1.txt";
            // ① 使用系统文件路径方式加载文件
            Resource res1 = new FileSystemResource(filePath);
            // ② 使用类路径方式加载文件
            Resource res2 = new ClassPathResource("conf/file1.txt");
            InputStream ins1 = res1.getInputStream();
            InputStream ins2 = res2.getInputStream();
            System.out.println("res1:"+res1.getFilename());
            System.out.println("res2:"+res2.getFilename());
            } catch (IOException e) {
            e.printStackTrace();
            }
            }
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>在获取资源后，您就可以通过 Resource 接口定义的多个方法访问文件的数据和其它的信息：如您可以通过 getFileName() 获取文件名，通过 getFile() 获取资源对应的 File 对象，通过 getInputStream() 直接获取文件的输入流。此外，您还可以通过 createRelative(String relativePath) 在资源相对地址上创建新的资源。</p>
<p>在 Web 应用中，您还可以通过 ServletContextResource 以相对于 Web 应用根目录的方式访问文件资源，如下所示：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">&lt;%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%&gt;
            &lt;jsp:directive.page import="
            org.springframework.web.context.support.ServletContextResource"/&gt;
            &lt;jsp:directive.page import="org.springframework.core.io.Resource"/&gt;
            &lt;%
            // ① 注意文件资源地址以相对于 Web 应用根路径的方式表示
            Resource res3 = new ServletContextResource(application,
            "/WEB-INF/classes/conf/file1.txt");
            out.print(res3.getFilename());
            %&gt;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>对于位于远程服务器（Web 服务器或 FTP 服务器）的文件资源，您则可以方便地通过 UrlResource 进行访问。</p>
<p>为了方便访问不同类型的资源，您必须使用相应的 Resource 实现类，是否可以在不显式使用 Resource 实现类的情况下，仅根据带特殊前缀的资源地址直接加载文件资源呢？Spring 提供了一个 ResourceUtils 工具类，它支持&#8220;classpath:&#8221;和&#8220;file:&#8221;的地址前缀，它能够从指定的地址加载文件资源，请看下面的例子：</p>
<br />
<a name="N1009B"><strong>清单 2. ResourceUtilsExample</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">package com.baobaotao.io;
            import java.io.File;
            import org.springframework.util.ResourceUtils;
            public class ResourceUtilsExample {
            public static void main(String[] args) throws Throwable{
            File clsFile = ResourceUtils.getFile("classpath:conf/file1.txt");
            System.out.println(clsFile.isFile());
            String httpFilePath = "file:D:/masterSpring/chapter23/src/conf/file1.txt";
            File httpFile = ResourceUtils.getFile(httpFilePath);
            System.out.println(httpFile.isFile());
            }
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>ResourceUtils 的 getFile(String resourceLocation) 方法支持带特殊前缀的资源地址，这样，我们就可以在不和 Resource 实现类打交道的情况下使用 Spring 文件资源加载的功能了。</p>
<p><strong>本地化文件资源</strong> </p>
<p>本地化文件资源是一组通过本地化标识名进行特殊命名的文件，Spring 提供的 LocalizedResourceHelper 允许通过文件资源基名和本地化实体获取匹配的本地化文件资源并以 Resource 对象返回。假设在类路径的 i18n 目录下，拥有一组基名为 message 的本地化文件资源，我们通过以下实例演示获取对应中国大陆和美国的本地化文件资源：</p>
<br />
<a name="N100B0"><strong>清单 3. LocaleResourceTest</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">package com.baobaotao.io;
            import java.util.Locale;
            import org.springframework.core.io.Resource;
            import org.springframework.core.io.support.LocalizedResourceHelper;
            public class LocaleResourceTest {
            public static void main(String[] args) {
            LocalizedResourceHelper lrHalper = new LocalizedResourceHelper();
            // ① 获取对应美国的本地化文件资源
            Resource msg_us = lrHalper.findLocalizedResource("i18n/message", ".properties",
            Locale.US);
            // ② 获取对应中国大陆的本地化文件资源
            Resource msg_cn = lrHalper.findLocalizedResource("i18n/message", ".properties",
            Locale.CHINA);
            System.out.println("fileName(us):"+msg_us.getFilename());
            System.out.println("fileName(cn):"+msg_cn.getFilename());
            }
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>虽然 JDK 的 java.util.ResourceBundle 类也可以通过相似的方式获取本地化文件资源，但是其返回的是 ResourceBundle 类型的对象。如果您决定统一使用 Spring 的 Resource 接表征文件资源，那么 LocalizedResourceHelper 就是获取文件资源的非常适合的帮助类了。</p>
<p><a name="N100BC"><span class="smalltitle">文件操作</span></a></p>
<p>在使用各种 Resource 接口的实现类加载文件资源后，经常需要对文件资源进行读取、拷贝、转存等不同类型的操作。您可以通过 Resource 接口所提供了方法完成这些功能，不过在大多数情况下，通过 Spring 为 Resource 所配备的工具类完成文件资源的操作将更加方便。</p>
<p><strong>文件内容拷贝</strong> </p>
<p>第一个我们要认识的是 FileCopyUtils，它提供了许多一步式的静态操作方法，能够将文件内容拷贝到一个目标 byte[]、String 甚至一个输出流或输出文件中。下面的实例展示了 FileCopyUtils 具体使用方法：</p>
<br />
<a name="N100CE"><strong>清单 4. FileCopyUtilsExample</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">package com.baobaotao.io;
            import java.io.ByteArrayOutputStream;
            import java.io.File;
            import java.io.FileReader;
            import java.io.OutputStream;
            import org.springframework.core.io.ClassPathResource;
            import org.springframework.core.io.Resource;
            import org.springframework.util.FileCopyUtils;
            public class FileCopyUtilsExample {
            public static void main(String[] args) throws Throwable {
            Resource res = new ClassPathResource("conf/file1.txt");
            // ① 将文件内容拷贝到一个 byte[] 中
            byte[] fileData = FileCopyUtils.copyToByteArray(res.getFile());
            // ② 将文件内容拷贝到一个 String 中
            String fileStr = FileCopyUtils.copyToString(new FileReader(res.getFile()));
            // ③ 将文件内容拷贝到另一个目标文件
            FileCopyUtils.copy(res.getFile(),
            new File(res.getFile().getParent()+ "/file2.txt"));
            // ④ 将文件内容拷贝到一个输出流中
            OutputStream os = new ByteArrayOutputStream();
            FileCopyUtils.copy(res.getInputStream(), os);
            }
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>往往我们都通过直接操作 InputStream 读取文件的内容，但是流操作的代码是比较底层的，代码的面向对象性并不强。通过 FileCopyUtils 读取和拷贝文件内容易于操作且相当直观。如在 ① 处，我们通过 FileCopyUtils 的 copyToByteArray(File in) 方法就可以直接将文件内容读到一个 byte[] 中；另一个可用的方法是 copyToByteArray(InputStream in)，它将输入流读取到一个 byte[] 中。</p>
<p>如果是文本文件，您可能希望将文件内容读取到 String 中，此时您可以使用 copyToString(Reader in) 方法，如 ② 所示。使用 FileReader 对 File 进行封装，或使用 InputStreamReader 对 InputStream 进行封装就可以了。</p>
<p>FileCopyUtils 还提供了多个将文件内容拷贝到各种目标对象中的方法，这些方法包括：</p>
<table class="data-table-1" cellspacing="0" cellpadding="0" width="100%" summary="" border="0">
    <tbody>
        <tr>
            <th>方法</th>
            <th>说明</th>
        </tr>
        <tr>
            <td><code>static void copy(byte[] in, File out)</code> </td>
            <td>将 byte[] 拷贝到一个文件中</td>
        </tr>
        <tr>
            <td><code>static void copy(byte[] in, OutputStream out) </code></td>
            <td>将 byte[] 拷贝到一个输出流中</td>
        </tr>
        <tr>
            <td><code>static int copy(File in, File out) </code></td>
            <td>将文件拷贝到另一个文件中</td>
        </tr>
        <tr>
            <td><code>static int copy(InputStream in, OutputStream out)</code> </td>
            <td>将输入流拷贝到输出流中</td>
        </tr>
        <tr>
            <td><code>static int copy(Reader in, Writer out)</code> </td>
            <td>将 Reader 读取的内容拷贝到 Writer 指向目标输出中</td>
        </tr>
        <tr>
            <td><code>static void copy(String in, Writer out)</code> </td>
            <td>将字符串拷贝到一个 Writer 指向的目标中</td>
        </tr>
    </tbody>
</table>
<p>在实例中，我们虽然使用 Resource 加载文件资源，但 FileCopyUtils 本身和 Resource 没有任何关系，您完全可以在基于 JDK I/O API 的程序中使用这个工具类。</p>
<p><strong>属性文件操作</strong> </p>
<p>我们知道可以通过 java.util.Properties的load(InputStream inStream) 方法从一个输入流中加载属性资源。Spring 提供的 PropertiesLoaderUtils 允许您直接通过基于类路径的文件地址加载属性资源，请看下面的例子：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">package com.baobaotao.io;
            import java.util.Properties;
            import org.springframework.core.io.support.PropertiesLoaderUtils;
            public class PropertiesLoaderUtilsExample {
            public static void main(String[] args) throws Throwable {
            // ① jdbc.properties 是位于类路径下的文件
            Properties props = PropertiesLoaderUtils.loadAllProperties("jdbc.properties");
            System.out.println(props.getProperty("jdbc.driverClassName"));
            }
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>一般情况下，应用程序的属性文件都放置在类路径下，所以 PropertiesLoaderUtils 比之于 Properties#load(InputStream inStream) 方法显然具有更强的实用性。此外，PropertiesLoaderUtils 还可以直接从 Resource 对象中加载属性资源：</p>
<table class="data-table-1" cellspacing="0" cellpadding="0" width="100%" summary="" border="0">
    <tbody>
        <tr>
            <th>方法</th>
            <th>说明</th>
        </tr>
        <tr>
            <td><code>static Properties loadProperties(Resource resource)</code> </td>
            <td>从 Resource 中加载属性</td>
        </tr>
        <tr>
            <td><code>static void fillProperties(Properties props, Resource resource)</code> </td>
            <td>将 Resource 中的属性数据添加到一个已经存在的 Properties 对象中</td>
        </tr>
    </tbody>
</table>
<p><strong>特殊编码的资源</strong> </p>
<p>当您使用 Resource 实现类加载文件资源时，它默认采用操作系统的编码格式。如果文件资源采用了特殊的编码格式（如 UTF-8），则在读取资源内容时必须事先通过 EncodedResource 指定编码格式，否则将会产生中文乱码的问题。</p>
<br />
<a name="N10188"><strong>清单 5. EncodedResourceExample</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">package com.baobaotao.io;
            import org.springframework.core.io.ClassPathResource;
            import org.springframework.core.io.Resource;
            import org.springframework.core.io.support.EncodedResource;
            import org.springframework.util.FileCopyUtils;
            public class EncodedResourceExample {
            public static void main(String[] args) throws Throwable  {
            Resource res = new ClassPathResource("conf/file1.txt");
            // ① 指定文件资源对应的编码格式（UTF-8）
            EncodedResource encRes = new EncodedResource(res,"UTF-8");
            // ② 这样才能正确读取文件的内容，而不会出现乱码
            String content  = FileCopyUtils.copyToString(encRes.getReader());
            System.out.println(content);
            }
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>EncodedResource 拥有一个 getResource() 方法获取 Resource，但该方法返回的是通过构造函数传入的原 Resource 对象，所以必须通过 EncodedResource#getReader() 获取应用编码后的 Reader 对象，然后再通过该 Reader 读取文件的内容。</p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="N10194"><span class="atitle">Web 相关工具类</span></a></p>
<p>您几乎总是使用 Spring 框架开发 Web 的应用，Spring 为 Web 应用提供了很多有用的工具类，这些工具类可以给您的程序开发带来很多便利。在这节里，我们将逐一介绍这些工具类的使用方法。</p>
<p><a name="N1019D"><span class="smalltitle">操作 Servlet API 的工具类</span></a></p>
<p>当您在控制器、JSP 页面中想直接访问 Spring 容器时，您必须事先获取 WebApplicationContext 对象。Spring 容器在启动时将 WebApplicationContext 保存在 ServletContext的属性列表中，通过 WebApplicationContextUtils 工具类可以方便地获取 WebApplicationContext 对象。</p>
<p><strong>WebApplicationContextUtils</strong> </p>
<p>当 Web 应用集成 Spring 容器后，代表 Spring 容器的 WebApplicationContext 对象将以 WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE 为键存放在 ServletContext 属性列表中。您当然可以直接通过以下语句获取 WebApplicationContext：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">WebApplicationContext wac = (WebApplicationContext)servletContext.
            getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>但通过位于 org.springframework.web.context.support 包中的 WebApplicationContextUtils 工具类获取 WebApplicationContext 更方便：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">WebApplicationContext wac =WebApplicationContextUtils.
            getWebApplicationContext(servletContext);
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>当 ServletContext 属性列表中不存在 WebApplicationContext 时，getWebApplicationContext() 方法不会抛出异常，它简单地返回 null。如果后续代码直接访问返回的结果将引发一个 NullPointerException 异常，而 WebApplicationContextUtils 另一个 getRequiredWebApplicationContext(ServletContext sc) 方法要求 ServletContext 属性列表中一定要包含一个有效的 WebApplicationContext 对象，否则马上抛出一个 IllegalStateException 异常。我们推荐使用后者，因为它能提前发现错误的时间，强制开发者搭建好必备的基础设施。</p>
<p><strong>WebUtils</strong> </p>
<p>位于 org.springframework.web.util 包中的 WebUtils 是一个非常好用的工具类，它对很多 Servlet API 提供了易用的代理方法，降低了访问 Servlet API 的复杂度，可以将其看成是常用 Servlet API 方法的门面类。</p>
<p>下面这些方法为访问 HttpServletRequest 和 HttpSession 中的对象和属性带来了方便：</p>
<table class="data-table-1" cellspacing="0" cellpadding="0" width="100%" summary="" border="0">
    <tbody>
        <tr>
            <th>方法</th>
            <th>说明</th>
        </tr>
        <tr>
            <td><code>Cookie getCookie(HttpServletRequest request, String name)</code> </td>
            <td>获取 HttpServletRequest 中特定名字的 Cookie 对象。如果您需要创建 Cookie， Spring 也提供了一个方便的 CookieGenerator 工具类；</td>
        </tr>
        <tr>
            <td><code>Object getSessionAttribute(HttpServletRequest request, String name) </code></td>
            <td>获取 HttpSession 特定属性名的对象，否则您必须通过request.getHttpSession.getAttribute(name) 完成相同的操作；</td>
        </tr>
        <tr>
            <td><code>Object getRequiredSessionAttribute(HttpServletRequest request, String name)</code> </td>
            <td>和上一个方法类似，只不过强制要求 HttpSession 中拥有指定的属性，否则抛出异常；</td>
        </tr>
        <tr>
            <td><code>String getSessionId(HttpServletRequest request) </code></td>
            <td>获取 Session ID 的值；</td>
        </tr>
        <tr>
            <td><code>void exposeRequestAttributes(ServletRequest request, Map attributes)</code> </td>
            <td>将 Map 元素添加到 ServletRequest 的属性列表中，当请求被导向（forward）到下一个处理程序时，这些请求属性就可以被访问到了；</td>
        </tr>
    </tbody>
</table>
<p>此外，WebUtils还提供了一些和ServletContext相关的方便方法：</p>
<table class="data-table-1" cellspacing="0" cellpadding="0" width="100%" summary="" border="0">
    <tbody>
        <tr>
            <th>方法</th>
            <th>说明</th>
        </tr>
        <tr>
            <td><code>String getRealPath(ServletContext servletContext, String path)</code> </td>
            <td>获取相对路径对应文件系统的真实文件路径；</td>
        </tr>
        <tr>
            <td><code>File getTempDir(ServletContext servletContext) </code></td>
            <td>获取 ServletContex 对应的临时文件地址，它以 File 对象的形式返回。</td>
        </tr>
    </tbody>
</table>
<p>下面的片断演示了使用 WebUtils 从 HttpSession 中获取属性对象的操作：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">protected Object formBackingObject(HttpServletRequest request) throws Exception {
            UserSession userSession = (UserSession) WebUtils.getSessionAttribute(request,
            "userSession");
            if (userSession != null) {
            return new AccountForm(this.petStore.getAccount(
            userSession.getAccount().getUsername()));
            } else {
            return new AccountForm();
            }
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p><a name="N10252"><span class="smalltitle">Spring 所提供的过滤器和监听器</span></a></p>
<p>Spring 为 Web 应用提供了几个过滤器和监听器，在适合的时间使用它们，可以解决一些常见的 Web 应用问题。</p>
<p><strong>延迟加载过滤器</strong> </p>
<p>Hibernate 允许对关联对象、属性进行延迟加载，但是必须保证延迟加载的操作限于同一个 Hibernate Session 范围之内进行。如果 Service 层返回一个启用了延迟加载功能的领域对象给 Web 层，当 Web 层访问到那些需要延迟加载的数据时，由于加载领域对象的 Hibernate Session 已经关闭，这些导致延迟加载数据的访问异常。</p>
<p>Spring 为此专门提供了一个 OpenSessionInViewFilter 过滤器，它的主要功能是使每个请求过程绑定一个 Hibernate Session，即使最初的事务已经完成了，也可以在 Web 层进行延迟加载的操作。</p>
<p>OpenSessionInViewFilter 过滤器将 Hibernate Session 绑定到请求线程中，它将自动被 Spring 的事务管理器探测到。所以 OpenSessionInViewFilter 适用于 Service 层使用HibernateTransactionManager 或 JtaTransactionManager 进行事务管理的环境，也可以用于非事务只读的数据操作中。</p>
<p>要启用这个过滤器，必须在 web.xml 中对此进行配置：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">&#8230;
            &lt;filter&gt;
            &lt;filter-name&gt;hibernateFilter&lt;/filter-name&gt;
            &lt;filter-class&gt;
            org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
            &lt;/filter-class&gt;
            &lt;/filter&gt;
            &lt;filter-mapping&gt;
            &lt;filter-name&gt;hibernateFilter&lt;/filter-name&gt;
            &lt;url-pattern&gt;*.html&lt;/url-pattern&gt;
            &lt;/filter-mapping&gt;
            &#8230;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
上面的配置，我们假设使用 .html 的后缀作为 Web 框架的 URL 匹配模式，如果您使用 Struts 等 Web 框架，可以将其改为对应的&#8220;*.do&#8221;模型。
<p><strong>中文乱码过滤器</strong> </p>
<p>在您通过表单向服务器提交数据时，一个经典的问题就是中文乱码问题。虽然我们所有的 JSP 文件和页面编码格式都采用 UTF-8，但这个问题还是会出现。解决的办法很简单，我们只需要在 web.xml 中配置一个 Spring 的编码转换过滤器就可以了：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">&lt;web-app&gt;
            &lt;!---listener的配置--&gt;
            &lt;filter&gt;
            &lt;filter-name&gt;encodingFilter&lt;/filter-name&gt;
            &lt;filter-class&gt;
            org.springframework.web.filter.CharacterEncodingFilter ① Spring 编辑过滤器
            &lt;/filter-class&gt;
            &lt;init-param&gt; ② 编码方式
            &lt;param-name&gt;encoding&lt;/param-name&gt;
            &lt;param-value&gt;UTF-8&lt;/param-value&gt;
            &lt;/init-param&gt;
            &lt;init-param&gt; ③ 强制进行编码转换
            &lt;param-name&gt;forceEncoding&lt;/param-name&gt;
            &lt;param-value&gt;true&lt;/param-value&gt;
            &lt;/init-param&gt;
            &lt;/filter&gt;
            &lt;filter-mapping&gt; ② 过滤器的匹配 URL
            &lt;filter-name&gt;encodingFilter&lt;/filter-name&gt;
            &lt;url-pattern&gt;*.html&lt;/url-pattern&gt;
            &lt;/filter-mapping&gt;
            &lt;!---servlet的配置--&gt;
            &lt;/web-app&gt;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>这样所有以 .html 为后缀的 URL 请求的数据都会被转码为 UTF-8 编码格式，表单中文乱码的问题就可以解决了。</p>
<p><strong>请求跟踪日志过滤器</strong> </p>
<p>除了以上两个常用的过滤器外，还有两个在程序调试时可能会用到的请求日志跟踪过滤器，它们会将请求的一些重要信息记录到日志中，方便程序的调试。这两个日志过滤器只有在日志级别为 DEBUG 时才会起作用：</p>
<table class="data-table-1" cellspacing="0" cellpadding="0" width="100%" summary="" border="0">
    <tbody>
        <tr>
            <th>方法</th>
            <th>说明</th>
        </tr>
        <tr>
            <td><code>org.springframework.web.filter.ServletContextRequestLoggingFilter</code> </td>
            <td>该过滤器将请求的 URI 记录到 Common 日志中（如通过 Log4J 指定的日志文件）；</td>
        </tr>
        <tr>
            <td><code>org.springframework.web.filter.ServletContextRequestLoggingFilter</code> </td>
            <td>该过滤器将请求的 URI 记录到 ServletContext 日志中。</td>
        </tr>
    </tbody>
</table>
<p>以下是日志过滤器记录的请求跟踪日志的片断：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">(JspServlet.java:224) -     JspEngine --&gt; /htmlTest.jsp
            (JspServlet.java:225) - 	     ServletPath: /htmlTest.jsp
            (JspServlet.java:226) - 	        PathInfo: null
            (JspServlet.java:227) - 	        RealPath: D:\masterSpring\chapter23\webapp\htmlTest.jsp
            (JspServlet.java:228) - 	      RequestURI: /baobaotao/htmlTest.jsp
            &#8230;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>通过这个请求跟踪日志，程度调试者可以详细地查看到有哪些请求被调用，请求的参数是什么，请求是否正确返回等信息。虽然这两个请求跟踪日志过滤器一般在程序调试时使用，但是即使程序部署不将其从 web.xml 中移除也不会有大碍，因为只要将日志级别设置为 DEBUG 以上级别，它们就不会输出请求跟踪日志信息了。</p>
<p><strong>转存 Web 应用根目录监听器和 Log4J 监听器</strong> </p>
<p>Spring 在 org.springframework.web.util 包中提供了几个特殊用途的 Servlet 监听器，正确地使用它们可以完成一些特定需求的功能。比如某些第三方工具支持通过 ${key} 的方式引用系统参数（即可以通过 System.getProperty() 获取的属性），WebAppRootListener 可以将 Web 应用根目录添加到系统参数中，对应的属性名可以通过名为&#8220;webAppRootKey&#8221;的 Servlet 上下文参数指定，默认为&#8220;webapp.root&#8221;。下面是该监听器的具体的配置：</p>
<br />
<a name="list6"><strong>清单 6. WebAppRootListener 监听器配置</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">&#8230;
            &lt;context-param&gt;
            &lt;param-name&gt;webAppRootKey&lt;/param-name&gt;
            &lt;param-value&gt;baobaotao.root&lt;/param-value&gt; ① Web 应用根目录以该属性名添加到系统参数中
            &lt;/context-param&gt;
            &#8230;
            ② 负责将 Web 应用根目录以 webAppRootKey 上下文参数指定的属性名添加到系统参数中
            &lt;listener&gt;
            &lt;listener-class&gt;
            org.springframework.web.util.WebAppRootListener
            &lt;/listener-class&gt;
            &lt;/listener&gt;
            &#8230;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>这样，您就可以在程序中通过 System.getProperty("baobaotao.root") 获取 Web 应用的根目录了。不过更常见的使用场景是在第三方工具的配置文件中通过${baobaotao.root} 引用 Web 应用的根目录。比如以下的 log4j.properties 配置文件就通过 ${baobaotao.root} 设置了日志文件的地址：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">log4j.rootLogger=INFO,R
            log4j.appender.R=org.apache.log4j.RollingFileAppender
            log4j.appender.R.File=${baobaotao.root}/WEB-INF/logs/log4j.log ① 指定日志文件的地址
            log4j.appender.R.MaxFileSize=100KB
            log4j.appender.R.MaxBackupIndex=1
            log4j.appender.R.layout.ConversionPattern=%d %5p [%t] (%F:%L) - %m%n
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>另一个专门用于 Log4J 的监听器是 Log4jConfigListener。一般情况下，您必须将 Log4J 日志配置文件以 log4j.properties 为文件名并保存在类路径下。Log4jConfigListener 允许您通过 log4jConfigLocation Servlet 上下文参数显式指定 Log4J 配置文件的地址，如下所示：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">① 指定 Log4J 配置文件的地址
            &lt;context-param&gt;
            &lt;param-name&gt;log4jConfigLocation&lt;/param-name&gt;
            &lt;param-value&gt;/WEB-INF/log4j.properties&lt;/param-value&gt;
            &lt;/context-param&gt;
            &#8230;
            ② 使用该监听器初始化 Log4J 日志引擎
            &lt;listener&gt;
            &lt;listener-class&gt;
            org.springframework.web.util.Log4jConfigListener
            &lt;/listener-class&gt;
            &lt;/listener&gt;
            &#8230;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<table cellspacing="0" cellpadding="0" width="40%" align="right" border="0">
    <tbody>
        <tr>
            <td width="10"><img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /></td>
            <td>
            <table cellspacing="0" cellpadding="5" width="100%" border="1">
                <tbody>
                    <tr>
                        <td bgcolor="#eeeeee"><a name="N102E2"><strong>提示</strong></a><br />
                        <p>一些Web应用服务器（如 Tomcat）不会为不同的Web应用使用独立的系统参数，也就是说，应用服务器上所有的 Web 应用都共享同一个系统参数对象。这时，您必须通过webAppRootKey 上下文参数为不同Web应用指定不同的属性名：如第一个 Web 应用使用 webapp1.root 而第二个 Web 应用使用 webapp2.root 等，这样才不会发生后者覆盖前者的问题。此外，WebAppRootListener 和 Log4jConfigListener 都只能应用在 Web 应用部署后 WAR 文件会解包的 Web 应用服务器上。一些 Web 应用服务器不会将Web 应用的 WAR 文件解包，整个 Web 应用以一个 WAR 包的方式存在（如 Weblogic），此时因为无法指定对应文件系统的 Web 应用根目录，使用这两个监听器将会发生问题。</p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<p>Log4jConfigListener 监听器包括了 WebAppRootListener 的功能，也就是说，Log4jConfigListener 会自动完成将 Web 应用根目录以 webAppRootKey 上下文参数指定的属性名添加到系统参数中，所以当您使用 Log4jConfigListener 后，就没有必须再使用 WebAppRootListener了。</p>
<p><strong>Introspector 缓存清除监听器</strong> </p>
<p>Spring 还提供了一个名为 org.springframework.web.util.IntrospectorCleanupListener 的监听器。它主要负责处理由 JavaBean Introspector 功能而引起的缓存泄露。IntrospectorCleanupListener 监听器在 Web 应用关闭的时会负责清除 JavaBean Introspector 的缓存，在 web.xml 中注册这个监听器可以保证在 Web 应用关闭的时候释放与其相关的 ClassLoader 的缓存和类引用。如果您使用了 JavaBean Introspector 分析应用中的类，Introspector 缓存会保留这些类的引用，结果在应用关闭的时候，这些类以及Web 应用相关的 ClassLoader 不能被垃圾回收。不幸的是，清除 Introspector 的唯一方式是刷新整个缓存，这是因为没法准确判断哪些是属于本 Web 应用的引用对象，哪些是属于其它 Web 应用的引用对象。所以删除被缓存的 Introspection 会导致将整个 JVM 所有应用的 Introspection 都删掉。需要注意的是，Spring 托管的 Bean 不需要使用这个监听器，因为 Spring 的 Introspection 所使用的缓存在分析完一个类之后会马上从 javaBean Introspector 缓存中清除掉，并将缓存保存在应用程序特定的 ClassLoader 中，所以它们一般不会导致内存资源泄露。但是一些类库和框架往往会产生这个问题。例如 Struts 和 Quartz 的 Introspector 的内存泄漏会导致整个的 Web 应用的 ClassLoader 不能进行垃圾回收。在 Web 应用关闭之后，您还会看到此应用的所有静态类引用，这个错误当然不是由这个类自身引起的。解决这个问题的方法很简单，您仅需在 web.xml 中配置 IntrospectorCleanupListener 监听器就可以了：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">&lt;listener&gt;
            &lt;listener-class&gt;
            org.springframework.web.util.IntrospectorCleanupListener
            &lt;/listener-class&gt;
            &lt;/listener&gt;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="N102FB"><span class="atitle">小结</span></a></p>
<p>本文介绍了一些常用的 Spring 工具类，其中大部分 Spring 工具类不但可以在基于 Spring 的应用中使用，还可以在其它的应用中使用。使用 JDK 的文件操作类在访问类路径相关、Web 上下文相关的文件资源时，往往显得拖泥带水、拐弯抹角，Spring 的 Resource 实现类使这些工作变得轻松了许多。</p>
<p>在 Web 应用中，有时你希望直接访问 Spring 容器，获取容器中的 Bean，这时使用 WebApplicationContextUtils 工具类从 ServletContext 中获取 WebApplicationContext 是非常方便的。WebUtils 为访问 Servlet API 提供了一套便捷的代理方法，您可以通过 WebUtils 更好的访问 HttpSession 或 ServletContext 的信息。</p>
<p>Spring 提供了几个 Servlet 过滤器和监听器，其中 ServletContextRequestLoggingFilter 和 ServletContextRequestLoggingFilter 可以记录请求访问的跟踪日志，你可以在程序调试时使用它们获取请求调用的详细信息。WebAppRootListener 可以将 Web 应用的根目录以特定属性名添加到系统参数中，以便第三方工具类通过 ${key} 的方式进行访问。Log4jConfigListener 允许你指定 Log4J 日志配置文件的地址，且可以在配置文件中通过 ${key} 的方式引用 Web 应用根目录，如果你需要在 Web 应用相关的目录创建日志文件，使用 Log4jConfigListener 可以很容易地达到这一目标。</p>
<p>Web 应用的内存泄漏是最让开发者头疼的问题，虽然不正确的程序编写可能是这一问题的根源，也有可能是一些第三方框架的 JavaBean Introspector 缓存得不到清除而导致的，Spring 专门为解决这一问题配备了 IntrospectorCleanupListener 监听器，它只要简单在 web.xml 中声明该监听器就可以了。<br />
<br />
原文摘自：http://www.zhuoda.org/lunzi/85887.html</p>
<img src ="http://www.blogjava.net/nogocn/aggbug/285918.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nogocn/" target="_blank">NG</a> 2009-07-08 11:06 <a href="http://www.blogjava.net/nogocn/archive/2009/07/08/285918.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在页面上显示图片</title><link>http://www.blogjava.net/nogocn/archive/2007/05/05/115470.html</link><dc:creator>NG</dc:creator><author>NG</author><pubDate>Sat, 05 May 2007 15:20:00 GMT</pubDate><guid>http://www.blogjava.net/nogocn/archive/2007/05/05/115470.html</guid><wfw:comment>http://www.blogjava.net/nogocn/comments/115470.html</wfw:comment><comments>http://www.blogjava.net/nogocn/archive/2007/05/05/115470.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nogocn/comments/commentRss/115470.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nogocn/services/trackbacks/115470.html</trackback:ping><description><![CDATA[<strong>jsp<br></strong>
<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: #008080">1</span>&nbsp;<span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">IMG&nbsp;width</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">200</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;height</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">200</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;border</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">&nbsp;&nbsp;&nbsp;&nbsp;style</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">cursor:&nbsp;pointer;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">2</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;src</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&lt;%=request.getContextPath()%&gt;/xxxx.do?type=show&amp;pkId=xx</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&gt;</span></div>
<p align=left><br><strong>action.do</strong><br><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: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(type.equals(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">show</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">))<br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InputStream&nbsp;inputsteam&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">null</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pkId</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">Long.parseLong(servletRequest.getParameter(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">pkId</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">));<br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(pkId&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">null</span><span style="COLOR: #000000">&amp;&amp;!</span><span style="COLOR: #000000">pkId.equals(</span><span style="COLOR: #000000">""</span><span style="COLOR: #000000">))<br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inputsteam&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;bpo.getBlobByID(pkId).getBinaryStream();<br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BufferedImage&nbsp;image&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;ImageIO.read(inputsteam);<br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ServletOutputStream&nbsp;sos&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;servletResponse.getOutputStream();<br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JPEGImageEncoder&nbsp;encoder&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;JPEGCodec.createJPEGEncoder(sos);<br></span><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;encoder.encode(image);<br></span><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inputsteam.close();<br></span><span style="COLOR: #008080">15</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">16</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">17</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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">null</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">18</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">19</span>&nbsp;<span style="COLOR: #000000"></span></div>
<img src ="http://www.blogjava.net/nogocn/aggbug/115470.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nogocn/" target="_blank">NG</a> 2007-05-05 23:20 <a href="http://www.blogjava.net/nogocn/archive/2007/05/05/115470.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>