﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-蒙古狼-随笔分类-java应用</title><link>http://www.blogjava.net/landy/category/10829.html</link><description>像狼一样凶狠</description><language>zh-cn</language><lastBuildDate>Mon, 18 Apr 2011 13:54:12 GMT</lastBuildDate><pubDate>Mon, 18 Apr 2011 13:54:12 GMT</pubDate><ttl>60</ttl><item><title>JSP禁用迅雷等下载工具下载文件,强制使用右键另存功能下载文件</title><link>http://www.blogjava.net/landy/archive/2011/03/26/347075.html</link><dc:creator>独孤过客</dc:creator><author>独孤过客</author><pubDate>Sat, 26 Mar 2011 15:22:00 GMT</pubDate><guid>http://www.blogjava.net/landy/archive/2011/03/26/347075.html</guid><wfw:comment>http://www.blogjava.net/landy/comments/347075.html</wfw:comment><comments>http://www.blogjava.net/landy/archive/2011/03/26/347075.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/landy/comments/commentRss/347075.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/landy/services/trackbacks/347075.html</trackback:ping><description><![CDATA[<span style="font-family: Verdana, ����; ">
<table cellpadding="0" cellspacing="5" style="width: 705px; ">
    <tbody>
        <tr>
            <td align="left" style="font-family: Verdana, ����; font-size: 9pt; color: black; "><span id="content">
            <p>* 实现文件另存功能<br />
            *&nbsp;<br />
            * @param text<br />
            * 文件内容<br />
            * @param fileName<br />
            * 文件名称<br />
            * @return<br />
            */<br />
            protected String renderFile(String text, String fileName)<br />
            throws IOException<br />
            {<br />
            response.addHeader("Content-Disposition", "attachment; filename="<br />
            + fileName);<br />
            response.setContentType("application/octet-stream");<br />
            response.setCharacterEncoding("GB2312");<br />
            response.getWriter().write(text);<br />
            response.flushBuffer();<br />
            response.getWriter().close();<br />
            return null;<br />
            }</p>
            <p>下载的action:</p>
            <p>/** *//**<br />
            * 提供下载的方法<br />
            * @return<br />
            */<br />
            public String down()<br />
            {<br />
            String dir = getFullPath() + "/upload/file/";<br />
            try<br />
            {<br />
            if (!FileUtils.exists(dir))<br />
            {<br />
            new File(dir).mkdirs();<br />
            }<br />
            Random r = new Random(System.currentTimeMillis());<br />
            Integer randomInt = r.nextInt();<br />
            this.renderFile("test content:" + randomInt,randomInt + ".txt");<br />
            }<br />
            catch (IOException e)<br />
            {<br />
            e.printStackTrace();<br />
            this.renderText(e.getMessage());<br />
            }<br />
            return null;<br />
            }</p>
            <p>页面链接调用:</p>
            <p>&lt;a href="${ctx}/va/va!down.do" &gt;下载&lt;/a&gt;</p>
            </span></td>
        </tr>
    </tbody>
</table>
</span>
<script type="text/javascript">
var _gaq = _gaq || [];  _gaq.push(['_setAccount', 'UA-22730797-3']);  _gaq.push(['_trackPageview']);
(function() {    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);  })();
</script>

<img src ="http://www.blogjava.net/landy/aggbug/347075.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/landy/" target="_blank">独孤过客</a> 2011-03-26 23:22 <a href="http://www.blogjava.net/landy/archive/2011/03/26/347075.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]BPM 介绍</title><link>http://www.blogjava.net/landy/archive/2009/10/24/299557.html</link><dc:creator>独孤过客</dc:creator><author>独孤过客</author><pubDate>Sat, 24 Oct 2009 03:08:00 GMT</pubDate><guid>http://www.blogjava.net/landy/archive/2009/10/24/299557.html</guid><wfw:comment>http://www.blogjava.net/landy/comments/299557.html</wfw:comment><comments>http://www.blogjava.net/landy/archive/2009/10/24/299557.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/landy/comments/commentRss/299557.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/landy/services/trackbacks/299557.html</trackback:ping><description><![CDATA[<p class="style1" style="margin-right: 0cm; margin-left: 0cm; font-size: 10.5pt; font-family: 宋体; font-weight: bold; line-height: 21px; "><span lang="EN-US">BPM&nbsp;</span>介绍</p>
<p class="style2" style="margin-right: 0cm; margin-left: 0cm; font-size: 9pt; font-family: 宋体; line-height: 18px; "><span lang="EN-US">Business Process Management</span>，<span lang="EN-US">BPM</span>）不是一个新概念，甚至不是一个新名词。它是从相关的业务流程变革领域，如业务流程改进（<span lang="EN-US">BPI</span>）、业务流程重组（<span lang="EN-US">BPR</span>）、业务流程革新中发展起来的。流程管理技术也是从早期的工作流管理、<span lang="EN-US">EAI</span>企业应用集成（<span lang="EN-US">Enterprise Application Integration</span>，）、流程自动化、流程集成、流程建模、流程优化等技术中发展起来的。</p>
<p style="margin-right: 0cm; margin-left: 0cm; font-size: 12pt; font-family: 宋体; line-height: 24px; "><span lang="EN-US" style="font-size: 9pt; line-height: 18px; "><img width="300" height="170" src="file://asp0243/wwwroot/BpmFlowWeb/cases/BPMFlow%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB--About%E5%88%86%E5%B1%82%E5%BC%8F%E6%9E%B6%E6%9E%84_clip_image002_0002.jpg"  alt="" /></span></p>
<p class="style2" style="margin-right: 0cm; margin-left: 0cm; font-size: 9pt; font-family: 宋体; line-height: 18px; "><span lang="EN-US">BPM</span>管理系统能够提供方便迅速分析业务流程、商业数据的工具，以便企业决定用最适和流程引导商业目的的实现。也就是<span lang="EN-US">BPM</span>必须能用一种通用的语言传达给商业伙伴对于特殊业务流程的清晰明确的描述。<span lang="EN-US">&nbsp;<br />
BPM</span>的定义是：<span lang="EN-US">BPM</span>是一个描述一组服务和工具的一般名词，这些服务和工具为显式的流程管理<span lang="EN-US">(</span>如流程的分析、定义、执行、监视和管理<span lang="EN-US">)</span>提供支持。</p>
<p class="style2" style="margin-right: 0cm; margin-left: 0cm; font-size: 9pt; font-family: 宋体; line-height: 18px; ">目前，<span lang="EN-US">BPM</span>方面的研究主要集中在：<span lang="EN-US">&nbsp;<br />
◎&nbsp;</span>理论基础：<span lang="EN-US">BPM</span>的体系、模型、定义语言的研究；<span lang="EN-US">&nbsp;<br />
◎&nbsp;</span>实现技术：<span lang="EN-US">BPM</span>的仿真和评估；流程的事务特性；<span lang="EN-US">Web Service</span>、<span lang="EN-US">XML</span>、组件技术等在<span lang="EN-US">BPM</span>中的应用<span lang="EN-US"><br />
◎&nbsp;</span>应用：<span lang="EN-US">BPM</span>的实施技术；在不同领域内的应用方法。</p>
<p style="margin-right: 0cm; margin-left: 0cm; font-size: 12pt; font-family: 宋体; line-height: 24px; "><span lang="EN-US" style="font-size: 9pt; line-height: 18px; "><img width="274" height="101" src="file://asp0243/wwwroot/BpmFlowWeb/cases/BPMFlow%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB--About%E5%88%86%E5%B1%82%E5%BC%8F%E6%9E%B6%E6%9E%84_clip_image002_0003.jpg"  alt="" /></span></p>
<p style="margin-right: 0cm; margin-left: 0cm; font-size: 12pt; font-family: 宋体; line-height: 24px; "><span class="style11" style="font-weight: bold; "><span lang="EN-US" style="font-size: 10.5pt; line-height: 21px; ">BPM</span></span><span class="style11" style="font-weight: bold; "><span style="font-size: 10.5pt; line-height: 21px; ">的生命周期&nbsp;</span></span><span lang="EN-US" style="font-size: 9pt; line-height: 18px; "><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></p>
<p class="style2" style="margin-right: 0cm; margin-left: 0cm; font-size: 9pt; font-family: 宋体; line-height: 18px; ">从整体上将<span lang="EN-US">BPM</span>生命周期划分为五个阶段，分别是：业务流程发掘（<span lang="EN-US">Business Process Discovery</span>）、业务流程设计（<span lang="EN-US">Business Process Design</span>）、业务流程执行（<span lang="EN-US">Business Process Execution</span>）、业务流程管理维护<span lang="EN-US">(Business Process Administration)</span>，以及业务流程最优化（<span lang="EN-US">Business Process Optimization</span>）。对于这五个阶段，各个厂商之间并不存在过多的异议。</p>
<p class="style2" style="margin-right: 0cm; margin-left: 0cm; font-size: 9pt; font-family: 宋体; line-height: 18px; "><span lang="EN-US">1.&nbsp;</span>业务流程发掘<span lang="EN-US">&nbsp;<br />
</span>企业要全面应用<span lang="EN-US">BPM</span>，首先面临的工作当然是要搞清楚知道企业现行流程的工作方式与工作状况，这是后续所有工作的出发点和基石，因此理应得到足够的重视。其中，最为重要的是当前流程中的信息流<span lang="EN-US">(Message flow)</span>、事件流<span lang="EN-US">(Event flow)</span>以及控制流<span lang="EN-US">(Control flow)</span>。更为具体一点，企业需要了解哪些流程可以实施自动化？哪些流程需要人工参与？各个流程都是需要什么人来参与？需要多少人？相关流程是在组织内部执行，还是在外部被执行？风险如何评估？现有流程的瓶颈可能位于哪个环节？诸如此类，不一而足。在这个阶段，通常有两个方面的工作需要进行。第一个工作是进行流程评估<span lang="EN-US">(BPA</span>，<span lang="EN-US">Business Process Assessment)</span>，一般的做法是聘请企业外部的顾问管理公司或者行业专家进行，评估的范围可能涵盖策略与管理目标与流程的连结。完成了流程评估之后，接下来就是配合导入一些管理主题（譬如<span lang="EN-US">ISO</span>质量管理体系或六西格玛等），进行流程再造<span lang="EN-US">(BPR</span>，<span lang="EN-US">Business Process Reengineering)</span>。然后，将得到的信息和数据反馈到第二个阶段。<span lang="EN-US">&nbsp;<br />
2.&nbsp;</span>业务流程设计<span lang="EN-US">&nbsp;<br />
</span>这个阶段是根据前期的工作对未来进行流程的定位和设计。本阶段分为四个步骤，分别是建模<span lang="EN-US">(Modeling)</span>、分析<span lang="EN-US">(Analyzing)</span>、模拟<span lang="EN-US">&nbsp;(Simulation)</span>和流程重构<span lang="EN-US">(Redesigning)</span>。如图<span lang="EN-US">1</span>所示，这四个步骤是一个反复的循环，循环的目的是力求得到更准确、更有价值的业务流程。<span lang="EN-US">&nbsp;<br />
</span>首先是建模，通常我们将建模所采用的工具称作<span lang="EN-US">Process Designer</span>（进程设计器），一般来说它包括四个比较重要的部分：结构表格<span lang="EN-US">(Organization Chart)</span>、流程图<span lang="EN-US">(Activity Diagram)</span>、商业规则（<span lang="EN-US">Business Rule</span>），以及电子窗体<span lang="EN-US">(e-Form)</span>设计工具（电子窗体指的是信息显现的接口，一般而言企业可以把应用系统的数据与流程相关的数据，通过电子窗体来展现，这样做有助于处理第三个阶段中人机互动的步骤，而呈现的方式则可以通过特定的工具进行快速的订制），<span lang="EN-US">&nbsp;<br />
</span>分析是从流程定义的语意与理论上进行推论，仿真则可设定机率变量与行为假设让系统自动跑出期望值或变异差数据。市场上有些产品则仅提供自动执行<span lang="EN-US">(Automation)</span>或手动逐步执行以观测流程行为。<span lang="EN-US">&nbsp;<br />
</span>需要注意的是，建模并不是孤立的，在建模之后企业一定要进行流程执行动作前的分析与仿真，以便验证设计出来的流程是否正确并且适用于本企业，此外它还能提供初步设计的流程可能遇到的瓶颈信息，以避免在业务流程执行后才发现相关问题进而导致重大的运营损失。与此同时，如果分析和模拟出来的结果并不尽如人意，可以多次反复和循环本阶段的四个步骤，直至满意为止。这样做的好处还在于，面对外部巨大的竞争压力与种种商机，企业在进行经营和管理中（非模拟状态），对于一些细微的流程变化<span lang="EN-US">(Fine-grained process change)</span>，可以做出实时有效的反应，以便于企业快速地进行重构流程的工作。<span lang="EN-US">&nbsp;<br />
3.&nbsp;</span>业务流程执行<span lang="EN-US">&nbsp;<br />
</span>经过多次的建模、分析、仿真和确定了企业的业务流程之后，接下来面临的就是流程的执行。<span lang="EN-US">&nbsp;<br />
</span>业务流程的执行分为三个步骤，分别是部署（<span lang="EN-US">deployment</span>）、自动操作（<span lang="EN-US">automation</span>）和人机交互（<span lang="EN-US">interaction</span>）这三个步骤并非一个循环的关系，而是由部署引出自动操作和人机交互两个步骤，自动操作与人机交互并行进行。<span lang="EN-US">&nbsp;<br />
</span>布署是将设计好的流程推出上线，并且让所有的参与者来执行。这里所说的参与者是泛指的，它可能是人，也可能是某些系统应用或者其他流程。对于这个步骤，企业的主要目的应该是以最少的工作量达到运算资源<span lang="EN-US">(Computing Resource)</span>与组织人员的优化和整合，最少的工作量并不意味着偷工减料或者有意地减少工作，其目的是减少企业资源占有，降低成本，从而达到效益的最大化。<span lang="EN-US">&nbsp;<br />
</span>在自动操作这一步骤中，负责控制执行的模块我们可称之为工作流引擎<span lang="EN-US">(Workflow Engine)</span>或流程服务器<span lang="EN-US">(Process Server)</span>。这个步骤具有一个重要的特点，那就是无需技术人员的亲自参与，流程的使用者依然可以自行编辑和修改既有的商业逻辑。企业可以借助调度日程<span lang="EN-US">&nbsp;(Scheduler)&nbsp;</span>来设定启动自动操作的时间和周期频率，另外有些厂商提供的<span lang="EN-US">BPM</span>解决方案还会提供规则引擎<span lang="EN-US">&nbsp;(Rule Engine)</span>来进行商业规则的判别与推理。<span lang="EN-US">&nbsp;<br />
</span>通常情况下，并非企业的所有流程都可以自动操作，因此<span lang="EN-US">BPM</span>还应提供能够让人管理自动流程与人工流程之间的接口（有的时候这种流程接口本身也是一个流程）。负责与人互动的接口被称为工作项目处理器<span lang="EN-US">&nbsp;(Workitem Handler)</span>。几年前工作项目处理器大都比较简单，然而在实际工作中，由于种种原因，企业往往需要的是那种能订制、个性化，并且能整合在不同系统的接口，因此很多厂商纷纷推出了更加符合用户需求的流程入口<span lang="EN-US">(Process Portal)</span>。应当说，这是一个可喜的变化。<span lang="EN-US">&nbsp;<br />
4.&nbsp;</span>业务流程管理维护<span lang="EN-US">&nbsp;<br />
</span>当流程上线后，伴随而来的自然是管理维护的问题，这其中包括三个步骤的工作：运行（<span lang="EN-US">operation</span>）、维护（<span lang="EN-US">maintaining</span>）和监测（<span lang="EN-US">Activity monitoring</span>）。如图<span lang="EN-US">1</span>所示，这三个工作并行进行，相互之间不存在递进或者循环的关系。<span lang="EN-US">&nbsp;<br />
</span>前两个步骤相对简单，这里不再赘述，我们重点关注一下流程的监测。由于在运营中，企业内外部各种状况不断出现，人员组织也会出现一些变更以及其他一些变化，业务流程的使用者或管理者需要随时掌握流程的执行状态与过程，因此他们就要求系统具备预警功能，同时可以让他们设定流程要追踪的关卡，并得到系统主动回报相关信息，及时处理相关问题。另外，服务器的流量与执行监控及流程存储（<span lang="EN-US">Process Repository</span>）的数据维护功能也相当重要。<span lang="EN-US">&nbsp;<br />
5.&nbsp;</span>业务流程最佳化<span lang="EN-US">&nbsp;<br />
</span>这是所有五个阶段的最后一步，也是业务流程管理系统生命周期迈入下一个循环的<span lang="EN-US">&#8220;</span>前夜<span lang="EN-US">&#8221;</span>，不是终结，而是开始。本阶段包括三个步骤<span lang="EN-US">:</span>测定（<span lang="EN-US">Measurement</span>）、报告（<span lang="EN-US">Reporting</span>）和改进（<span lang="EN-US">Improvement</span>）。三者呈逐步推进的关系，缺一不可。<span lang="EN-US">&nbsp;<br />
</span>测定能够向使用者和管理者提供流程的执行效率；通过报告工具（<span lang="EN-US">Reporting Tool</span>），企业可以对自己的组织行为有充分的了解，并将之作为持续改善的依据，这样企业才有可能策划出改进与最佳化的策略；改进是个持续性的活动，不断反复，朝向最佳化迈进。<span lang="EN-US">&nbsp;<br />
</span>有专家指出，这个阶段跟商业智能<span lang="EN-US">(BI</span>，<span lang="EN-US">&nbsp;Business Intelligence)</span>的技术与主题有异曲同工之处，不过我们应该看出，它们之间的差异在于<span lang="EN-US">BPM</span>可以自动记录和收集与流程有关的数据，让企业主管清楚哪些流程是在标准差内，哪些是在失控状态。同时，系统提供的报表都是使用者自行定义或查询的，而且无需<span lang="EN-US">IT</span>人员的参与。<span lang="EN-US">&nbsp;<br />
</span>从整个生命周期中，<span lang="EN-US">BPM</span>的重点在：<span lang="EN-US">&nbsp;<br />
◎&nbsp;</span>业务流程的分析<span lang="EN-US">(BPA)</span>和设计<span lang="EN-US">(BPD)</span>；<span lang="EN-US">&nbsp;<br />
◎&nbsp;</span>业务流程的改进<span lang="EN-US">(BPI)</span>和优化<span lang="EN-US">(BPO)</span>；<span lang="EN-US">&nbsp;<br />
◎&nbsp;</span>业务流程自动化<span lang="EN-US">(BPA)</span>；<span lang="EN-US">&nbsp;<br />
◎&nbsp;</span>业务过程集成<span lang="EN-US">(BPI)</span>；<span lang="EN-US">&nbsp;<br />
◎&nbsp;</span>业务过程重组<span lang="EN-US">(BPR)——</span>革命性变更；<span lang="EN-US">&nbsp;<br />
◎&nbsp;</span>业务过程外包<span lang="EN-US">(BPO)——</span>聚焦核心业务。</p>
<p style="margin-right: 0cm; margin-left: 0cm; font-size: 12pt; font-family: 宋体; line-height: 24px; "><span lang="EN-US" style="font-size: 9pt; line-height: 18px; "><img width="553" height="69" src="file://asp0243/wwwroot/BpmFlowWeb/cases/BPMFlow%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB--About%E5%88%86%E5%B1%82%E5%BC%8F%E6%9E%B6%E6%9E%84_clip_image002_0004.jpg"  alt="" /></span></p>
<p style="margin-right: 0cm; margin-left: 0cm; font-size: 12pt; font-family: 宋体; line-height: 24px; "><span class="style11" style="font-weight: bold; "><span lang="EN-US" style="font-size: 10.5pt; line-height: 21px; ">BPM</span></span><span class="style11" style="font-weight: bold; "><span style="font-size: 10.5pt; line-height: 21px; ">的未来趋势&nbsp;</span></span><span lang="EN-US" style="font-size: 9pt; line-height: 18px; "><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
</span><span class="style21"><span style="font-size: 9pt; line-height: 18px; ">我们期望最后为客户达到以下<span lang="EN-US">5</span>点：&nbsp;</span></span><span lang="EN-US" style="font-size: 9pt; line-height: 18px; "><br />
</span><span class="style21"><span style="font-size: 9pt; line-height: 18px; ">图形化工具<span lang="EN-US">——</span>设计来分析，模块和定义流程。这些工具专为需要建立流程流和设计新流的业务分析人员设计。这些流然后为将来执行而设定。&nbsp;</span></span><span lang="EN-US" style="font-size: 9pt; line-height: 18px; "><br />
</span><span class="style21"><span style="font-size: 9pt; line-height: 18px; ">运行时间执行引擎<span lang="EN-US">——</span>这是一个根本的统计机器执行定义流程流。随着流程流的执行，引擎可能要求自动服务或任务必须人力完成。服务可能由程序提供<span lang="EN-US">&#8211;</span>遗留和新的服务<span lang="EN-US">&#8211;</span>或通过企业可能是交易伙伴或分包商。运行时间环境维持每个流程当时的状态。&nbsp;</span></span><span lang="EN-US" style="font-size: 9pt; line-height: 18px; "><br />
</span><span class="style21"><span style="font-size: 9pt; line-height: 18px; ">机敏工具<span lang="EN-US">——</span>这个功能涉及流程调整，工作单管理和优先工作。&nbsp;</span></span><span lang="EN-US" style="font-size: 9pt; line-height: 18px; "><br />
</span><span class="style21"><span style="font-size: 9pt; line-height: 18px; ">监控和管理流的工具<span lang="EN-US">——</span>监控可能包括流程表现，完成程度或呼出条件，流程管理可能包括流程终止，扑救流程，工作平衡和重新流转。&nbsp;</span></span><span lang="EN-US" style="font-size: 9pt; line-height: 18px; "><br />
</span><span class="style21"><span style="font-size: 9pt; line-height: 18px; ">完成后分析工具<span lang="EN-US">——</span>这些工具用收到的统计数据衡量和调整业务流程。</span></span></p>
<img src ="http://www.blogjava.net/landy/aggbug/299557.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/landy/" target="_blank">独孤过客</a> 2009-10-24 11:08 <a href="http://www.blogjava.net/landy/archive/2009/10/24/299557.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]《软件架构设计》读书笔记</title><link>http://www.blogjava.net/landy/archive/2009/10/11/297808.html</link><dc:creator>独孤过客</dc:creator><author>独孤过客</author><pubDate>Sun, 11 Oct 2009 12:21:00 GMT</pubDate><guid>http://www.blogjava.net/landy/archive/2009/10/11/297808.html</guid><wfw:comment>http://www.blogjava.net/landy/comments/297808.html</wfw:comment><comments>http://www.blogjava.net/landy/archive/2009/10/11/297808.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/landy/comments/commentRss/297808.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/landy/services/trackbacks/297808.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/landy/archive/2009/10/11/297808.html'>阅读全文</a><img src ="http://www.blogjava.net/landy/aggbug/297808.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/landy/" target="_blank">独孤过客</a> 2009-10-11 20:21 <a href="http://www.blogjava.net/landy/archive/2009/10/11/297808.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>性能调优经验介绍</title><link>http://www.blogjava.net/landy/archive/2009/09/24/296351.html</link><dc:creator>独孤过客</dc:creator><author>独孤过客</author><pubDate>Thu, 24 Sep 2009 13:35:00 GMT</pubDate><guid>http://www.blogjava.net/landy/archive/2009/09/24/296351.html</guid><wfw:comment>http://www.blogjava.net/landy/comments/296351.html</wfw:comment><comments>http://www.blogjava.net/landy/archive/2009/09/24/296351.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/landy/comments/commentRss/296351.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/landy/services/trackbacks/296351.html</trackback:ping><description><![CDATA[一个典型的J2EE系统由DB、应用、应用（WEB）服务器、JVM组成。<br />
调优可分别针对这几个部分调优，下面介绍一下各个部分调优的一些经验。<br />
1. DB调优：DB调优主要关注下面几个方面：1）选择合适索引；2）避免复杂查询；3）尽量将复杂运算挪到应用中，以降低DB复杂，因为让应用可伸缩的代价远比让DB可伸缩的代价低；4）避免关联查询；调优的过程中，可借助Oracle的sql将比较耗时的SQL查询出来，再针对性的优化。<br />
2. 应用调优：应用调优主要分成两个方面：1）用Jprofiler或optimizeit等工具找出执行比较耗时的代码，并针对性的优化；2）应用运行时，通过打JVM的堆栈来分析应用的线程是否因资源竞争导致block，然后导致CPU无法充分利用，从而应用性能上不去，找出性能瓶颈后可针对性的做优化。<br />
3. 应用服务器调优：主要调节数据库连接池大小，连接数大小（tomcat就有连接数大小）等<br />
4. JVM调优：主要针对应用的特点，调整JVM参数，使应用运行更稳定。<br />
判断性能调优是否到位的方法是看数据库服务器和应用服务器的CPU占用率，首先要确认不是内存的问题，确认服务器没有产生页面交换；然后就看应用侧和DB侧的CPU是否能够达到90%以上了，一般来讲，要求应用侧的CPU使用率达到90%以上。<blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px;"></blockquote><blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px;"></blockquote>
<img src ="http://www.blogjava.net/landy/aggbug/296351.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/landy/" target="_blank">独孤过客</a> 2009-09-24 21:35 <a href="http://www.blogjava.net/landy/archive/2009/09/24/296351.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CXF使用JMS作为传输协议的配置</title><link>http://www.blogjava.net/landy/archive/2009/08/30/293230.html</link><dc:creator>独孤过客</dc:creator><author>独孤过客</author><pubDate>Sun, 30 Aug 2009 13:50:00 GMT</pubDate><guid>http://www.blogjava.net/landy/archive/2009/08/30/293230.html</guid><wfw:comment>http://www.blogjava.net/landy/comments/293230.html</wfw:comment><comments>http://www.blogjava.net/landy/archive/2009/08/30/293230.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/landy/comments/commentRss/293230.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/landy/services/trackbacks/293230.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/landy/archive/2009/08/30/293230.html'>阅读全文</a><img src ="http://www.blogjava.net/landy/aggbug/293230.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/landy/" target="_blank">独孤过客</a> 2009-08-30 21:50 <a href="http://www.blogjava.net/landy/archive/2009/08/30/293230.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>工作流合单的实现</title><link>http://www.blogjava.net/landy/archive/2009/07/06/285730.html</link><dc:creator>独孤过客</dc:creator><author>独孤过客</author><pubDate>Mon, 06 Jul 2009 15:22:00 GMT</pubDate><guid>http://www.blogjava.net/landy/archive/2009/07/06/285730.html</guid><wfw:comment>http://www.blogjava.net/landy/comments/285730.html</wfw:comment><comments>http://www.blogjava.net/landy/archive/2009/07/06/285730.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/landy/comments/commentRss/285730.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/landy/services/trackbacks/285730.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/landy/archive/2009/07/06/285730.html'>阅读全文</a><img src ="http://www.blogjava.net/landy/aggbug/285730.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/landy/" target="_blank">独孤过客</a> 2009-07-06 23:22 <a href="http://www.blogjava.net/landy/archive/2009/07/06/285730.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>三篇工作流实现机制好文，与有志之士分享</title><link>http://www.blogjava.net/landy/archive/2009/01/01/249433.html</link><dc:creator>独孤过客</dc:creator><author>独孤过客</author><pubDate>Thu, 01 Jan 2009 01:59:00 GMT</pubDate><guid>http://www.blogjava.net/landy/archive/2009/01/01/249433.html</guid><wfw:comment>http://www.blogjava.net/landy/comments/249433.html</wfw:comment><comments>http://www.blogjava.net/landy/archive/2009/01/01/249433.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/landy/comments/commentRss/249433.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/landy/services/trackbacks/249433.html</trackback:ping><description><![CDATA[http://www.workflowpatterns.com/patterns/resource/resource_modelling.php<br />
http://www.workflowpatterns.com/patterns/resource/workflow_structure.php<br />
http://www.workflowpatterns.com/patterns/resource/work_distribution.php<br />
<br />
workflowpatterns总结了工作流的许多模式，机理是petri网那一套。oracle的auqualogic实现机制就跟着三篇文章讲得差不多。<br />
有自己实现工作流引擎的朋友可以借鉴一下，本人对此也小有研究，欢迎交流。<br />
<img src ="http://www.blogjava.net/landy/aggbug/249433.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/landy/" target="_blank">独孤过客</a> 2009-01-01 09:59 <a href="http://www.blogjava.net/landy/archive/2009/01/01/249433.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JavaFX脚本编程语言参考--第一章 概览</title><link>http://www.blogjava.net/landy/archive/2008/12/04/244239.html</link><dc:creator>独孤过客</dc:creator><author>独孤过客</author><pubDate>Wed, 03 Dec 2008 16:06:00 GMT</pubDate><guid>http://www.blogjava.net/landy/archive/2008/12/04/244239.html</guid><wfw:comment>http://www.blogjava.net/landy/comments/244239.html</wfw:comment><comments>http://www.blogjava.net/landy/archive/2008/12/04/244239.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/landy/comments/commentRss/244239.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/landy/services/trackbacks/244239.html</trackback:ping><description><![CDATA[<span style="border-collapse: separate; color: #000000; font-family: 'Lucida Grande'; font-size: 16px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;">
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;">This chapter provides an overview of the&nbsp;JavaFX&#8482; Script programming language. At a high level, this chapter describes the programming language's main features, saving detailed coverage of specific constructs for subsequent chapters. This book is intended for designers and developers of rich Internet client applications and elements, that run in web pages, as&nbsp;Java&#8482; Web Start software, or as traditional desktop applications. Its content assumes the reader is familiar with either the JavaScript or&nbsp;Java&#8482; programming language, or both. While this document does not define a formal language specification, it can be considered a complete reference for all currently supported language features.</p>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;">本章提供了JavaFx脚本编程语言的一个概览。本章概述了这门编程语言的主要特性，后续章节将会详细介绍这些特性的细节。本书适用于副Internet客户端应用的设计者和开发者。这些应用可以作为Java Web Start软件运行在网页中或者作为传统的桌面应用。本书假定读者熟悉了javascript或java编程语言或者两者都熟悉。但是本书并不是正式的语言规范，可仅仅做为当前JavaFx支持的语言特性的一个完整的参考。<br />
</p>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;"><br />
</p>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;">The JavaFX Script programming language has the following distinctions:</p>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;">JavaFX脚本编程语言有如下的语言特色：<br />
</p>
<div>
<ul type="disc">
    <li style="padding-top: 8pt;">Uses a declarative syntax for specifying Graphical User Interface (GUI) components, enabling a developer's code to closely match the actual layout of the GUI.</li>
    <li style="padding-top: 8pt;">可使用声明式的语法编写图形界面组件，使得开发者的代码非常接近于GUI的实际布局。<br />
    </li>
    <li style="padding-top: 8pt;">Uses declarative data binding and incremental evaluation, enabling easy creation and configuration of individual components. Application data and GUI components are automatically synchronized.</li>
    <li style="padding-top: 8pt;">使用声明式的数据绑定和incremental evaluation(不知道如何翻译), 使得创建和配置组件变得简单。应用数据和GUI组件将自动同步。<br />
    </li>
    <li style="padding-top: 8pt;">Is statically typed, having most of the same code structuring, reuse, and encapsulation features that enable creating and maintaining very large programs in the Java programming language.</li>
    <li style="padding-top: 8pt;">它是一门静态类型的、绝大部分代码结构、复用和封装特性跟Java编程语言一样，可用来创建和维护大型应用。<br />
    </li>
    <li style="padding-top: 8pt;">Works with all major IDEs, including the NetBeans IDE, the reference implementation IDE for software development with the Java programming language.</li>
    <li style="padding-top: 8pt;">支持主流IDE，包括NetBeans IDE，NetBeans IDE是使用Java编程语言进行软件开发的IDE参考实现。<br />
    </li>
    <li style="padding-top: 8pt;">Is capable of supporting GUIs of any size or complexity.</li>
    <li style="padding-top: 8pt;">能够支持容易大小和复杂度的GUI。<br />
    </li>
    <li style="padding-top: 8pt;">Makes it easier to use Swing.</li>
    <li style="padding-top: 8pt;">它使Swing编程变得更容易<br />
    </li>
</ul>
</div>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;">The following sections present a quick tour of the JavaFX Script programming language. These sections provide a general introduction to its core syntax and capabilities, comparing and contrasting to the Java programming language where appropriate. Each topic is then covered in greater detail in subsequent chapters.</p>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;">接下来的小节是JavaFX脚本编程语言的一个快速指南，介绍了JavaFx的关键语法和能力，并且比较了它跟java编程语言之间的差异，每个主题将在后续的章节中详细的介绍。<br />
</p>
<div>
<div>
<div>
<div>
<h4 style="padding-top: 8pt; font-family: sans-serif; font-weight: bold; font-style: italic; font-size: 100%; color: #305070;">Scripts</h4>
</div>
</div>
</div>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;">In the JavaFX Script programming language, a "script" is one or more declarations or expressions. Evaluating the script evaluates the declarations or expressions, in order:</p>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;">在JavaFx中，&#8220;script&#8221;是一个以上的声明活表达式。执行脚本就是顺序执行脚本中的声明或表达式：<br />
</p>
<pre style="border-color: white; padding-top: 6pt; padding-bottom: 6pt; padding-left: 6pt; background-color: #ddddee; margin-left: 24pt; margin-right: 44pt;">var ten : Integer = 10;<br />
java.lang.System.out.println("Twice {ten} is {2 * ten}.");   </pre>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;">This prints out:</p>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;">上面的语句会打印出：<br />
</p>
<pre style="border-color: white; padding-top: 6pt; padding-bottom: 6pt; padding-left: 6pt; background-color: #ddddee; margin-left: 24pt; margin-right: 44pt;">Twice 10 is 20.</pre>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;">Unlike an application written in the Java programming language, a script need not contain any class definitions or functions.</p>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;">不想用java写的应用，脚本不需要包含class定义或者函数。<br />
</p>
</div>
<div>
<div>
<div>
<div>
<h4 style="padding-top: 8pt; font-family: sans-serif; font-weight: bold; font-style: italic; font-size: 100%; color: #305070;">Classes</h4>
</div>
</div>
</div>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;">Class definitions share many similarities with the Java programming language, but some differences are notable. State, for example, is information stored in&nbsp;<em>attributes</em>, not fields. Behavior is exposed through&nbsp;<em>functions</em>, not methods. The following example defines a simple&nbsp;<code>Rectangle</code>&nbsp;class that demonstrates the basic syntax of each.</p>
<pre style="border-color: white; padding-top: 6pt; padding-bottom: 6pt; padding-left: 6pt; background-color: #ddddee; margin-left: 24pt; margin-right: 44pt;">class Rectangle {<br />
<br />
attribute width: Integer;<br />
attribute height: Integer;<br />
<br />
function grow(): Void {<br />
grow(1);<br />
}<br />
<br />
function grow(amount: Integer): Void {<br />
width += amount;<br />
height += amount;<br />
}<br />
<br />
}<br />
</pre>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;">The JavaFX Script programming language supports&nbsp;<em>multiple inheritance</em>, making it possible to inherit from more than one class.</p>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;">Classes are covered in detail in&nbsp;<a href="classintro.html" target="_top" style="color: black;"><em>Chapter 2</em></a></p>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;">Attributes and Functions are covered in detail in&nbsp;<a href="functions.html" target="_top" style="color: black;"><em>Chapter 3</em></a></p>
</div>
<div>
<div>
<div>
<div>
<h4 style="padding-top: 8pt; font-family: sans-serif; font-weight: bold; font-style: italic; font-size: 100%; color: #305070;">Objects</h4>
</div>
</div>
</div>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;"><em>Object literals</em>&nbsp;provide a simple syntax for class instantiation. The following code creates a single instance of the&nbsp;<code>Rectangle</code>&nbsp;class defined previously, initializing its&nbsp;<code>width</code>&nbsp;and&nbsp;<code>height</code>attributes to&nbsp;<code>100</code>. (Note that&nbsp;<code>new</code>&nbsp;is not needed.)</p>
<pre style="border-color: white; padding-top: 6pt; padding-bottom: 6pt; padding-left: 6pt; background-color: #ddddee; margin-left: 24pt; margin-right: 44pt;">Rectangle {<br />
<br />
width: 100<br />
height: 100<br />
<br />
}</pre>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;">To store a reference to this object, use the&nbsp;<code>var</code>&nbsp;keyword:</p>
<pre style="border-color: white; padding-top: 6pt; padding-bottom: 6pt; padding-left: 6pt; background-color: #ddddee; margin-left: 24pt; margin-right: 44pt;">var myRect = Rectangle {<br />
<br />
width: 100<br />
height: 100<br />
}</pre>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;">Objects are covered in detail in&nbsp;<a href="classintro.html" target="_top" style="color: black;"><em>Chapter 2</em>&nbsp;</a>.</p>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;">Variables and basic data types are covered in detail in&nbsp;<a href="types.html" target="_top" style="color: black;"><em>Chapter 4</em></a></p>
</div>
<div>
<div>
<div>
<div>
<h4 style="padding-top: 8pt; font-family: sans-serif; font-weight: bold; font-style: italic; font-size: 100%; color: #305070;">Expressions and Operators</h4>
</div>
</div>
</div>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;">Like other programming languages, the JavaFX Script programming language supports expressions and operators.</p>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;"><a href="expressions.html" target="_top" style="color: black;"><em>Chapter 5</em>&nbsp;</a>discusses the expressions and operators available in the JavaFX Script programming language.</p>
</div>
<div>
<div>
<div>
<div>
<h4 style="padding-top: 8pt; font-family: sans-serif; font-weight: bold; font-style: italic; font-size: 100%; color: #305070;">Sequences</h4>
</div>
</div>
</div>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;">A&nbsp;<em>sequence</em>&nbsp;holds an ordered list of objects. This is roughly analogous to Java programming language arrays. Both hold multiple values and are accessed by index starting at 0.</p>
<pre style="border-color: white; padding-top: 6pt; padding-bottom: 6pt; padding-left: 6pt; background-color: #ddddee; margin-left: 24pt; margin-right: 44pt;">var week = ["Monday","Tuesday","Wednesday","Thursday",<br />
"Friday","Saturday","Sunday"];<br />
var mon = week[0];<br />
var wed = week[2];<br />
var fri = week[4];<br />
</pre>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;">Sequence&nbsp;<em>slices</em>&nbsp;are also supported:</p>
<pre style="border-color: white; padding-top: 6pt; padding-bottom: 6pt; padding-left: 6pt; background-color: #ddddee; margin-left: 24pt; margin-right: 44pt;">var week = ["Monday","Tuesday","Wednesday","Thursday",<br />
"Friday","Saturday","Sunday"];<br />
var weekdays = week[0..4]; // first slice<br />
var weekend = week[5..6]; // second slice<br />
</pre>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;"><a href="sequences.html" target="_top" style="color: black;"><em>Chapter 6</em>&nbsp;</a>covers the basics of declaring sequences, while&nbsp;<a href="comprehensions.html" target="_top" style="color: black;"><em>Chapter 7</em>&nbsp;</a>focuses on&nbsp;<em>using</em>&nbsp;sequences.</p>
</div>
<div>
<div>
<div>
<div>
<h4 style="padding-top: 8pt; font-family: sans-serif; font-weight: bold; font-style: italic; font-size: 100%; color: #305070;">Data Binding</h4>
</div>
</div>
</div>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;"><em>Data binding</em>&nbsp;provides a simple syntax for synchronizing the state of multiple objects. When two objects are&nbsp;<em>bound</em>&nbsp;to each other, the second object's value automatically changes whenever the first object is updated. A common use of data binding is to keep GUI components synchronized with their underlying data.</p>
<pre style="border-color: white; padding-top: 6pt; padding-bottom: 6pt; padding-left: 6pt; background-color: #ddddee; margin-left: 24pt; margin-right: 44pt;">import javafx.application.Frame;<br />
import javafx.application.Stage;<br />
import javafx.scene.text.Text;<br />
<br />
var myString = "Hello World!";<br />
<br />
Frame {<br />
width: 50<br />
height: 50<br />
visible: true<br />
stage: Stage {<br />
content: Text {<br />
content: bind myString<br />
}<br />
}<br />
}<br />
<br />
// If some other part of code changes myString<br />
// then the GUI's text will automatically change<br />
// as well.<br />
</pre>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;">Data Binding is covered in detail in&nbsp;<a href="binding.html" target="_top" style="color: black;"><em>Chapter 8</em>&nbsp;</a>.</p>
</div>
<div>
<div>
<div>
<div>
<h4 style="padding-top: 8pt; font-family: sans-serif; font-weight: bold; font-style: italic; font-size: 100%; color: #305070;">Triggers</h4>
</div>
</div>
</div>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;"><em>Triggers</em>&nbsp;are blocks of code that run when certain conditions are true. For example, you may want to be alerted if an attribute's value has been set to something that is inappropriate. The following example shows the basic trigger syntax:</p>
<pre style="border-color: white; padding-top: 6pt; padding-bottom: 6pt; padding-left: 6pt; background-color: #ddddee; margin-left: 24pt; margin-right: 44pt;">import java.lang.System;<br />
<br />
ReplaceDemo {<br />
<br />
mySensitiveData: "Will anyone notice?"<br />
<br />
}<br />
<br />
class ReplaceDemo {<br />
attribute mySensitiveData: String<br />
on replace {<br />
System.out.println("I noticed a change!");                      <br />
};<br />
<br />
// application-specific safeguarding code would go here <br />
}<br />
</pre>
<p style="padding-top: 8pt; font-family: Tahoma,Arial,sans-serif; background-color: white; color: black; font-size: 12px;">Triggers are covered in detail in&nbsp;<a href="triggers.html" target="_top" style="color: black;"><em>Chapter 9</em>&nbsp;</a>.</p>
</div>
</span>
<img src ="http://www.blogjava.net/landy/aggbug/244239.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/landy/" target="_blank">独孤过客</a> 2008-12-04 00:06 <a href="http://www.blogjava.net/landy/archive/2008/12/04/244239.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>快速构建面向服务的应用-2</title><link>http://www.blogjava.net/landy/archive/2008/11/19/241510.html</link><dc:creator>独孤过客</dc:creator><author>独孤过客</author><pubDate>Wed, 19 Nov 2008 14:55:00 GMT</pubDate><guid>http://www.blogjava.net/landy/archive/2008/11/19/241510.html</guid><wfw:comment>http://www.blogjava.net/landy/comments/241510.html</wfw:comment><comments>http://www.blogjava.net/landy/archive/2008/11/19/241510.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/landy/comments/commentRss/241510.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/landy/services/trackbacks/241510.html</trackback:ping><description><![CDATA[<p style="text-indent:21.0pt"><span style="font-family:宋体;">总结一下，个人认为企业应用的核心组成要素是&#8220;数据</span> + <span style="font-family:宋体;">服务&#8221;，</span>
<span style="font-family:宋体;">而服务又分为原子服务，聚合服务，流程服务。权限也是一种数据，供&#8220;权限服务&#8221;消费。后面暂不考虑权限处理。信令流因为用得少，很多人可能都不知道是什么东西，这里也不考虑，如果遇到了记得使用流程技术把信号的处理也流程化就可以了，可参考</span>apache<span style="font-family:宋体;">的</span>SCXML<span style="font-family:宋体;">，虽然号称是个状态机引擎，但是请君用你的慧眼观察一下它的</span>schema<span style="font-family:宋体;">，显然是一个活动图。</span></p>
<p style="text-indent:21.0pt"><span style="font-family:宋体;">接下来的推导分为两个阶段，第一阶段先推导支撑技术，第二阶段再推导以什么样的开发方式将这些支撑技术串起来，达到快速开发的目的。</span></p>
<p style="text-indent:21.0pt"><span style="font-family:宋体;">下表中列出了对上面的核心组成要素（数据</span>+<span style="font-family:宋体;">服务）的一些支撑技术：</span></p>
<table border="1" cellspacing="0" cellpadding="0" style="border-collapse: collapse; border-width: initial; border-color: initial; ">
    <tbody>
        <tr>
            <td width="189" valign="top" style="width: 142pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><span style="font-family:宋体;">要素</span></p>
            </td>
            <td width="189" valign="top" style="width: 142.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><span style="font-family:宋体;">支撑技术</span></p>
            </td>
            <td width="189" valign="top" style="width: 142.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><span style="font-family:宋体;">考虑</span></p>
            </td>
        </tr>
        <tr>
            <td width="189" valign="top" style="width: 142pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><span style="font-family:宋体;">数据实体</span></p>
            </td>
            <td width="189" valign="top" style="width: 142.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><font  face="宋体"><span style="font-size:10.5pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;Times New Roman&quot;;">Java</span><span style="font-size:10.5pt;font-family:宋体;Times New Roman&quot;;">，</span><span style="font-size:10.5pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;Times New Roman&quot;;">sdo</span><span style="font-size:10.5pt;font-family:宋体;Times New Roman&quot;;">，</span><span style="font-size:10.5pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;Times New Roman&quot;;">c++</span><span style="font-size:10.5pt;font-family:宋体;Times New Roman&quot;;">等等</span></font></p>
            </td>
            <td width="189" valign="top" style="width: 142.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><font  face="宋体"><br />
            </font></p>
            </td>
        </tr>
        <tr>
            <td width="189" valign="top" style="width: 142pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><span style="font-family:宋体;">原子服务</span></p>
            </td>
            <td width="189" valign="top" style="width: 142.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;">Java<span style="font-family:宋体;">，</span>c++<span style="font-family:宋体;">，</span>c<span style="font-family:宋体;">，脚本等等</span></p>
            </td>
            <td width="189" valign="top" style="width: 142.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><span style="font-family:宋体;">没什么可说的，码肯定是要编的</span></p>
            </td>
        </tr>
        <tr>
            <td width="189" valign="top" style="width: 142pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><span style="font-family:宋体;">聚合服务</span></p>
            </td>
            <td width="189" valign="top" style="width: 142.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;">SCA</p>
            </td>
            <td width="189" valign="top" style="width: 142.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><span style="font-family:宋体;">用</span>sca<span style="font-family:宋体;">来将原子服务装配成聚合服务。如果想要使用什么数据转换啊，接口映射啊，安全控制啊之类的特性的话也可以引进</span>ESB<span style="font-family:宋体;">，作为</span>SCA<span style="font-family:宋体;">的一种</span>container<span style="font-family:宋体;">。</span></p>
            </td>
        </tr>
        <tr>
            <td width="189" valign="top" style="width: 142pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><span style="font-family:宋体;">操作流程</span></p>
            </td>
            <td width="189" valign="top" style="width: 142.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><span style="font-family:宋体;">实现一个</span>SCA<span style="font-family:宋体;">中的</span>container<span style="font-family:宋体;">，接受操作流程的描述文件的作为执行文件</span></p>
            </td>
            <td width="189" valign="top" style="width: 142.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            </td>
        </tr>
        <tr>
            <td width="189" valign="top" style="width: 142pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><span>View
            process</span></p>
            </td>
            <td width="189" valign="top" style="width: 142.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><span style="font-family:宋体;">在</span>web<span style="font-family:宋体;">应用下，采用一种</span>webflow<span style="font-family:宋体;">的实现，</span>swing<span style="font-family:宋体;">下就自己写把。</span></p>
            </td>
            <td width="189" valign="top" style="width: 142.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            </td>
        </tr>
        <tr>
            <td width="189" valign="top" style="width: 142pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><span>Business
            process</span></p>
            </td>
            <td width="189" valign="top" style="width: 142.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;">WFA<span style="font-family:宋体;">类流程，</span>EOS or OBE<span style="font-family:宋体;">类似的工作流引擎，可直接将</span>EOS<span style="font-family:宋体;">或者</span>OBE<span style="font-family:宋体;">提供的</span>API<span style="font-family:宋体;">作为一个原子组件</span></p>
            </td>
            <td width="189" valign="top" style="width: 142.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            </td>
        </tr>
        <tr>
            <td width="189" valign="top" style="width: 142pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p>Orchestration Process</p>
            </td>
            <td width="189" valign="top" style="width: 142.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;">EAI<span style="font-family:宋体;">类流程，用</span>ODE<span style="font-family:宋体;">，一个</span>bpel<span style="font-family:宋体;">引擎，也作为</span>SCA<span style="font-family:宋体;">的一个</span>container<span style="font-family:宋体;">，</span>BPEL<span style="font-family:宋体;">作为一种组件实现方式</span></p>
            </td>
            <td width="189" valign="top" style="width: 142.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            </td>
        </tr>
    </tbody>
</table>
<p style="text-indent:21.0pt"><span style="font-family:宋体;">下面在列一些辅助支撑技术，这些技术是为了让企业应用这些大厦能够构建的更快，毕竟盖房子，有了水泥和砖是不够的，还要有扁担，簸箕等等。</span></p>
<table border="1" cellspacing="0" cellpadding="0" style="border-collapse: collapse; border-width: initial; border-color: initial; ">
    <tbody>
        <tr>
            <td width="284" valign="top" style="width: 213.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><span style="font-family:宋体;">技术</span></p>
            </td>
            <td width="284" valign="top" style="width: 213.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><span style="font-family:宋体;">作用</span></p>
            </td>
        </tr>
        <tr>
            <td width="284" valign="top" style="width: 213.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><span style="font-family:宋体;">元数据技术</span></p>
            </td>
            <td width="284" valign="top" style="width: 213.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><span style="font-family:宋体;">利用元数据描述数据实体，以及对数据实体、实体属性的约束、权限等信息，可以基于</span>RBAC<span style="font-family:宋体;">的权限系统设计思路，将用户组织机构与权限关联起来，实现自动生成页面时，对特定用户的权限控制，等等其它的东东。</span></p>
            </td>
        </tr>
        <tr>
            <td width="284" valign="top" style="width: 213.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><span style="font-family:宋体;">表单生成技术</span></p>
            </td>
            <td width="284" valign="top" style="width: 213.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><span style="font-family:宋体;">根据元数据生成表单，支持可视化的定制表单布局等，支持生成</span>jsp<span style="font-family:宋体;">等，如果需要多种展现，可以生成多种特定的展现实现，如</span>swing<span style="font-family:宋体;">界面等</span></p>
            </td>
        </tr>
        <tr>
            <td width="284" valign="top" style="width: 213.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><span style="font-family:宋体;">图形化建模技术</span></p>
            </td>
            <td width="284" valign="top" style="width: 213.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><span style="font-family:宋体;">可视化的建模</span>view process<span style="font-family:宋体;">，</span><span>Orchestration
            process</span><span style="font-family:宋体;">，</span>business process<span style="font-family:宋体;">，</span>operation process<span style="font-family:宋体;">等</span></p>
            </td>
        </tr>
        <tr>
            <td width="284" valign="top" style="width: 213.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><span style="font-family:宋体;">图形化组件装配技术</span></p>
            </td>
            <td width="284" valign="top" style="width: 213.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><span style="font-family:宋体;">可视化的将组件装配成大粒度组件等</span></p>
            </td>
        </tr>
        <tr>
            <td width="284" valign="top" style="width: 213.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><span style="font-family:宋体;">代码生成技术</span></p>
            </td>
            <td width="284" valign="top" style="width: 213.05pt; padding-top: 0cm; padding-right: 5.4pt; padding-bottom: 0cm; padding-left: 5.4pt; ">
            <p style="text-indent:0cm;"><font  face="宋体"><span style="font-size:10.5pt;
            font-family:宋体;Times New Roman&quot;;">根据元数据生成数据实体、</span><span style="font-size:10.5pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;Times New Roman&quot;;">DAO</span><span style="font-size:10.5pt;font-family:宋体;Times New Roman&quot;;">代码等</span></font></p>
            </td>
        </tr>
    </tbody>
</table>
<span style="font-size:10.5pt;font-family:宋体;Times New Roman&quot;;">这里这个</span><span style="font-size:10.5pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;Times New Roman&quot;;">SCE</span><span style="font-size:10.5pt;font-family:宋体;Times New Roman&quot;;">大致包括一些什么东西就清楚了，下面用一个序列图来表示用户基于</span><span style="font-size:10.5pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;Times New Roman&quot;;">SCE</span><span style="font-size:10.5pt;font-family:宋体;Times New Roman&quot;;">的一种自顶向下的开发方式。当然也应该支持自下而上。</span>
<img src ="http://www.blogjava.net/landy/aggbug/241510.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/landy/" target="_blank">独孤过客</a> 2008-11-19 22:55 <a href="http://www.blogjava.net/landy/archive/2008/11/19/241510.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>由google的V8 javascript引擎想到的</title><link>http://www.blogjava.net/landy/archive/2008/11/17/241056.html</link><dc:creator>独孤过客</dc:creator><author>独孤过客</author><pubDate>Mon, 17 Nov 2008 15:33:00 GMT</pubDate><guid>http://www.blogjava.net/landy/archive/2008/11/17/241056.html</guid><wfw:comment>http://www.blogjava.net/landy/comments/241056.html</wfw:comment><comments>http://www.blogjava.net/landy/archive/2008/11/17/241056.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/landy/comments/commentRss/241056.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/landy/services/trackbacks/241056.html</trackback:ping><description><![CDATA[现在javascript虚拟机开始出现了，这对flex等新东东来讲不是个好消息，flex的优势在于具有丰富的UI控件，用户可以容易的编写界面，但是当javascript虚拟机出来后，这点优势很快将荡然无存，跟java类似，java预置了很多界面相关的组件，javascript虚拟机也可以做同样的事情，将一些常用的UI控件用javascript封装好提供出来，提供类似于java虚拟机一样的诊断工具供检测性能问题、内存泄露问题等等，这样javascript就可以做到展现逻辑全部在客户端，服务端与客户端之间传递的只是数据（事实上现在已经有大量框架支持了），展现能力做到跟flex持平，但javascript有先发优势，而且成为了浏览器的标准，能够直接操纵html文档，这些都是flex的弱项... 但是当前javascript规范不统一，多版本存在带来了javascript编程的复杂性，用户需要关心javascript在特定浏览器下的特定使用方式，不过当前各大巨头正试图规范javascript，但愿早日finalize啊！！呵呵。finalize之后，javasciript必将有一番改头换面的变化，让我们拭目以待把。
<div>看着flex，越看越像另一种html，只是展现更丰富一些，互动能力更强一些，不看好它的前景。</div>
<img src ="http://www.blogjava.net/landy/aggbug/241056.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/landy/" target="_blank">独孤过客</a> 2008-11-17 23:33 <a href="http://www.blogjava.net/landy/archive/2008/11/17/241056.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>快速构建面向服务的应用-1</title><link>http://www.blogjava.net/landy/archive/2008/11/07/239348.html</link><dc:creator>独孤过客</dc:creator><author>独孤过客</author><pubDate>Fri, 07 Nov 2008 15:50:00 GMT</pubDate><guid>http://www.blogjava.net/landy/archive/2008/11/07/239348.html</guid><wfw:comment>http://www.blogjava.net/landy/comments/239348.html</wfw:comment><comments>http://www.blogjava.net/landy/archive/2008/11/07/239348.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/landy/comments/commentRss/239348.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/landy/services/trackbacks/239348.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 快速构建面向服务的应用&nbsp;&nbsp;<a href='http://www.blogjava.net/landy/archive/2008/11/07/239348.html'>阅读全文</a><img src ="http://www.blogjava.net/landy/aggbug/239348.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/landy/" target="_blank">独孤过客</a> 2008-11-07 23:50 <a href="http://www.blogjava.net/landy/archive/2008/11/07/239348.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java SE 6 Beta 2 发布...Mustang 8大看点</title><link>http://www.blogjava.net/landy/archive/2006/06/23/54796.html</link><dc:creator>独孤过客</dc:creator><author>独孤过客</author><pubDate>Fri, 23 Jun 2006 15:55:00 GMT</pubDate><guid>http://www.blogjava.net/landy/archive/2006/06/23/54796.html</guid><wfw:comment>http://www.blogjava.net/landy/comments/54796.html</wfw:comment><comments>http://www.blogjava.net/landy/archive/2006/06/23/54796.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/landy/comments/commentRss/54796.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/landy/services/trackbacks/54796.html</trackback:ping><description><![CDATA[Java 平台的第六个版本, Standard Edition (Java SE), 代号<span style="COLOR: blue">Mustang</span>, 发布了第二个Beta版本.<br /><br /><a href="http://www.matrix.org.cn/resource/news/516_JavaSE+6+Beta.html" target="_new">今年年初Mustang发布了第一个Beta版本</a>.掀开了Java SE 6 的神秘面纱.<br /><br />这一次,是时隔4个月发布第二次Beta版本.<br /><br /><span style="COLOR: red">Java SE 6 Beta 2 (Mustang) 有什么新东西? 有什么值得开发者关注?</span><br /><br /><b>简化Web Services</b><br />Mustang 将 简化Web services 的开发和发布. XML和Web服务一直都是Mustang的关注重点.. Mustang为此引入了JAX-WS(Java Architecture for XML-Web Services) 2.0 以及JAXB(Java Architecture for XML Binding) 2.0.. 同时还有Streaming API for XML (STaX), 它提供了一个双向API，这个API可以通过一个事件流来读取或者写入XML，其中包括跳过某个部分，然后直接关注与文档中的另外一个小部分的能力。 <br /><br /><br /><b>Scripting,整合脚本语言</b><br />目前来讲，Java 开发者们必须在Java之外独立地额外编码来使用non-Java 脚本语言。这个头痛的问题将被Mustang 消灭，开发者将更加轻松的使用Perl、PHP、Python、JavaScript 和Ruby等脚本语言。新的框架将允许人们操作任意的脚本语言，和使用Java 对象。<br /><br />Java SE6中实现了JSR223。这是一个脚本框架，提供了让脚本语言来访问Java内部的方法。你可以在运行的时候找到脚本引擎，然后调用这个引擎去执行脚本。这个脚本API允许你为脚本语言提供Java支持。另外，Web Scripting Framework允许脚本代码在任何的Servlet容器（例如Tomcat）中生成Web内容。<br /><br /><b>Database,绑定Derby</b><br />开源嵌入式数据库 Derby(JavaDB) 绑定在JDK 1.6中.具体可以参考:<a href="http://www.matrix.org.cn/resource/news/785_Derby.html" target="_new">JDK 1.6 将绑定开源数据库 Derby</a><br /><br /><b>更丰富的Desktop APIs</b><br />Mustang中拥有更多强的桌面API提供给开发者, 开发者可以更简单地开发更强大的桌面应用, 比如启动界面的支持,系统托盘的支持,JTable排序等等<br /><br /><b>监视和管理</b><br />Java SE 6中对内存泄漏增强了分析以及诊断能力。当遇到java.lang.OutOfMemory异常的时候，可以得到一个完整的堆栈信息，并且当堆已经满了的时候，会产生一个Log文件来记录这个致命错误。另外，JVM还添加了一个选项，允许你在堆满的时候运行脚本。(这也就是提供了另外一种方法来诊断错误)<br /><br />增强的JMX 监视API在MBean的属性值传入了一个特定的参数的时候，允许这个应用程序发送一个事件通告。（这里的属性值可以在很复杂的类型中）<br /><br />对于Solaris 10的用户，为Solaris提供的Hotspot JVM中，提供了一种通过Solaris DTrace(这是个系统的调试工具)来追踪显示JVM内部的活动情况，包括垃圾收集，类装载，线程，锁等等。<br /><br /><b>Pluggable Annotations</b><br />从Java SE 5  带来得新特性Annotations,将在Mustang继续扮演重要角色.. <br /><br /><b>Compiler API:访问编译器</b><br />对于Java开发工具, 或者Web框架 等的开发者来说, 利用编译器编译动态生成的代码, 是一个普遍的需求.<br /><br />Mustang实现了JSR 199,  提供了Java编译器API(应用程序接口)，允许你从一个Java应用程序中去编译其他的Java源程序--比如在应用程序中动态生成的一些源代码..<br /><br /><b>Security:安全性</b><br />Java SE 6的安全部分，增加了 XML-Digital Signature (XML-DSIG) APIs, 整合了GSS/Kerberos的操作API，LDAP上的JAAS认证。<br /><br /><br /><br /><br />Java SE 6 Beta 2 下载：<br /><a href="http://java.sun.com/javase/6/download.jsp?feed=JSC" target="_new">http://java.sun.com/javase/6/download.jsp?feed=JSC</a><br /><img src ="http://www.blogjava.net/landy/aggbug/54796.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/landy/" target="_blank">独孤过客</a> 2006-06-23 23:55 <a href="http://www.blogjava.net/landy/archive/2006/06/23/54796.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用 Java 5 RowSet 新特性访问 IBM DB2 数据库</title><link>http://www.blogjava.net/landy/archive/2006/06/10/51879.html</link><dc:creator>独孤过客</dc:creator><author>独孤过客</author><pubDate>Sat, 10 Jun 2006 11:43:00 GMT</pubDate><guid>http://www.blogjava.net/landy/archive/2006/06/10/51879.html</guid><wfw:comment>http://www.blogjava.net/landy/comments/51879.html</wfw:comment><comments>http://www.blogjava.net/landy/archive/2006/06/10/51879.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/landy/comments/commentRss/51879.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/landy/services/trackbacks/51879.html</trackback:ping><description><![CDATA[
		<p>2006 年 4 月 10 日</p>
		<blockquote>Java 5 在 Java Database Connectivity (JDBC) 方面加强了支持，其中加入了新的包 javax.sql.rowset，javax.sql.rowset.serial，javax.sql.rowset.spi。本文将通过实例来演示这些新的特性。</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="IDALC0MB">
						<span class="atitle">
								<font face="Arial" size="4">RowSet 新特性简介</font>
						</span>
				</a>
		</p>
		<p>Java 5在Java Database Connectivity (JDBC)方面加强了支持，其中加入了新的包javax.sql.rowset，javax.sql.rowset.serial，javax.sql.rowset.spi。从RowSet接口继承规定了五个新的接口：</p>
		<p>1. CachedRowSet： CachedRowset可以不用与数据源建立长期的连接，只有当从数据库读取数据或是往数据库写入数据的时候才会与数据库建立连接，它提供了一种轻量级的访问数据库的方式，其数据均存在内存中。</p>
		<p>2. JdbcRowSet：对ResultSet的对象进行包装，使得可以将ResultSet对象做为一个JavaBeans ™ 组件。</p>
		<p>3. FilteredRowSet：继承自CachedRowSet，可以根据设置条件得到数据的子集。</p>
		<p>4. JoinRowSet：继承自CachedRowSet，可以将多个RowSet对象进行SQL Join语句的合并。</p>
		<p>5. WebRowSet：继承自CachedRowSet，可以将WebRowSet对象输出成XML格式。</p>
		<p>下面分别演示如何使用这五个新接口。<br /><br /></p>
		<p>
				<a name="IDAXC0MB">
						<span class="atitle">
								<font face="Arial" size="4">实验环境</font>
						</span>
				</a>
		</p>
		<p>IBM DB2 Universal 8.1<br />数据库名：DemoDB<br />数据库用户名：db2admin<br />数据库密码：password</p>
		<p>
				<br />
		</p>
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-zhanghz2/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="IDAED0MB">
						<span class="atitle">
								<font face="Arial" size="4">CachedRowSet</font>
						</span>
				</a>
		</p>
		<p>CachedRowSet可以通过调用populate(ResuletSet rs)来生成数据，一旦获得数据，CachedRowSet就可以断开与数据库的连接，直到往数据库写入数据的时候才需建立连接。</p>
		<p>可以使用自己扩展的或是使用Reference Implement的实现类进行访问数据库。下面的代码演示了如何根据ResultSet建立一个CachedRowSet对象，在中断与数据库连接的情况下，读取数据，并做更新，最后再获取数据库连接，将更新落实到数据库中。</p>
		<p>
				<br />
		</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">public static void testCachedRowSet(){
	Connection conn = null;
	try {
		// 获得数据库连接
	    conn= DriverManager.getConnection(DB2URL, DB2USER, DB2PASSWORD);
	    Statement stmt = conn.createStatement();
	    // 查询数据库，获得表数据
	    ResultSet rs = stmt.executeQuery("select * from student");//$NON-NLS-1$
	    // 根据ResultSet对象生成CachedRowSet类型的对象
	    CachedRowSetImpl crs = new CachedRowSetImpl();
	    crs.populate(rs);
	    // 关闭ResultSet
		rs.close();
	    // 关闭数据库的连接
	    conn.close();
	    // 在中断与数据库连接的情况下，对CachedRowSet进行操作
	    operateOnRowSet(crs);
	    // 重新获取与数据库的连接
	    conn= DriverManager.getConnection(DB2URL, DB2USER, DB2PASSWORD);
	    // 将CachedRowSet的内容更新到数据库
	    crs.acceptChanges(conn);
	    // 关闭CachedRowSet
	    crs.close();
	    // 关闭数据库连接
	    conn.close();
	} catch (InstantiationException e) {
	    System.out.println("Andrew: InstantiationException!");//$NON-NLS-1$
	} catch (IllegalAccessException e) {
	    System.out.println("Andrew: IllegalAccessException!");//$NON-NLS-1$
	} catch (ClassNotFoundException e) {
	    System.out.println("Andrew: ClassNotFoundException!");//$NON-NLS-1$
	}catch (SQLException e) {
	  	System.out.println("Andrew: SQLException!");//$NON-NLS-1$
		e.printStackTrace();
	}	
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>其中operateOnRowSet方法遍历读取RowSet中的元素，并将id值加1。RowSet允许注册监听器，可以在光标移动，RowSet发生改变时触发。其具体代码如下：</p>
		<p>
				<br />
		</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">public static void operateOnRowSet(RowSet rs){
	// 为RowSet注册监听器
	MyRowsetListener myListener = new MyRowsetListener();
    rs.addRowSetListener(myListener);
    // 操作RowSet数据
	try{
		// 遍历读取数据
		while (rs.next()) {
			String id = rs.getString("ID");//$NON-NLS-1$
	        String name = rs.getString("NAME");//$NON-NLS-1$
	        System.out.println("ID="+id+",NAME="+name);//$NON-NLS-1$
	        //在id最末位连接"1"
	        rs.updateString(1, id+"1");
	    }
	}catch (SQLException e) {
	    System.out.println("Andrew: SQLException!");//$NON-NLS-1$
		e.printStackTrace();
	}
}
class MyRowsetListener implements RowSetListener{
	// 光标发生移动
	public void cursorMoved(RowSetEvent event) {
		System.out.println("cursor moved");
	}
	// row发生改变
	public void rowChanged(RowSetEvent event) {
		System.out.println("row changed");
	}
	// RowSet发生改变
	public void rowSetChanged(RowSetEvent event) {
		System.out.println("row set changed");
	}
}
public static void main(String[] args) {
	try {
		Class.forName(DB2DRIVER).newInstance();
	} catch (InstantiationException e) {
		System.out.println("Andrew: InstantiationException!");//$NON-NLS-1$
	} catch (IllegalAccessException e) {
		System.out.println("Andrew: IllegalAccessException!");//$NON-NLS-1$
	} catch (ClassNotFoundException e) {
		System.out.println("Andrew: ClassNotFoundException!");//$NON-NLS-1$
	}
	testCachedRowSet();
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>上面的程序的运行结果如下：</p>
		<p>
				<br />
		</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">cursor moved
ID=001,NAME=zhou
cursor moved
ID=002,NAME=zhang
cursor moved
cursor moved
cursor moved
cursor moved
cursor moved
cursor moved
row set changed
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>并且数据库中的id更新为0011，0021。</p>
		<p>
				<br />
		</p>
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-zhanghz2/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="IDADE0MB">
						<span class="atitle">
								<font face="Arial" size="4">JdbcRowSet</font>
						</span>
				</a>
		</p>
		<p>JdbcRowSet功能与ResultSet类似，与CachedRowSet不同，JdbcRowSet在操作时保持与数据库的连接。可以将与数据库连接的URL，用户名，密码以及执行的SQL语句通过setXXX形式绑定。另外，JdbcRowSet返回的结果默认是可以上下滚动和可更新的，当然这需要数据库厂商提供的JDBC Driver支持。下面的代码演示了如何通过set方法设定数据库连接参数，以及如何操作JdbcRowSet对象。</p>
		<p>
				<br />
		</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">public static void testJdbcRowSet() {
	JdbcRowSetImpl jrs = new JdbcRowSetImpl();
	try {
		// 设置连接数据库的URL
		jrs.setUrl(DB2URL);
		// 设置连接数据库的用户名
		jrs.setUsername(DB2USER);
		// 设置连接数据库的密码
		jrs.setPassword(DB2PASSWORD);
		// 设置执行数据库的SQL语句
		jrs.setCommand("select * from student");
		// 执行操作
		jrs.execute();
		// 对获得的JdbcRowSet进行操作
		operateOnRowSet(jrs);
		// 关闭JdbcRowset
		jrs.close();
	} catch (SQLException e) {
		System.out.println("Andrew: SQLException!");//$NON-NLS-1$
		e.printStackTrace();
	}
}

public static void operateOnRowSet(RowSet rs) {
	// 为RowSet注册监听器
	MyRowsetListener myListener = new MyRowsetListener();
	rs.addRowSetListener(myListener);
	// 操作RowSet数据
	try {
		// 遍历读取数据
		while (rs.next()) {
			String id = rs.getString("ID");//$NON-NLS-1$
			String name = rs.getString("NAME");//$NON-NLS-1$
			System.out.println("ID=" + id + ",NAME=" + name);//$NON-NLS-1$
		}
	} catch (SQLException e) {
		System.out.println("Andrew: SQLException!");//$NON-NLS-1$
		e.printStackTrace();
	}
}
	</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>其运行结果如下：</p>
		<p>
				<br />
		</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">cursor moved
ID=0011,NAME=zhou
cursor moved
ID=0021,NAME=zhang
cursor moved
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<font face="Lucida Console">
												<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" />
										</font>
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<font face="Lucida Console">
												<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
												<br />
										</font>
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<font face="Lucida Console">
																				<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																				<br />
																		</font>
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-zhanghz2/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="IDAYE0MB">
						<span class="atitle">
								<font face="Arial" size="4">FilteredRowSet</font>
						</span>
				</a>
		</p>
		<p>FilteredRowSet接口中规定了可以设定过滤器，其过滤接口为Predicate接口，必须实现Predicate接口中的evaluate方法。具体的代码如下：</p>
		<p>
				<br />
		</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">public static void testFilteredRowSet() {
	try {
		// 获得数据库连接
		Connection conn = DriverManager.getConnection(DB2URL, DB2USER,
			DB2PASSWORD);
		Statement stmt = conn.createStatement();
		// 查询数据库，获得表数据
		ResultSet rs = stmt.executeQuery("select * from student");//$NON-NLS-1$
		FilteredRowSet frs = new FilteredRowSetImpl();
		frs.populate(rs);
		// 设置过滤器
		MyDBFilter filter = new MyDBFilter(11, 100);
		frs.setFilter(filter);
		operateOnRowSet(frs);
		// 关闭FilteredRowSet
		frs.close();
		// 关闭与数据库的连接
		conn.close();
	} catch (SQLException e) {
		System.out.println("Andrew: SQLException!");//$NON-NLS-1$
		e.printStackTrace();
	}
}

public static void operateOnRowSet(RowSet rs) {
	// 为RowSet注册监听器
	System.out.println("operateOnRowSet!");//$NON-NLS-1$
	MyRowsetListener myListener = new MyRowsetListener();
	rs.addRowSetListener(myListener);
	// 操作RowSet数据
	try {
		// 遍历读取数据
		while (rs.next()) {
			String id = rs.getString("ID");//$NON-NLS-1$
			String name = rs.getString("NAME");//$NON-NLS-1$
			System.out.println("ID=" + id + ",NAME=" + name);//$NON-NLS-1$
		}
	} catch (SQLException e) {
		System.out.println("Andrew: SQLException!");//$NON-NLS-1$
		e.printStackTrace();
	}
}

public static void main(String[] args) {
	try {
		Class.forName(DB2DRIVER).newInstance();
	} catch (InstantiationException e) {
		System.out.println("Andrew: InstantiationException!");//$NON-NLS-1$
	} catch (IllegalAccessException e) {
		System.out.println("Andrew: IllegalAccessException!");//$NON-NLS-1$
	} catch (ClassNotFoundException e) {
		System.out.println("Andrew: ClassNotFoundException!");//$NON-NLS-1$
	}
	testFilteredRowSet();
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>其中MyDBFilter实现了Predicate接口，其实现代码如下：</p>
		<p>
				<br />
		</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">class MyDBFilter implements Predicate {
	private int low;
	private int high;
	public MyDBFilter(int low, int high) {
		this.low = low;
		this.high = high;
	}
	public boolean evaluate(RowSet rs) {
		CachedRowSet crs=(CachedRowSet)rs;
		//如果id在low和high之间返回真
		try {
			String id = (String) crs.getString("id");
			int idValue = Integer.parseInt(id);
			if (low &lt; idValue &amp;&amp; idValue &lt; high) {
				return true;
			}
		} catch (SQLException e) {
			
		}
		return false;
	}
	public boolean evaluate(Object arg0, int arg1) throws SQLException {
		return false;
	}

	public boolean evaluate(Object arg0, String arg1) throws SQLException {
		return false;
	}
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>其运行结果如下：</p>
		<p>
				<br />
		</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">cursor moved
ID=0021,NAME=zhang
cursor moved
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<font face="Lucida Console">
												<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" />
										</font>
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<font face="Lucida Console">
												<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
												<br />
										</font>
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<font face="Lucida Console">
																				<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																				<br />
																		</font>
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-zhanghz2/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="IDAVF0MB">
						<span class="atitle">
								<font face="Arial" size="4">JoinRowSet</font>
						</span>
				</a>
		</p>
		<p>JoinRowSet可以将多个RowSet对象进行join合并，Join的列可以通过每个RowSet通过调用setMatchColumn方法来设置。setMatchColumn方式是Joinable接口定义的方法，五种类型的RowSet规定都需要实现该接口。下面的代码演示将student表和intern表中id相同的数据进行join操作。JoinRowSet不需要保持与数据库的连接。</p>
		<p>
				<br />
		</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">public static void testJoinRowSet(){
	Connection conn = null;
	try {
		JoinRowSet jrs = new JoinRowSetImpl();
		// 获得数据库连接
		conn = DriverManager.getConnection(DB2URL, DB2USER, DB2PASSWORD);
		Statement stmt = conn.createStatement();
		// 查询数据库，获得表数据
		ResultSet rs1 = stmt.executeQuery("select id,name from student");//$NON-NLS-1$
		// 根据ResultSet对象生成CachedRowSet类型的对象
		CachedRowSetImpl crs1 = new CachedRowSetImpl();
		crs1.populate(rs1);
		crs1.setMatchColumn(1);
		// 关闭ResultSet
		jrs.addRowSet(crs1);
		rs1.close();
		
		// 查询数据库，获得表数据
		ResultSet rs2 = stmt.executeQuery("select id,company from intern");//$NON-NLS-1$
		// 根据ResultSet对象生成CachedRowSet类型的对象
		CachedRowSetImpl crs2 = new CachedRowSetImpl();
		crs2.populate(rs2);
		crs2.setMatchColumn(1);
		// 关闭ResultSet
		rs2.close();
		// 将Result2放入JoinRowSet中进行Join操作
		jrs.addRowSet(crs2);
		// 关闭数据库连接
		conn.close();
		
		while (jrs.next()) {
			String id = jrs.getString(1);
			String name = jrs.getString(2);
			String company = jrs.getString(3);
			//$NON-NLS-1$
			System.out.println("ID=" + id + ",NAME=" + name+",COMPNAY="+company);
		}
	} catch (SQLException e) {
		System.out.println("Andrew: SQLException!");//$NON-NLS-1$
		e.printStackTrace();
	}
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>其输出结果为</p>
		<p>
				<br />
		</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">ID=001111,NAME=zhou,COMPNAY=companyA
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<font face="Lucida Console">
												<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" />
										</font>
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<font face="Lucida Console">
												<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
												<br />
										</font>
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<font face="Lucida Console">
																				<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																				<br />
																		</font>
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-zhanghz2/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="IDAKG0MB">
						<span class="atitle">
								<font face="Arial" size="4">WebRowSet</font>
						</span>
				</a>
		</p>
		<p>WebRowSet继承自CachedRowSet，支持XML格式的查询，更新等操作，下面的代码将WebRowSet对象输出成XML格式到文件。</p>
		<p>
				<br />
		</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">public static void testWebRowSet(){
	try {
		// 获得数据库连接
		Connection conn = DriverManager.getConnection(DB2URL, DB2USER,
				DB2PASSWORD);
		Statement stmt = conn.createStatement();
		// 查询数据库，获得表数据
		ResultSet rs = stmt.executeQuery("select * from student");//$NON-NLS-1$
		WebRowSetImpl wrs = new WebRowSetImpl();
		wrs.populate(rs);
		FileOutputStream out = new FileOutputStream("data.xml");
		wrs.writeXml(out);
		wrs.close();
		// 关闭与数据库的连接
		conn.close();
	} catch (SQLException e) {
		System.out.println("Andrew: SQLException!");//$NON-NLS-1$
		e.printStackTrace();
	} catch(IOException e){
		System.out.println("Andrew: IOException!");//$NON-NLS-1$
		e.printStackTrace();
	}
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>其运行结果data.xml大致如下：</p>
		<p>
				<br />
		</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">&lt;?xml version="1.0"?&gt;
XML文件属性格式 
……
&lt;metadata&gt;
    &lt;column-count&gt;2&lt;/column-count&gt;
    &lt;column-definition&gt;
      &lt;column-index&gt;1&lt;/column-index&gt;
      &lt;auto-increment&gt;false&lt;/auto-increment&gt;
      &lt;case-sensitive&gt;true&lt;/case-sensitive&gt;
      &lt;currency&gt;false&lt;/currency&gt;
      &lt;nullable&gt;0&lt;/nullable&gt;
      &lt;signed&gt;false&lt;/signed&gt;
      &lt;searchable&gt;true&lt;/searchable&gt;
      &lt;column-display-size&gt;10&lt;/column-display-size&gt;
      &lt;column-label&gt;ID&lt;/column-label&gt;
      &lt;column-name&gt;ID&lt;/column-name&gt;
      &lt;schema-name&gt;ZHOUDP  &lt;/schema-name&gt;
      &lt;column-precision&gt;10&lt;/column-precision&gt;
      &lt;column-scale&gt;0&lt;/column-scale&gt;
      &lt;table-name&gt;STUDENT&lt;/table-name&gt;
      &lt;catalog-name&gt;TEST&lt;/catalog-name&gt;
      &lt;column-type&gt;12&lt;/column-type&gt;
      &lt;column-type-name&gt;VARCHAR&lt;/column-type-name&gt;
    &lt;/column-definition&gt;
    &lt;column-definition&gt;
      &lt;column-index&gt;2&lt;/column-index&gt;
      &lt;auto-increment&gt;false&lt;/auto-increment&gt;
      &lt;case-sensitive&gt;true&lt;/case-sensitive&gt;
      &lt;currency&gt;false&lt;/currency&gt;
      &lt;nullable&gt;1&lt;/nullable&gt;
      &lt;signed&gt;false&lt;/signed&gt;
      &lt;searchable&gt;true&lt;/searchable&gt;
      &lt;column-display-size&gt;50&lt;/column-display-size&gt;
      &lt;column-label&gt;NAME&lt;/column-label&gt;
      &lt;column-name&gt;NAME&lt;/column-name&gt;
      &lt;schema-name&gt;ZHOUDP  &lt;/schema-name&gt;
      &lt;column-precision&gt;50&lt;/column-precision&gt;
      &lt;column-scale&gt;0&lt;/column-scale&gt;
      &lt;table-name&gt;STUDENT&lt;/table-name&gt;
      &lt;catalog-name&gt;TEST&lt;/catalog-name&gt;
      &lt;column-type&gt;12&lt;/column-type&gt;
      &lt;column-type-name&gt;VARCHAR&lt;/column-type-name&gt;
    &lt;/column-definition&gt;
  &lt;/metadata&gt;
  &lt;data&gt;
    &lt;currentRow&gt;
      &lt;columnValue&gt;0011&lt;/columnValue&gt;
      &lt;columnValue&gt;zhou&lt;/columnValue&gt;
    &lt;/currentRow&gt;
    &lt;currentRow&gt;
      &lt;columnValue&gt;0021&lt;/columnValue&gt;
      &lt;columnValue&gt;zhang&lt;/columnValue&gt;
    &lt;/currentRow&gt;
  &lt;/data&gt;
&lt;/webRowSet&gt;
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
<img src ="http://www.blogjava.net/landy/aggbug/51879.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/landy/" target="_blank">独孤过客</a> 2006-06-10 19:43 <a href="http://www.blogjava.net/landy/archive/2006/06/10/51879.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>扩展JAAS实现类实例级授权</title><link>http://www.blogjava.net/landy/archive/2006/05/06/44758.html</link><dc:creator>独孤过客</dc:creator><author>独孤过客</author><pubDate>Sat, 06 May 2006 08:05:00 GMT</pubDate><guid>http://www.blogjava.net/landy/archive/2006/05/06/44758.html</guid><wfw:comment>http://www.blogjava.net/landy/comments/44758.html</wfw:comment><comments>http://www.blogjava.net/landy/archive/2006/05/06/44758.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/landy/comments/commentRss/44758.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/landy/services/trackbacks/44758.html</trackback:ping><description><![CDATA[
		<div>
				<blockquote>“Java 认证和授权服务”（Java Authentication and Authorization Service，JAAS）是对 Java 2 SDK 的扩展。在 JAAS 下，可以给予用户或服务特定的许可权来执行 Java 类中的代码。在本文中，软件工程师 Carlos Fonseca 向您展示如何为企业扩展 JAAS 框架。向 JAAS 框架添加类实例级授权和特定关系使您能够构建更动态、更灵活并且伸缩性更好的企业应用程序。请单击文章顶部或底部的 <b>讨论</b>，在 <a href="javascript:void forumWindow()"><font color="#5c81a7">讨论论坛</font></a>与作者和其他读者分享您对本文的想法。 </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>大多数 Java 应用程序都需要某种类实例级的访问控制。例如，基于 Web 的、自我服务的拍卖应用程序的规范可能有下列要求：</p>
				<p>
						<i>任何已注册（经过认证）的用户都可以创建一个拍卖，但只有创建拍卖的用户才可以修改这个拍卖。 </i>
				</p>
				<p>这意味着任何用户都可以执行被编写用来创建 <code><font face="Courier">Auction</font></code> 类实例的代码，但只有拥有该实例的用户可以执行用来修改它的代码。通常情况下，创建 <code><font face="Courier">Auction</font></code> 实例的用户就是所有者。这被称为 <i>类实例所有者关系（class instance owner relationship）</i>。 </p>
				<p>该应用程序的另一个要求可能是：</p>
				<p>
						<i>任何用户都可以为拍卖创建一个投标，拍卖的所有者可以接受或拒绝任何投标。 </i>
				</p>
				<p>再一次，任何用户都可以执行被编写用来创建 <code><font face="Courier">Bid</font></code> 类实例的代码，但只有拥有该实例的用户会被授予修改该实例的许可权。而且， <code><font face="Courier">Auction</font></code> 类实例的所有者必须能够修改相关的 <code><font face="Courier">Bid</font></code> 类实例中的接受标志。这意味着在 <code><font face="Courier">Auction</font></code> 实例和相应的 <code><font face="Courier">Bid</font></code> 实例之间有一种被称为 <i>特定关系（special relationship）</i>的关系。 </p>
				<p>不幸的是，“Java 认证和授权服务”（JAAS）― 它是 Java 2 平台的一部分 ― 没有考虑到类实例级访问控制或者特定关系。在本文中，我们将扩展 JAAS 框架使其同时包含这两者。推动这种扩展的动力是允许我们将访问控制分离到一个通用的框架，该框架使用基于所有权和特定关系的策略。然后管理员可以在应用程序的生命周期内更改这些策略。</p>
				<p>在深入到扩展 JAAS 框架之前，我们将重温一下 Java 2 平台的访问控制机制。我们将讨论策略文件和许可权的使用，并讨论 <code><font face="Courier">SecurityManager</font></code> 和 <code><font face="Courier">AccessController</font></code> 之间的关系。 </p>
				<p>
						<a name="1">
								<span class="atitle">
										<strong>
												<font size="4">Java 2 平台中的访问控制</font>
										</strong>
								</span>
						</a>
				</p>
				<p>在 Java 2 平台中，所有的代码，不管它是本地代码还是远程代码，都可以由策略来控制。 <i>策略（policy）</i>由不同位置上的代码的一组许可权定义，或者由不同的签发者定义、或者由这两者定义。 <i>许可权</i>允许对资源进行访问；它通过名称来定义，并且可能与某些操作关联在一起。 </p>
				<p>抽象类 <code><font face="Courier">java.security.Policy</font></code> 被用于表示应用程序的安全性策略。缺省的实现由 <code><font face="Courier">sun.security.provider.PolicyFile</font></code> 提供，在 <code><font face="Courier">sun.security.provider.PolicyFile</font></code> 中，策略被定义在一个文件中。清单 1 是一个典型策略文件示例： </p>
				<br />
				<a name="code1">
						<b>清单 1. 一个典型的策略文件</b>
				</a>
				<br />
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code class="section">
																<font face="Lucida Console">// Grant these permissions to code loaded from a sample.jar file
// in the C drive and if it is signed by XYZ
grant codebase "file:/C:/sample.jar", signedby "XYZ" {
	// Allow socket actions to any host using port 8080
	permission java.net.SocketPermission "*:8080", "accept, connect, 
	  listen, resolve";
	// Allows file access (read, write, execute, delete) in
	// the user's home directory.
	Permission java.io.FilePermission "${user.home}/-", "read, write, 
	  execute, delete";
};
</font>
														</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>
						<a name="N100B6">
								<span class="smalltitle">
										<strong>
												<font size="3">SecurityManager 对 AccessController</font>
										</strong>
								</span>
						</a>
				</p>
				<p>在标准 JDK 分发版中，控制代码源访问的机制缺省情况下是关闭的。在 Java 2 平台以前，对代码源的访问都是由 <code><font face="Courier">SecurityManager</font></code> 类管理的。 <code><font face="Courier">SecurityManager</font></code> 是由 <code><font face="Courier">java.security.manager</font></code> 系统属性启动的，如下所示： </p>
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code class="section">
																<font face="Lucida Console">java -Djava.security.manager
</font>
														</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>在 Java 2 平台中，可以将一个应用程序设置为使用 <code><font face="Courier">java.lang.SecurityManager</font></code> 类或者 <code><font face="Courier">java.security.AccessController</font></code> 类管理敏感的操作。 <code><font face="Courier">AccessController</font></code> 在 Java 2 平台中是新出现的。为便于向后兼容， <code><font face="Courier">SecurityManager</font></code> 类仍然存在，但把自己的决定提交 <code><font face="Courier">AccessController</font></code> 类裁决。 <code><font face="Courier">SecurityManager</font></code> 和 <code><font face="Courier">AccessController</font></code> 都使用应用程序的策略文件确定是否允许一个被请求的操作。清单 2 显示了 <code><font face="Courier">AccessController</font></code> 如何处理 <code><font face="Courier">SocketPermission</font></code> 请求： </p>
				<br />
				<a name="code2">
						<b>清单 2. 保护敏感操作</b>
				</a>
				<br />
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code class="section">
																<font face="Lucida Console">Public void someMethod() {
	Permission permission = 
	  new java.net.SocketPermission("localhost:8080", "connect");
	AccessController.checkPermission(permission);
	// Sensitive code starts here
	Socket s = new Socket("localhost", 8080);
}
</font>
														</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>在这个示例中，我们看到 <code><font face="Courier">AccessController</font></code> 检查应用程序的当前策略实现。如果策略文件中定义的任何许可权暗示了被请求的许可权，该方法将只简单地返回；否则抛出一个 <code><font face="Courier">AccessControlException</font></code> 异常。在这个示例中，检查实际上是多余的，因为缺省套接字实现的构造函数也执行相同的检查。 </p>
				<p>在下一部分，我们将更仔细地看一下 <code><font face="Courier">AccessController</font></code> 如何与 <code><font face="Courier">java.security.Policy</font></code> 实现共同合作安全地处理应用程序请求。 </p>
				<br />
				<table cellspacing="0" cellpadding="0" width="100%" border="0">
						<tbody>
								<tr>
										<td>
												<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
												<br />
												<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
										</td>
								</tr>
						</tbody>
				</table>
				<table class="no-print" cellspacing="0" cellpadding="0" align="right">
						<tbody>
								<tr align="right">
										<td>
												<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
												<br />
												<table cellspacing="0" cellpadding="0" border="0">
														<tbody>
																<tr>
																		<td valign="center">
																				<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																				<br />
																		</td>
																		<td valign="top" align="right">
																				<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-jaas/#main">
																						<b>
																								<font face="Verdana" color="#996699">回页首</font>
																						</b>
																				</a>
																		</td>
																</tr>
														</tbody>
												</table>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<br />
				<p>
						<a name="2">
								<span class="atitle">
										<strong>
												<font size="4">运行中的 AccessController</font>
										</strong>
								</span>
						</a>
				</p>
				<p>
						<code>
								<font face="Courier">AccessController</font>
						</code> 类典型的 <code><font face="Courier">checkPermission(Permission p)</font></code> 方法调用可能会导致下面的一系列操作： </p>
				<ol>
						<li>
								<code>
										<font face="Courier" size="2">AccessController</font>
								</code> 调用 <code><font face="Courier" size="2">java.security.Policy</font></code> 类实现的 <code><font face="Courier" size="2">getPermissions(CodeSource codeSource)</font></code> 方法。 
</li>
						<li>
								<code>
										<font face="Courier" size="2">getPermissions(CodeSource codeSource)</font>
								</code> 方法返回一个 <code><font face="Courier" size="2">PermissionCollection</font></code> 类实例，这个类实例代表一个相同类型许可权的集合。 
</li>
						<li>
								<code>
										<font face="Courier" size="2">AccessController</font>
								</code> 调用 <code><font face="Courier" size="2">PermissionCollection</font></code> 类的 <code><font face="Courier" size="2">implies(Permission p)</font></code> 方法。 
</li>
						<li>接下来， <code><font face="Courier" size="2">PermissionCollection</font></code> 调用集合中包含的单个 <code><font face="Courier" size="2">Permission</font></code> 对象的 <code><font face="Courier" size="2">implies(Permission p)</font></code> 方法。如果集合中的当前许可权对象暗示指定的许可权，则这些方法返回 <code><font face="Courier" size="2">true</font></code> ，否则返回 <code><font face="Courier" size="2">false</font></code> 。 </li>
				</ol>
				<p>现在，让我们更详细地看一下这个访问控制序列中的重要元素。</p>
				<p>
						<a name="N1016D">
								<span class="smalltitle">
										<strong>
												<font size="3">PermissionCollection 类</font>
										</strong>
								</span>
						</a>
				</p>
				<p>大多数许可权类类型都有一个相应的 <code><font face="Courier">PermissionCollection</font></code> 类。这样一个集合的实例可以通过调用 <code><font face="Courier">Permission</font></code> 子类实现定义的 <code><font face="Courier">newPermissionCollection()</font></code> 方法来创建。 <code><font face="Courier">java.security.Policy</font></code> 类实现的 <code><font face="Courier">getPermissions()</font></code> 方法也可以返回 <code><font face="Courier">Permissions</font></code> 类实例 ― <code><font face="Courier">PermissionCollection</font></code> 的一个子类。这个类代表由 <code><font face="Courier">PermissionCollection</font></code> 组织的不同类型许可权对象的一个集合。 <code><font face="Courier">Permissions</font></code> 类的 <code><font face="Courier">implies(Permission p)</font></code> 方法可以调用单个 <code><font face="Courier">PermissionCollection</font></code> 类的 <code><font face="Courier">implies(Permission p)</font></code> 方法。 </p>
				<p>
						<a name="N101A6">
								<span class="smalltitle">
										<strong>
												<font size="3">CodeSource 和 ProtectionDomain 类</font>
										</strong>
								</span>
						</a>
				</p>
				<p>许可权组合与 <code><font face="Courier">CodeSource</font></code> （被用于验证签码（signed code）的代码位置和证书）被封装在 <code><font face="Courier">ProtectionDomain</font></code> 类中。有相同许可权和相同 <code><font face="Courier">CodeSource</font></code> 的类实例被放在相同的域中。带有相同许可权，但不同 <code><font face="Courier">CodeSource</font></code> 的类被放在不同的域中。一个类只可属于一个 <code><font face="Courier">ProtectionDomain</font></code> 。要为对象获取 <code><font face="Courier">ProtectionDomain</font></code> ，请使用 <code><font face="Courier">java.lang.Class</font></code> 类中定义的 <code><font face="Courier">getProtectionDomain()</font></code> 方法。 </p>
				<p>
						<a name="N101CF">
								<span class="smalltitle">
										<strong>
												<font size="3">许可权</font>
										</strong>
								</span>
						</a>
				</p>
				<p>赋予 <code><font face="Courier">CodeSource</font></code> 许可权并不一定意味着允许所暗示的操作。要使操作成功完成，调用栈中的每个类必须有必需的许可权。换句话说，如果您将 <code><font face="Courier">java.io.FilePermission</font></code> 赋给类 B，而类 B 是由类 A 来调用，那么类 A 必须也有相同的许可权或者暗示 <code><font face="Courier">java.io.FilePermission</font></code> 的许可权。 </p>
				<p>在另一方面，调用类可能需要临时许可权来完成另一个拥有那些许可权的类中的操作。例如，当从另一个位置加载的类访问本地文件系统时，我们可能不信任它。但是，本地加载的类被授予对某个目录的读许可权。这些类可以实现 <code><font face="Courier">PrivilegedAction</font></code> 接口来给予调用类许可权以便完成指定的操作。调用栈的检查在遇到 <code><font face="Courier">PrivilegedAction</font></code> 实例时停止，有效地将执行指定操作所必需的许可权授予所有的后继类调用。 </p>
				<br />
				<table cellspacing="0" cellpadding="0" width="100%" border="0">
						<tbody>
								<tr>
										<td>
												<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
												<br />
												<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
										</td>
								</tr>
						</tbody>
				</table>
				<table class="no-print" cellspacing="0" cellpadding="0" align="right">
						<tbody>
								<tr align="right">
										<td>
												<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
												<br />
												<table cellspacing="0" cellpadding="0" border="0">
														<tbody>
																<tr>
																		<td valign="center">
																				<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																				<br />
																		</td>
																		<td valign="top" align="right">
																				<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-jaas/#main">
																						<b>
																								<font face="Verdana" color="#996699">回页首</font>
																						</b>
																				</a>
																		</td>
																</tr>
														</tbody>
												</table>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<br />
				<p>
						<a name="3">
								<span class="atitle">
										<strong>
												<font size="4">使用 JAAS</font>
										</strong>
								</span>
						</a>
				</p>
				<p>顾名思义，JAAS 由两个主要组件组成：认证和授权。我们主要关注扩展 JAAS 的授权组件，但开始我们先简要概述一下 JAAS 认证，紧接着看一下一个简单的 JAAS 授权操作。</p>
				<p>
						<a name="N101F8">
								<span class="smalltitle">
										<strong>
												<font size="3">JAAS 中的用户认证</font>
										</strong>
								</span>
						</a>
				</p>
				<p>JAAS 通过添加基于 subject 的策略加强了 Java 2 中定义的访问控制安全性模型。许可权的授予不仅基于 <code><font face="Courier">CodeSource</font></code> ，还基于执行代码的用户。显然，要使这个模型生效，每个用户都必须经过认证。 </p>
				<p>JAAS 的认证机制建立在一组可插登录模块的基础上。JAAS 分发版包含几个 <code><font face="Courier">LoginModule</font></code> 实现。 <code><font face="Courier">LoginModules</font></code> 可以用于提示用户输入用户标识和密码。 <code><font face="Courier">LoginContext</font></code> 类使用一个配置文件来确定使用哪个 <code><font face="Courier">LoginModule</font></code> 对用户进行认证。这个配置可以通过系统属性 <code><font face="Courier">java.security.auth.login.config</font></code> 指定。一个示例配置是： </p>
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code class="section">
																<font face="Lucida Console">java -Djava.security.auth.login.config=login.conf
</font>
														</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>下面是一个登录配置文件的样子：</p>
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code class="section">
																<font face="Lucida Console">Example {
  com.ibm.resource.security.auth.LoginModuleExample required 
    debug=true userFile="users.xml" groupFile="groups.xml";
};
</font>
														</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>
						<a name="N10227">
								<span class="smalltitle">
										<strong>
												<font size="3">认识您的主体</font>
										</strong>
								</span>
						</a>
				</p>
				<p>
						<code>
								<font face="Courier">Subject</font>
						</code> 类被用于封装一个被认证实体（比如用户）的凭证。一个 <code><font face="Courier">Subject</font></code> 可能拥有一个被称为 <i>主体（principal）</i>的身份分组。例如，如果 <code><font face="Courier">Subject</font></code> 是一个用户，用户的名字和相关的社会保险号可能是 <code><font face="Courier">Subject</font></code> 的某些身份或主体。主体是与身份名关联在一起的。 </p>
				<p>
						<code>
								<font face="Courier">Principal</font>
						</code> 实现类及其名称都是在 JAAS 策略文件中指定的。缺省的 JAAS 实现使用的策略文件与 Java 2 实现的策略文件相似 ― 除了每个授权语句必须与至少一个主体关联在一起。 <code><font face="Courier">javax.security.auth.Policy</font></code> 抽象类被用于表示 JAAS 安全性策略。它的缺省实现由 <code><font face="Courier">com.sun.security.auth.PolicyFile</font></code> 提供，在 <code><font face="Courier">com.sun.security.auth.PolicyFile</font></code> 中策略定义在一个文件中。清单 3 是 JAAS 策略文件的一个示例： </p>
				<br />
				<a name="code3">
						<b>清单 3. 示例 JAAS 策略文件</b>
				</a>
				<br />
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code class="section">
																<font face="Lucida Console">// Example grant entry
grant codeBase "file:/C:/sample.jar", signedby "XYZ",
  principal com.ibm.resource.security.auth.PrincipalExample "admin" {
    // Allow socket actions to any host using port 8080
    permission java.net.SocketPermission 
      "*:8080", "accept, connect, listen, resolve";
    // Allows file access (read, write, execute, delete) in
    // the user's home directory.
    Permission java.io.FilePermission 
      "${user.home}/-", "read, write, execute, delete";
};
</font>
														</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>这个示例与清单 1 中所示的标准 Java 2 策略文件相似。实际上，唯一的不同是主体语句，该语句声明只有拥有指定主体和主体名字的 subject（用户）被授予指定的许可权。</p>
				<p>再一次，使用系统属性 <code><font face="Courier">java.security.auth.policy</font></code> 指出 JAAS 策略文件驻留在何处，如下所示： </p>
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code class="section">
																<font face="Lucida Console">java -Djava.security.auth.policy=policy.jaas
</font>
														</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>
						<code>
								<font face="Courier">Subject</font>
						</code> 类包含几个方法来作为特殊 subject 执行工作；这些方法如下所示： </p>
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code class="section">
																<font face="Lucida Console">public static Object 
  doAs(Subject subject, java.security.PrivilegedAction action)
public static Object 
  doAs(Subject subject, java.security.PrivilegedAction action)
  throws java.security.PrivilegedActionException	
</font>
														</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>注意，用来保护敏感代码的方法与“Java 2 代码源访问控制”（Java 2 CodeSource Access Control）概述中描述的方法相同。请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jaas/#resources"><font color="#996699">参考资料</font></a>部分以了解更多关于 JAAS 中代码源访问控制和认证的信息。 </p>
				<br />
				<table cellspacing="0" cellpadding="0" width="100%" border="0">
						<tbody>
								<tr>
										<td>
												<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
												<br />
												<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
										</td>
								</tr>
						</tbody>
				</table>
				<table class="no-print" cellspacing="0" cellpadding="0" align="right">
						<tbody>
								<tr align="right">
										<td>
												<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
												<br />
												<table cellspacing="0" cellpadding="0" border="0">
														<tbody>
																<tr>
																		<td valign="center">
																				<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																				<br />
																		</td>
																		<td valign="top" align="right">
																				<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-jaas/#main">
																						<b>
																								<font face="Verdana" color="#996699">回页首</font>
																						</b>
																				</a>
																		</td>
																</tr>
														</tbody>
												</table>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<br />
				<p>
						<a name="4">
								<span class="atitle">
										<strong>
												<font size="4">JAAS 中的授权</font>
										</strong>
								</span>
						</a>
				</p>
				<p>清单 4 显示一个授权请求的结果，该请求使用清单 3 中显示的 JAAS 策略文件。假设已经安装了 <code><font face="Courier">SecurityManager</font></code> ，并且 <code><font face="Courier">loginContext</font></code> 已经认证了一个带有名为“admin”的 <code><font face="Courier">com.ibm.resource.security.auth.PrincipalExample</font></code> 主体的 <code><font face="Courier">Subject</font></code> 。 </p>
				<br />
				<a name="code4">
						<b>清单 4. 一个简单的授权请求</b>
				</a>
				<br />
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code class="section">
																<font face="Lucida Console">public class JaasExample {
	public static void main(String[] args) {
		...
		// where authenticatedUser is a Subject with
		// a PrincipalExample named admin.
		Subject.doAs(authenticatedUser, new JaasExampleAction());
		...
	}
}

public class JaasExampleAction implements PrivilegedAction {
	public Object run() {
		FileWriter fw = new FileWriter("hi.txt");
		fw.write("Hello, World!");
		fw.close();
	}
}	
</font>
														</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>这里，敏感代码被封装在 <code><font face="Courier">JaasExampleAction</font></code> 类中。还要注意，调用类不要求为 <code><font face="Courier">JaasExampleAction</font></code> 类代码源授予许可权，因为它实现了一个 <code><font face="Courier">PrivilegedAction</font></code> 。 </p>
				<br />
				<table cellspacing="0" cellpadding="0" width="100%" border="0">
						<tbody>
								<tr>
										<td>
												<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
												<br />
												<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
										</td>
								</tr>
						</tbody>
				</table>
				<table class="no-print" cellspacing="0" cellpadding="0" align="right">
						<tbody>
								<tr align="right">
										<td>
												<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
												<br />
												<table cellspacing="0" cellpadding="0" border="0">
														<tbody>
																<tr>
																		<td valign="center">
																				<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																				<br />
																		</td>
																		<td valign="top" align="right">
																				<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-jaas/#main">
																						<b>
																								<font face="Verdana" color="#996699">回页首</font>
																						</b>
																				</a>
																		</td>
																</tr>
														</tbody>
												</table>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<br />
				<p>
						<a name="5">
								<span class="atitle">
										<strong>
												<font size="4">扩展 JAAS</font>
										</strong>
								</span>
						</a>
				</p>
				<p>大多数应用程序都有定制逻辑，它授权用户不仅仅在类上执行操作，而且还在该类的实例上执行操作。这种授权通常建立在用户和实例之间的关系上。这是 JAAS 的一个小缺点。然而，幸运的是，这样设计 JAAS 使得 JAAS 可以扩展。只要做一点工作，我们将可以扩展 JAAS，使其包含一个通用的、类实例级的授权框架。</p>
				<p>在文章开头处我已经说明了，抽象类 <code><font face="Courier">javax.security.auth.Policy</font></code> 被用于代表 JAAS 安全性策略。它的缺省实现是由 <code><font face="Courier">com.sun.security.auth.PolicyFile</font></code> 类提供。 <code><font face="Courier">PolicyFile</font></code> 类从 JAAS 格式的文件（象清单 3 中显示的那个一样）中读取策略。 </p>
				<p>我们需要向这个文件添加一个东西为类实例级授权扩展策略定义：一个与许可权语句相关的可选关系参数。</p>
				<p>缺省 JAAS 许可权语句的格式如下：</p>
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code class="section">
																<font face="Lucida Console">permission &lt;permission implementation class&gt; [name], [actions];	
</font>
														</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>我们在这个许可权语句的末尾添加一个可选的关系参数来完成策略定义。下面是新许可权语句的格式：</p>
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code class="section">
																<font face="Lucida Console">permission &lt;permission implementation class&gt; 
  [name], [actions], [relationship];
</font>
														</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>在为类实例级授权扩展 JAAS 时要注意的最重要的一点是：许可权实现类必须有一个带三个参数的构造函数。第一个参数是名称参数，第二个是行为参数，最后一个是关系参数。</p>
				<p>
						<a name="N102DE">
								<span class="smalltitle">
										<strong>
												<font size="3">解析新文件格式</font>
										</strong>
								</span>
						</a>
				</p>
				<p>既然文件格式已经改变，就需要一个新的 <code><font face="Courier">javax.security.auth.Policy</font></code> 子类来解析文件。 </p>
				<p>为简单起见，我们的示例使用了一个新的 <code><font face="Courier">javax.security.auth.Policy</font></code> 子类 <code><font face="Courier">com.ibm.resource.security.auth.XMLPolicyFile</font></code> ，来从 XML 文件读取策略。在实际的企业应用程序中，关系数据库更适合执行这个任务。 </p>
				<p>使用 <code><font face="Courier">XMLPolicyFile</font></code> 类代替缺省的 JAAS 访问控制策略实现的最容易的方法是向 <code><font face="Courier">java.security</font></code> 属性文件添加 <code><font face="Courier">auth.policy.provider=com.ibm.resource.security.auth.XMLPolicyFile</font></code> 条目。 <code><font face="Courier">java.security</font></code> 属性文件位于 Java 2 平台运行时的 lib/security 目录下。清单 5 是与 <code><font face="Courier">XMLPolicyFile</font></code> 类一起使用的样本 XML 策略文件： </p>
				<br />
				<a name="code5">
						<b>清单 5. 一个 XML 策略文件</b>
				</a>
				<br />
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code class="section">
																<font face="Lucida Console">&lt;?xml version="1.0"?&gt;
&lt;policy&gt;
    &lt;grant codebase="file:/D:/sample_actions.jar"&gt;
      &lt;principal classname=
        "com.ibm.resource.security.auth.PrincipalExample" name="users"&gt;
        &lt;permission classname=
          "com.ibm.resource.security.auth.ResourcePermission"
          name="com.ibm.security.sample.Auction"
          actions="create" /&gt;
        &lt;permission classname=
         "com.ibm.resource.security.auth.ResourcePermission"
          name="com.ibm.security.sample.Auction"
          actions="read" /&gt;
        &lt;permission classname=
         "com.ibm.resource.security.auth.ResourcePermission"
          name="com.ibm.security.sample.Auction"
          actions="write"
          relationship="owner" /&gt;
        &lt;permission classname=
         "com.ibm.resource.security.auth.ResourcePermission"
          name="com.ibm.security.sample.Bid"
          actions="create" /&gt;
        &lt;permission classname=
         "com.ibm.resource.security.auth.ResourcePermission"
          name="com.ibm.security.sample.Bid"
          actions="read" /&gt;
        &lt;permission classname=
         "com.ibm.resource.security.auth.ResourcePermission"
          name="com.ibm.security.sample.Bid"
          actions="write"
          relationship="owner" /&gt;
        &lt;permission classname=
         "com.ibm.resource.security.auth.ResourcePermission"
          name="com.ibm.security.sample.Bid"
          actions="accept"
          relationship="actionOwner" /&gt;
    &lt;/principal&gt;
  &lt;/grant&gt;
&lt;/policy&gt;	
</font>
														</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>在这个示例策略文件中，任何与名为 <code><font face="Courier">PrincipalExample</font></code> 的用户有关的用户（ <code><font face="Courier">Subject</font></code> ）都可以创建并读取一个 <code><font face="Courier">Auction.class</font></code> 实例。但是，只有创建该实例的用户才可以更新（写）它。这是第三个 permission 元素定义的，该元素包含值为 <i>owner</i> 的 relationship 属性。 <code><font face="Courier">Bid.class</font></code> 实例也是一样，除了相应 <code><font face="Courier">Auction.class</font></code> 实例的所有者可以更改投标接受标志。 </p>
				<p>
						<a name="N10331">
								<span class="smalltitle">
										<strong>
												<font size="3">Resource 接口</font>
										</strong>
								</span>
						</a>
				</p>
				<p>要求类实例级访问控制的类必须实现 <code><font face="Courier">Resource</font></code> 接口。该接口的 <code><font face="Courier">getOwner()</font></code> 方法返回类实例的所有者。 <code><font face="Courier">fulfills(Subject subject, String relationship)</font></code> 方法被用于处理特定关系。另外，这些类使用 <code><font face="Courier">com.ibm.resource.security.auth.ResourcePermission</font></code> 类保护敏感代码。例如， <code><font face="Courier">Auction</font></code> 类拥有下列构造函数： </p>
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code class="section">
																<font face="Lucida Console">public Auction() {
  Permission permission = 
    new ResourcePermission("com.ibm.security.sample.Auction", "create");
  AccessController.checkPermission(permission);
	}	
</font>
														</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>
						<a name="N10352">
								<span class="smalltitle">
										<strong>
												<font size="3">所有者关系</font>
										</strong>
								</span>
						</a>
				</p>
				<p>
						<code>
								<font face="Courier">ResourcePermission</font>
						</code> 类的 <code><font face="Courier">implies(Permission p)</font></code> 方法是这个框架的关键。 <code><font face="Courier">implies()</font></code> 方法就等同性比较名称和行为属性。如果定义了一个关系，那么必须把受保护的类实例（ <code><font face="Courier">Resource</font></code> ）传递到 <code><font face="Courier">ResourcePermission</font></code> 构造函数中。 <code><font face="Courier">ResourcePermission</font></code> 类理解所有者关系。它将类实例的所有者与执行代码的 subject（用户）进行比较。特定关系被委托给受保护类的 <code><font face="Courier">fulfills()</font></code> 方法。 </p>
				<p>例如，在清单 5 中所示的 XML 策略文件中，只有 <code><font face="Courier">Auction</font></code> 类实例的所有者可以更新（写）文件。该类的 setter 方法使用清单 6 中显示的保护代码： </p>
				<br />
				<a name="code6">
						<b>清单 6. 运行中的 implies(Permission) 方法</b>
				</a>
				<br />
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code class="section">
																<font face="Lucida Console">public void setName(String newName) {
  Permission permission = 
    new ResourcePermission("com.ibm.security.sample.Auction", "write", this);
  AccessController.checkPermission(permission);
  // sensitive code
  this.name = newName;
}
</font>
														</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>被传递到 <code><font face="Courier">ResourcePermission</font></code> 构造函数中的 <code><font face="Courier">this</font></code> 引用代表 <code><font face="Courier">Auction</font></code> 类实现的 <code><font face="Courier">Resource</font></code> 接口。由于策略文件中列出的关系是 <i>owner</i>，所以 <code><font face="Courier">ResourcePermission</font></code> 类使用这个引用检查当前 <code><font face="Courier">Subject</font></code> （用户）是否拥有与实例所有者相匹配的主体。如果指定了另一个关系，那么 <code><font face="Courier">ResourcePermission</font></code> 类调用 <code><font face="Courier">Auction</font></code> 类的 <code><font face="Courier">fulfills(Subject subject, String relationship)</font></code> 方法。由 <code><font face="Courier">Resource</font></code> 实现类提供 <code><font face="Courier">fulfills()</font></code> 方法中的逻辑。 </p>
				<p>XML 策略文件中列出的 <code><font face="Courier">Bid</font></code> 类拥有清单 7 中所示的方法（假设 <code><font face="Courier">Bid</font></code> 类实例有一个对相应 <code><font face="Courier">Auction</font></code> 类实例的引用 ― auction）。 </p>
				<br />
				<a name="code7">
						<b>清单 7. 处理特定关系</b>
				</a>
				<br />
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code class="section">
																<font face="Lucida Console">public void setAccepted(boolean flag) {
  Permission permission = 
    new ResourcePermission("com.ibm.security.sample.Auction", "accept", this);
  AccessController.checkPermission(permission);
  // sensitive code
  this.accepted = flag;
  }
	
public boolean fulfills(Subject user, String relationship) {
  if( relationship.equalsIgnoreCase("auctionOwner") ) {
    String auctionOwner = auction.getOwner();
    Iterator principalIterator = user.getPrincipals().iterator();
    while(principalIterator.hasNext()) {
      Principal principal = (Principal) principalIterator.next();
      if( principal.getName().equals(auctionOwner) )
        return true;
    }
  }
  return false;
}
</font>
														</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>传递到 <code><font face="Courier">fulfills()</font></code> 方法中的关系字符串是策略文件中列出的关系。在这个案例中，我们使用了“ <code><font face="Courier">auctionOwner</font></code> ”字符串。 </p>
				<p>缺省情况下， <code><font face="Courier">XMLPolicyFile</font></code> 类在当前工作目录中查找名为 <code><font face="Courier">ResourcePolicy.xml</font></code> 的文件。系统属性 <code><font face="Courier">com.ibm.resource.security.auth.policy</font></code> 可以用于指定另一个不同的文件名和位置。 </p>
				<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="sidebar1">
																						<b>WebSphere Application Server 示例</b>
																				</a>
																				<br />
																				<p>除命令行示例之外，您可能还想运行这个简单的程序，该程序 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jaas/jaas-sidebar.html"><font color="#5c81a7">为了 IBM WebSphere Application Server，version 4.0.2 而被优化</font></a>。 </p>
																		</td>
																</tr>
														</tbody>
												</table>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<table cellspacing="0" cellpadding="0" width="100%" border="0">
						<tbody>
								<tr>
										<td>
												<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
												<br />
												<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
										</td>
								</tr>
						</tbody>
				</table>
				<table class="no-print" cellspacing="0" cellpadding="0" align="right">
						<tbody>
								<tr align="right">
										<td>
												<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
												<br />
												<table cellspacing="0" cellpadding="0" border="0">
														<tbody>
																<tr>
																		<td valign="center">
																				<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																				<br />
																		</td>
																		<td valign="top" align="right">
																				<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-jaas/#main">
																						<b>
																								<font face="Verdana" color="#996699">回页首</font>
																						</b>
																				</a>
																		</td>
																</tr>
														</tbody>
												</table>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<br />
				<p>
						<a name="6">
								<span class="atitle">
										<strong>
												<font size="4">一个可运行的示例</font>
										</strong>
								</span>
						</a>
				</p>
				<p>综合这些信息，我们将运行一个简单的命令行示例。该示例程序包含三个 jar 文件：</p>
				<ul>
						<li>resourceSecurity.jar 
</li>
						<li>example.jar 
</li>
						<li>exampleActions.jar </li>
				</ul>
				<p>resourceSecurity.jar 文件包含允许实例级访问控制的 JAAS 扩展框架。它还包含一个 <code><font face="Courier">LoginModuleExample</font></code> 类，这个类从 XML 文件读取用户认证信息。用户标识和密码存储在 users.xml 文件中。用户组存储在 groups.xml 文件中。关于 <code><font face="Courier">LoginModuleExample</font></code> 的更多信息，请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jaas/#resources"><font color="#996699">参考资料</font></a>部分。 </p>
				<p>该示例包含四个附加的文件：</p>
				<ul>
						<li>login.conf 
</li>
						<li>policy 
</li>
						<li>resourcePolicy.xml 
</li>
						<li>run.bat </li>
				</ul>
				<p>在试图运行这个示例程序之前，请确保更新了 run.bat、policy 和 resourcePolicy.xml 文件中的路径。缺省情况下，所有的密码都是“passw0rd”。 </p>
				<p>
						<a name="N10436">
								<span class="smalltitle">
										<strong>
												<font size="3">示例如何工作</font>
										</strong>
								</span>
						</a>
				</p>
				<p>该示例程序提示输入用户标识和密码。它用 users.xml 文件中的条目核对所提供的用户标识和密码。在认证了用户之后，程序设法创建一个 <code><font face="Courier">UserProfile</font></code> 类实例，修改它并从中读取。缺省情况下， <code><font face="Courier">UserProfile</font></code> 类的所有者是 Jane（jane）。当 Jane 登录时，三个操作全部成功。当 John（john）登录时，只有创建操作成功。当 Jane 的经理 Lou（lou）登录时，只有第一个和最后一个操作成功。当系统管理员（admin）登录时，操作全部成功。当然，只有当提供的 ResourcePolicy.xml 文件未被修改时，上述这些才都是真的。 </p>
				<p>
						<b>示例安装</b>
						<br />下面的安装指导假设您正在使用 JDK 1.3 并且已经把文件解压缩到 d:\JaasExample 目录。通过将文件解压缩到这个目录，您可以省去一些工作；否则您就必须使用正确的路径名修改 policy 和 ResourceSecurity.xml 策略文件。 </p>
				<p>下面是运行该示例需要做的工作：</p>
				<ol>
						<li>下载这个示例的 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jaas/standaloneExample.zip"><font color="#5c81a7">源文件</font></a>。 
</li>
						<li>把 jaas.jar 和 jaasmod.jar 复制到 JDK jre\lib\ext 目录（即 D:\JDK1.3\jre\lib\ext）。 
</li>
						<li>向位于 JDK 的 jre\lib\security 目录（即 D:\JDK1.3\jre\lib\security）中的 java.security 文件的末尾添加下面的字符串： <code><font face="Courier" size="2">auth.policy.provider=com.ibm.resource.security.auth.XMLPolicyFile</font></code> 。 
</li>
						<li>执行 run.bat 文件。 </li>
				</ol>
				<br />
				<table cellspacing="0" cellpadding="0" width="100%" border="0">
						<tbody>
								<tr>
										<td>
												<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
												<br />
												<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
										</td>
								</tr>
						</tbody>
				</table>
				<table class="no-print" cellspacing="0" cellpadding="0" align="right">
						<tbody>
								<tr align="right">
										<td>
												<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
												<br />
												<table cellspacing="0" cellpadding="0" border="0">
														<tbody>
																<tr>
																		<td valign="center">
																				<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																				<br />
																		</td>
																		<td valign="top" align="right">
																				<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-jaas/#main">
																						<b>
																								<font face="Verdana" color="#996699">回页首</font>
																						</b>
																				</a>
																		</td>
																</tr>
														</tbody>
												</table>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<br />
				<p>
						<a name="7">
								<span class="atitle">
										<strong>
												<font size="4">结束语</font>
										</strong>
								</span>
						</a>
				</p>
				<p>类实例级授权把访问控制分离到一个通用框架（该框架使用基于所有权和特定关系的策略）中。然后管理员可以在应用程序的生命周期内更改这些策略。用这种方法扩展 JAAS 减少了您或另一个程序员必须在应用程序生命周期内业务规则发生更改时重写代码的可能性。</p>
				<p>通过将关系字符串抽象为类可以进一步扩展特定关系这个概念。不调用 <code><font face="Courier">Resource</font></code> 实现类的 <code><font face="Courier">fulfills(Subject user, String relationship)</font></code> 方法，而只要调用 <code><font face="Courier">Relationship</font></code> 实现类中定义的新 <code><font face="Courier">fulfills(Subject user, Resource resource)</font></code> 方法。这样就会允许许多 <code><font face="Courier">Resource</font></code> 实现类使用相同的关系逻辑。 </p>
		</div>
<img src ="http://www.blogjava.net/landy/aggbug/44758.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/landy/" target="_blank">独孤过客</a> 2006-05-06 16:05 <a href="http://www.blogjava.net/landy/archive/2006/05/06/44758.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAAS:灵活的Java安全机制</title><link>http://www.blogjava.net/landy/archive/2006/05/06/44757.html</link><dc:creator>独孤过客</dc:creator><author>独孤过客</author><pubDate>Sat, 06 May 2006 08:05:00 GMT</pubDate><guid>http://www.blogjava.net/landy/archive/2006/05/06/44757.html</guid><wfw:comment>http://www.blogjava.net/landy/comments/44757.html</wfw:comment><comments>http://www.blogjava.net/landy/archive/2006/05/06/44757.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/landy/comments/commentRss/44757.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/landy/services/trackbacks/44757.html</trackback:ping><description><![CDATA[
		<div>
				<strong>
						<font color="#ac0000">摘要：<br /><br /></font>
				</strong>　　Java Authentication Authorization Service（JAAS，Java验证和授权API）提供了灵活和可伸缩的机制来保证客户端或服务器端的Java程序。Java早期的安全框架强调的是通过验证代码的来源和作者，保护用户避免受到下载下来的代码的攻击。JAAS强调的是通过验证谁在运行代码以及他／她的权限来保护系统面受用户的攻击。它让你能够将一些标准的安全机制，例如Solaris NIS（网络信息服务）、Windows NT、LDAP（轻量目录存取协议），Kerberos等通过一种通用的，可配置的方式集成到系统中。本文首先向你介绍JAAS验证中的一些核心部分，然后通过例子向你展示如何开发登录模块。<br /><br />　　你是否曾经需要为一个应用程序实现登录模块呢？如果你是一个比较有经验的程序员，相信你这样的工作做过很多次，而且每次都不完全一样。你有可能把你的登录模块建立在Oracle数据库的基础上，也有可能使用的是NT的用户验证，或者使用的是LDAP目录。如果有一种方法可以在不改变应用程序级的代码的基础上支持上面提到的所有这一些安全机制，对于程序员来说一定是一件幸运的事。<br /><br />　　现在你可以使用JAAS实现上面的目标。JAAS是一个比较新的的Java API。在J2SE 1.3中，它是一个扩展包；在J2SE 1.4中变成了一个核心包。在本文中，我们将介绍JAAS的一些核心概念，然后通过例子说明如何将JAAS应用到实际的程序中。本文的例子是根据我们一个基于Web的Java应用程序进行改编的，在这个例子中，我们使用了关系数据库保存用户的登录信息。由于使用了JAAS，我们实现了一个健壮而灵活的登录和身份验证模块。<br /><br />　　<b><font color="#ac000">Java验证和授权：概论</font></b><br /><br />　　在JAAS出现以前，Java的安全模型是为了满足跨平台的网络应用程序的需要而设计的。在Java早期版本中，Java通常是作为远程代码被使用，例如Applet，。因此最初的安全模型把注意力放在通过验证代码的来源来保护用户上。早期的Java安全机制中包含的概念，如SercurityManager，沙箱概念，代码签名，策略文件，多是为了保护用户。<br /><br />　　JAAS的出现反映了Java的演变。传统的服务器／客户端程序需要实现登录和存取控制，JAAS通过对运行程序的用户的进行验证，从而达到保护系统的目的。虽然JAAS同时具有验证和授权的能力，在这篇文章中，我们主要介绍验证功能。<br /><br />　　通过在应用程序和底层的验证和授权机制之间加入一个抽象层，JAAS可以简化涉及到Java Security包的程序开发。抽象层独立于平台的特性使开发人员可以使用各种不同的安全机制，而且不用修改应用程序级的代码。和其他Java Security API相似，JAAS通过一个可扩展的框架：服务提供者接口（Service Provider Interface，SPI）来保证程序独立于安全机制。服务提供者接口是由一组抽象类和接口组成的。图一中给出了JAAS程序的整体框架图。应用程序级的代码主要处理LoginContext。在LoginContext下面是一组动态配置的LoginModules。LoginModule使用正确的安全机制进行验证。<br /><br />　　图一给出了JAAS的概览。应用程序层的代码只需要和LoginContext打交道。在LoginContext之下是一组动态配置的LoginModule对象，这些对象使用相关的安全基础结构进行验证操作。<br /><br /><table width="100" align="center"><tbody><tr align="middle"><td><img height="396" src="http://www.yesky.com/20030114/jt-2003-1-14-image001.gif" width="573" /><br />图一 JAAS概览 </td></tr></tbody></table><br />　　JAAS提供了一些LoginModule的参考实现代码，比如JndiLoginModule。开发人员也可以自己实现LoginModule接口，就象在我们例子中的RdbmsLonginModule。同时我们还会告诉你如何使用一个简单的配置文件来安装应用程序。<br /><br />　　为了满足可插接性，JAAS是可堆叠的。在单一登录的情况下，一组安全模块可以堆叠在一起，然后被其他的安全机制按照堆叠的顺序被调用。<br /><br />　　JAAS的实现者根据现在一些流行的安全结构模式和框架将JASS模型化。例如可堆叠的特性同Unix下的可堆叠验证模块（PAM，Pluggable Authentication Module）框架就非常相似。从事务的角度看，JAAS类似于双步提交（Two-Phase Commit，2PC）协议的行为。JAAS中安全配置的概念（包括策略文件（Police File）和许可（Permission））来自于J2SE 1.2。JAAS还从其他成熟的安全框架中借鉴了许多思想。<br />　<b><font color="#ac000">客户端和服务器端的JAAS</font></b><br /><br />　　开发人员可以将JAAS应用到客户端和服务器端。在客户端使用JAAS很简单。在服务器端使用JAAS时情况要复杂一些。目前在应用服务器市场中的JAAS产品还不是很一致，使用JAAS的J2EE应用服务器有一些细微的差别。例如JBossSx使用自己的结构，将JAAS集成到了一个更大的安全框架中；而虽然WebLogic 6.x也使用了JAAS，安全框架却完全不一样。<br /><br />　　现在你能够理解为什么我们需要从客户端和服务器端的角度来看JAAS了。我们将在后面列出两种情况下的例子。为了使服务器端的例子程序更加简单，我们使用了Resin应用服务器。<br /><br />　　<b><font color="#ac000">核心JAAS类</font></b><br /><br />　　在使用JAAS之前，你首先需要安装JAAS。在J2SE 1.4中已经包括了JAAS，但是在J2SE 1.3中没有。如果你希望使用J2SE 1.3，你可以从SUN的官方站点上下载JAAS。当正确安装了JAAS后，你会在安装目录的lib目录下找到jaas.jar。你需要将该路径加入Classpath中。（注：如果你安装了应用服务器，其中就已经包括了JAAS，请阅读应用服务器的帮助文档以获得更详细的信息）。在Java安全属性文件java.security中，你可以改变一些与JAAS相关的系统属性。该文件保存在＜jre_home＞/lib/security目录中。<br /><br />　　在应用程序中使用JAAS验证通常会涉及到以下几个步骤：<br /><br />　　1. 创建一个LoginContext的实例。<br /><br />　　2. 为了能够获得和处理验证信息，将一个CallBackHandler对象作为参数传送给LoginContext。<br /><br />　　3. 通过调用LoginContext的login（）方法来进行验证。<br /><br />　　4. 通过使用login（）方法返回的Subject对象实现一些特殊的功能（假设登录成功）。<br /><br />　　下面是一个简单的例子：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>LoginContext lc = new LoginContext("MyExample");<br />try {<br />lc.login();<br />} catch (LoginException) {<br />// Authentication failed.<br />}<br /><br />// Authentication successful, we can now continue.<br />// We can use the returned Subject if we like.<br />Subject sub = lc.getSubject();<br />Subject.doAs(sub, new MyPrivilegedAction());</td></tr></tbody></table><br />　　在运行这段代码时，后台进行了以下的工作。<br /><br />　　1. 当初始化时，LoginContext对象首先在JAAS配置文件中找到MyExample项，然后更具该项的内容决定该加载哪个LoginModule对象（参见图二）。<br /><br />　　2. 在登录时，LoginContext对象调用每个LoginModule对象的login（）方法。<br /><br />　　3. 每个login（）方法进行验证操作或获得一个CallbackHandle对象。<br /><br />　　4. CallbackHandle对象通过使用一个或多个CallBack方法同用户进行交互，获得用户输入。<br /><br />　　5. 向一个新的Subject对象中填入验证信息。<br /><br />　　我们将对代码作进一步的解释。但是在这之前，让我们先看代码中涉及到的核心JAAS类和接口。这些类可以被分为三种类型：<br /><br />　　普通类型 Subject，Principal，凭证<br /><br />　　验证 LoginContext，LoginModule，CallBackHandler，Callback<br /><br />　　授权 Policy，AuthPermission，PrivateCredentialPermission<br /><br />　　上面列举的类和接口大多数都在javax.security.auth包中。在J2SE 1.4中，还有一些接口的实现类在com.sun.security.auth包中。<br /><br />　　<b>普通类型：Subject，Principal，凭证</b><br /><br />　　Subject类代表了一个验证实体，它可以是用户、管理员、Web服务，设备或者其他的过程。该类包含了三中类型的安全信息：<br /><br />　　 身份（Identities）：由一个或多个Principal对象表示<br /><br />　　 公共凭证（Public credentials）：例如名称或公共秘钥<br /><br />　　 私有凭证（Private credentials）：例如口令或私有密钥<br /><br />　　Principal对象代表了Subject对象的身份。它们实现了java.security.Principal和java.io.Serializable接口。在Subject类中，最重要的方法是getName（）。该方法返回一个身份名称。在Subject对象中包含了多个Principal对象，因此它可以拥有多个名称。由于登录名称、身份证号和Email地址都可以作为用户的身份标识，可见拥有多个身份名称的情况在实际应用中是非常普遍的情况。<br /><br />　　在上面提到的凭证并不是一个特定的类或借口，它可以是任何对象。凭证中可以包含任何特定安全系统需要的验证信息，例如标签（ticket），密钥或口令。Subject对象中维护着一组特定的私有和公有的凭证，这些凭证可以通过getPrivateCredentials（）和getPublicCredentials（）方法获得。这些方法通常在应用程序层中的安全子系统被调用。<br /><br />　　<b>验证：LoginContext</b><br /><br />　　在应用程序层中，你可以使用LoginContext对象来验证Subject对象。LoginContext对象同时体现了JAAS的动态可插入性（Dynamic Pluggability），因为当你创建一个LoginContext的实例时，你需要指定一个配置。LoginContext通常从一个文本文件中加载配置信息，这些配置信息告诉LoginContext对象在登录时使用哪一个LoginModule对象。<br /><br />　　下面列出了在LoginContext中经常使用的三个方法： <br /><br />　　login () 进行登录操作。该方法激活了配置中制定的所有LoginModule对象。如果成功，它将创建一个经过了验证的Subject对象；否则抛出LoginException异常。<br /><br />　　getSubject () 返回经过验证的Subject对象<br /><br />　　logout () 注销Subject对象，删除与之相关的Principal对象和凭证<br /><br />　　验证：LoginModule<br /><br />　　LoginModule是调用特定验证机制的接口。J2EE 1.4中包含了下面几种LoginModule的实现类：<br /><br />　　JndiLoginModule 用于验证在JNDI中配置的目录服务<br /><br />　　Krb5LoginModule 使用Kerberos协议进行验证<br /><br />　　NTLoginModul 使用当前用户在NT中的用户信息进行验证<br /><br />　　UnixLoginModule 使用当前用户在Unix中的用户信息进行验证<br /><br />　　同上面这些模块绑定在一起的还有对应的Principal接口的实现类，例如NTDomainPrincipal和UnixPrincipal。这些类在com.sun.security.auth包中。<br /><br />　　LoginModule接口中包含了五个方法：<br /><br />　　initialize () 当创建一LoginModule实例时会被构造函数调用<br /><br />　　login () 进行验证<br /><br />　　commit () 当LgoninContext对象接受所有LoginModule对象传回的结果后将调用该方法。该方法将Principal对象和凭证赋给Subject对象。<br />　　<br />　　abort () 当任何一个LoginModule对象验证失败时都会调用该方法。此时没有任何Principal对象或凭证关联到Subject对象上。<br /><br />　　logout () 删除与Subject对象关联的Principal对象和凭证。<br /><br />　　在应用程序的代码中，程序员通常不会直接调用上面列出的方法，而是通过LigonContext间接调用这些方法。<br /><br />　　验证：CallbackHandler和Callback<br /><br />　　CallbackHandler和Callback对象可以使LoginModule对象从系统和用户那里收集必要的验证信息，同时独立于实际的收集信息时发生的交互过程。<br />　　<br />　　JAAS在javax.sevurity.auth.callback包中包含了七个Callback的实现类和两个CallbackHandler的实现类：ChoiceCallback、ConfirmationCallback、LogcaleCallback、NameCallback、PasswordCallback、TextInputCallback、TextOutputCallback、DialogCallbackHandler和TextCallBackHandler。Callback接口只会在客户端会被使用到。我将在后面介绍如何编写你自己的CallbackHandler类。<br /><span class="txt">　　<b><font color="#ac000">配置文件</font></b><br /><br />　　上面我已经提到，JAAS的可扩展性来源于它能够进行动态配置，而配置信息通常是保存在文本。这些文本文件有很多个配置块构成，我们通常把这些配置块称作申请（Application）。每个申请对应了一个或多个特定的LoginModule对象。<br /><br />　　当你的代码构造一个LoginContext对象时，你需要把配置文件中申请的名称传递给它。LoginContext将会根据申请中的信息决定激活哪些LoginModule对象，按照什么顺序激活以及使用什么规则激活。<br /><br />　　配置文件的结构如下所示:<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>Application {<br />ModuleClass Flag ModuleOptions;<br />ModuleClass Flag ModuleOptions;<br />...<br />};<br />Application {<br />ModuleClass Flag ModuleOptions;<br />...<br />};<br />...</td></tr></tbody></table><br />　　下面是一个名称为Sample的申请<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>Sample {<br />com.sun.security.auth.module.NTLoginModule Rquired debug=true;<br />}</td></tr></tbody></table><br />　　上面这个简单的申请指定了LoginContext对象应该使用NTLoginModule进行验证。类的名称在ModuleClass中被指定。Flag控制当申请中包含了多个LoginModule时进行登录时的行为：Required、Sufficient、Requisite和Optional。最常用的是Required，使用它意味着对应的LoginModule对象必须被调用，并且必须需要通过所有的验证。由于Flag本身的复杂性，本文在这里不作深究。<br /><br />　　ModuleOption允许有多个参数。例如你可以设定调试参数为True（debug=true），这样诊断输出将被送到System.out中。<br /><br />　　配置文件可以被任意命名，并且可以被放在任何位置。JAAS框架通过使用java.securty.auth.long.config属性来确定配置文件的位置。例如当你的应用程序是JaasTest，配置文件是当前目录下的jaas.config，你需要在命令行中输入：<br /><br />java -Djava.security.auth.login.config=jass.config JavaTest<br /><br />　　图二描述了配置文件中各元素之间的关系<br /><br /><table width="100" align="center"><tbody><tr align="middle"><td><img height="300" src="http://www.yesky.com/20030114/jt-2003-1-14-image002.gif" width="548" /><br />图二 JAAS的配置文件 </td></tr></tbody></table><br />　　<b><font color="#ac000">通过命令行方式进行登录验证</font></b><br /><br />　　为了说明JAAS到底能干什么，我在这里编写了两个例子。一个是简单的由命令行输入调用的程序，另一个是服务器端的JSP程序。这两个程序都通过用户名／密码的方式进行登录，然后使用关系数据库对其进行验证。<br /><br />　　为了通过数据库进行验证，我们需要：<br /><br />　　1. 实现RdbmsLoginModul类，该类可以对输入的信息进行验证。<br /><br />　　2. 编辑一个配置文件，告诉LoginContext如何使用RdbmsLoginModule。<br /><br />　　3. 实现ConsoleCallbackHandler类，通过该类可以获取用户的输入。<br /><br />　　4. 编写应用程序代码。<br /><br />　　在RdbmsLoginModul类中，我们必须实现LgoinModule接口中的五个方法。首先是initialize（）方法：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>public void initialize(Subject subject, CallbackHandler <br />callbackHandler,<br /><br />Map sharedState, Map options)<br />{<br />this.subject = subject;<br />this.callbackHandler = callbackHandler;<br />this.sharedState = sharedState;<br />this.options = options;<br /><br />url = (String)options.get("url");<br />driverClass = (String)options.get("driver");<br />debug = "true".equalsIgnoreCase((String)options.get("debug"));<br />}</td></tr></tbody></table><br />　　LoginContext在调用login（）方法时会调用initialize（）方法。RdbmsLoginModule的第一个任务就是在类中保存输入参数的引用。在验证成功后将向Subject对象中送入Principal对象和凭证。<br /><br />　　CallbackHandler对象将会在login（）方法中被使用到。sharedState可以使数据在不同的LoginModule对象之间共享，但是在这个例子中我们不会使用它。最后是名为options的Map对象。options向LgoinModule对象传递在配置文件ModuleOption域中定义的参数的值。配置文件如下所示：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>Example {<br />RdbmsLoginModule required<br />driver="org.gjt.mm.mysql.Driver"<br />url="jdbc:mysql://localhost/jaasdb?user=root"<br />debug="true";<br />};</td></tr></tbody></table><br />　　在配置文件中，RdbmsLoginModule包含了五个参数，其中driver、url、user和password是必需的，而debug是可选阐述。driver、url、user和password参数告诉我们如何获得JDBC连接。当然你还可以在ModuleOption域中加入数据库中的表或列的信息。使用这些参数的目的是为了能够对数据库进行操作。在LoginModule类的initialize（）方法中我们保存了每个参数的值。<br /><br />　　我们前面提到一个LoginContext对应的配置文件告诉它应该使用文件中的哪一个申请。这个信息是通过LgoinContext的构造函数传递的。下面是初始化客户端的代码，在代码中创建了一个LoginContex对象并调用了login（）方法。<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>ConsoleCallbackHandler cbh = new ConsoleCallbackHandler();<br />LoginContext lc = new LoginContext("Example", cbh);<br />lc.login();</td></tr></tbody></table><br />　　当LgoinContext.login（）方法被调用时，它调用所有加载了的LoginModule对象的login（）方法。在我们的这个例子中是RdbmsLoginModule中的login（）方法。<br /><br />　　RdbmsLoginModule中的login（）方法进行了下面的操作：<br /><br />　　1. 创建两个Callback对象。这些对象从用户输入中获取用户名/密码。程序中使用了JAAS中的两个Callback类:NameCallback和PasswordCallback（这两个类包含在javax.security.auth.callback包中）。<br /><br />　　2. 通过将callbacks作为参数传递给CallbackHandler的handle（）方法来激活Callback。<br /><br />　　3. 通过Callback对象获得用户名／密码。<br /><br />　　4. 在rdbmsValidate（）方法中通过JDBC在数据库中验证获取的用户名／密码。<br /><br />　　下面是RdbmsLoginModule中的login（）方法的代码<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>public boolean login() throws LoginException {<br />if (callbackHandler == null)<br />throw new LoginException("no handler");<br /><br />NameCallback nameCb = new NameCallback("user: ");<br />PasswordCallback passCb = new PasswordCallback("password: ", true);<br />callbacks = new Callback[] { nameCb, passCb };<br />callbackHandler.handle(callbacks);<br /><br />String username = nameCb.getName();<br />String password = new String(passCb.getPassword());<br />success = rdbmsValidate(username, password);<br /><br />return(true);<br />}</td></tr></tbody></table><br />　　在ConsoleCallbackHandler类的handle（）方法中你可以看到Callback对象是如何同用户进行交互的：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>public void handle(Callback[] callbacks)<br />throws java.io.IOException, UnsupportedCallbackException {<br /><br />for (int i = 0; i ＜ callbacks.length; i++) {<br />if (callbacks[i] instanceof NameCallback) {<br />NameCallback nameCb = (NameCallback)callbacks[i];<br />System.out.print(nameCb.getPrompt());<br />String user=(new BufferedReader(new <br /><br />InputStreamReader(System.in))).readLine();<br />nameCb.setName(user);<br />} else if (callbacks[i] instanceof PasswordCallback) {<br />PasswordCallback passCb = (PasswordCallback)callbacks[i];<br />System.out.print(passCb.getPrompt());<br />String pass=(new BufferedReader(new <br /><br />InputStreamReader(System.in))).readLine();<br />passCb.setPassword(pass.toCharArray());<br />} else {<br />throw(new UnsupportedCallbackException(callbacks[i],<br />"Callback class not supported"));<br />}<br />}<br />}</td></tr></tbody></table></span></div>
		<span class="txt">　　<b><font color="#ac000">使用JSP和关系数据库进行登录验证</font></b><br /><br />　　现在我们希望将通过命令行调用的程序一直到Web应用程序中。由于Web应用程序与一般的应用程序的交互方式有区别不同，我们将不能使用JAAS提供的标准Callback和CallbackHandler类。因为我们不能在Web程序中打开一个命令窗口让用户输入信息。也许你会想到我们也可以使用基于HTTP的验证，这样我们可以从浏览器弹出的用户名／密码窗口中获得用户输入。但是这样做也有一些问题，它要求建立起双向的HTTP连接（在login（）方法很难实现双向连接）。因此在我们的例子中我们会使用利用表单进行登录，从表单中获取用户输入的信息，然后通过RdbmsLoginModule类验证它。<br /><br />　　由于我们没有在应用层同LoginModule直接打交道，而是通过LgoinContext来调用其中的方法的，我们如何将获得用户名和密码放入LoginModule对象中呢？我们可以使用其它的方法来绕过这个问题，例如我们可以在创建LoginContext对象前先初始化一个Subject对象，在Subject对象的凭证中保存用户名和密码。然后我们可以将该Subject对象传递给LoginContext的构造函数。这种方法虽然从技术上来说没有什么问题，但是它在应用程序层增加了很多与安全机制相关的代码。而且通常是在验证后向Subject送入凭证，而不是之前。<br />前面我们提到可以实现一个CallbackHandler类，然后将它的实例传递给LoginContext对象。在这里我们可以采用类似的方法来处理用户名和密码。我们实现了一个新的类PassiveCallbackHandler。下面是在JSP中使用该类的代码：<br /><br /><script language="Javascript"><![CDATA[ocument.write("<img src='http://counter.yesky.com/counter.shtml?CID=72348977504190464&AID=-1&refer="+escape(document.referrer)+"&cur="+escape(document.URL)+"' border='0' alt='' width='0' height='0'>");]]&gt;</script><img height="0" alt="" src="http://counter.yesky.com/counter.shtml?CID=72348977504190464&amp;AID=-1&amp;refer=&amp;cur=http%3A//www.cublog.cn/u/13101/showart.php%3Fid%3D102721" width="0" border="0" /><img height="0" alt="" src="http://counter.yesky.com/counter.shtml?CID=72348977504190464&amp;AID=-1&amp;refer=http%3A//www.yesky.com/20030114/1648365_2.shtml&amp;cur=http%3A//www.yesky.com/20030114/1648365_3.shtml" width="0" border="0" /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>String user = request.getParameter("user");<br />String pass = request.getParameter("pass");<br />PassiveCallbackHandler cbh = new PassiveCallbackHandler(user, pass);<br />LoginContext lc = new LoginContext("Example", cbh); </td></tr></tbody></table><br />　　PassiveCallbackHandler中构造函数的参数包含了用户名和密码。因此它可以在Callbick对象中设定正确的值。下面是PassiveCallbackHandler类的handle（）方法的代码：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>public void handle(Callback[] callbacks)<br />throws java.io.IOException, UnsupportedCallbackException {<br />for (int i = 0; i ＜ callbacks.length; i++) {<br />if (callbacks[i] instanceof NameCallback) {<br />NameCallback nameCb = (NameCallback)callbacks[i]; <br /><br />nameCb.setName(user);<br />} else if(callbacks[i] instanceof PasswordCallback) {<br />PasswordCallback passCb = (PasswordCallback)callbacks[i];<br />passCb.setPassword(pass.toCharArray());<br />} else {<br />throw(new UnsupportedCallbackException(callbacks[i],<br />"Callback class not supported"));<br />}<br />}<br />}<br />}</td></tr></tbody></table><br />　　从上面的代码中可以发现实际上我们只是从ConsoleCallbackHandler中去除了那些提示用户输入的代码。<br /><br />　　在运行这个JSP例子的时候，我们需要设定系统属性，这样LgoinContext对象才知道如何查找名称为"Example"的配置。我们使用的是Resin服务器。在resin.conf中，我们增加了一个＜caucho.com＞节点：<br /><br /><table width="100%" bgcolor="#ffffff"><tbody><tr><td>＜system-property <br />java.security.auth.login.config="/resin/conf/jaas.config"/＞ </td></tr></tbody></table><br />　　<b><font color="#ac000">小结</font></b><br /><br />　　JAAS通过提供动态的、可扩展的模型来进行用户验证和控制权限，从而使应用程序有更加健壮的安全机制。同时它还能够让你能够很轻松地创建自己的登录机制。JAAS可以同时在在客户端和服务器端应用程序上工作。虽然在服务器端的JAAS到目前还不是很稳定，但是随着技术的发展，相信会很好地解决这个问题。</span>
<img src ="http://www.blogjava.net/landy/aggbug/44757.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/landy/" target="_blank">独孤过客</a> 2006-05-06 16:05 <a href="http://www.blogjava.net/landy/archive/2006/05/06/44757.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>OSCache分析</title><link>http://www.blogjava.net/landy/archive/2006/05/06/44756.html</link><dc:creator>独孤过客</dc:creator><author>独孤过客</author><pubDate>Sat, 06 May 2006 08:04:00 GMT</pubDate><guid>http://www.blogjava.net/landy/archive/2006/05/06/44756.html</guid><wfw:comment>http://www.blogjava.net/landy/comments/44756.html</wfw:comment><comments>http://www.blogjava.net/landy/archive/2006/05/06/44756.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/landy/comments/commentRss/44756.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/landy/services/trackbacks/44756.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 1														                																																																摘要																																				本文档介绍了如何在																		Portlet																应...&nbsp;&nbsp;<a href='http://www.blogjava.net/landy/archive/2006/05/06/44756.html'>阅读全文</a><img src ="http://www.blogjava.net/landy/aggbug/44756.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/landy/" target="_blank">独孤过客</a> 2006-05-06 16:04 <a href="http://www.blogjava.net/landy/archive/2006/05/06/44756.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用 Velocity 实现客户端和服务器端模板</title><link>http://www.blogjava.net/landy/archive/2006/05/06/44755.html</link><dc:creator>独孤过客</dc:creator><author>独孤过客</author><pubDate>Sat, 06 May 2006 08:02:00 GMT</pubDate><guid>http://www.blogjava.net/landy/archive/2006/05/06/44755.html</guid><wfw:comment>http://www.blogjava.net/landy/comments/44755.html</wfw:comment><comments>http://www.blogjava.net/landy/archive/2006/05/06/44755.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/landy/comments/commentRss/44755.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/landy/services/trackbacks/44755.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 灵活的模板引擎为 JSP 技术提供一种没有遗产负担的选择																																																																																																																																								...&nbsp;&nbsp;<a href='http://www.blogjava.net/landy/archive/2006/05/06/44755.html'>阅读全文</a><img src ="http://www.blogjava.net/landy/aggbug/44755.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/landy/" target="_blank">独孤过客</a> 2006-05-06 16:02 <a href="http://www.blogjava.net/landy/archive/2006/05/06/44755.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts 与 Velocity 的集成</title><link>http://www.blogjava.net/landy/archive/2006/05/06/44754.html</link><dc:creator>独孤过客</dc:creator><author>独孤过客</author><pubDate>Sat, 06 May 2006 08:02:00 GMT</pubDate><guid>http://www.blogjava.net/landy/archive/2006/05/06/44754.html</guid><wfw:comment>http://www.blogjava.net/landy/comments/44754.html</wfw:comment><comments>http://www.blogjava.net/landy/archive/2006/05/06/44754.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/landy/comments/commentRss/44754.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/landy/services/trackbacks/44754.html</trackback:ping><description><![CDATA[
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr valign="top">
								<td width="100%">
										<p id="subtitle">用五个步骤轻松替代 JSP </p>
										<img class="display-img" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="1" />
								</td>
								<td class="no-print" width="192">
										<img height="18" alt="developerWorks" src="http://www-128.ibm.com/developerworks/cn/i/dw.gif" width="192" />
								</td>
						</tr>
				</tbody>
		</table>
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr valign="top">
								<td width="10">
										<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" />
								</td>
								<td width="100%">
										<table class="no-print" cellspacing="0" cellpadding="0" width="160" align="right" border="0">
												<tbody>
														<tr>
																<td width="10">
																		<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" />
																</td>
																<td>
																		<table cellspacing="0" cellpadding="0" width="150" border="0">
																				<tbody>
																						<tr>
																								<td class="v14-header-1-small">文档选项</td>
																						</tr>
																				</tbody>
																		</table>
																		<table class="v14-gray-table-border" cellspacing="0" cellpadding="0" border="0">
																				<tbody>
																						<tr>
																								<td class="no-padding" width="150">
																										<table cellspacing="0" cellpadding="0" width="143" border="0">
																												<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" />
																												<form name="email" action="https://www-128.ibm.com/developerworks/secure/email-it.jsp">
																														<input type="hidden" value="Struts 大师 George Franciscus 介绍如何把 Velocity 模板引擎集成进 Struts 应用程序。" name="body" />
																														<input type="hidden" value="Struts 与 Velocity 的集成" name="subject" />
																														<input type="hidden" value="cn" name="lang" />
																														<script language="JavaScript" type="text/javascript">
																																<!--
document.write('<tr valign="top"><td width="8"><img src="//www.ibm.com/i/c.gif" width="8" height="1" alt=""/></td><td width="16"><img src="//www.ibm.com/i/v14/icons/em.gif" height="16" width="16" vspace="3" alt="将此页作为电子邮件发送" /></td><td width="122"><p><a class="smallplainlink" href="javascript:document.email.submit();"><b>将此页作为电子邮件发送</b></a></p></td></tr>');
//-->
																														</script>
																														<tbody>
																																<tr valign="top">
																																		<td width="8">
																																				<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" />
																																		</td>
																																		<td width="16">
																																				<img height="16" alt="将此页作为电子邮件发送" src="http://www.ibm.com/i/v14/icons/em.gif" width="16" vspace="3" />
																																		</td>
																																		<td width="122">
																																				<p>
																																						<a class="smallplainlink" href="javascript:document.email.submit();">
																																								<b>
																																										<font color="#002c99">将此页作为电子邮件发送</font>
																																								</b>
																																						</a>
																																				</p>
																																		</td>
																																</tr>
																														</tbody>
																														<tbody>
																																<tr valign="top">
																																		<td width="8">
																																				<font color="#002c99">
																																						<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" />
																																				</font>
																																		</td>
																																		<td width="16">
																																				<font color="#002c99">
																																						<img height="16" alt="将此页作为电子邮件发送" src="http://www.ibm.com/i/v14/icons/em.gif" width="16" vspace="3" />
																																				</font>
																																		</td>
																																		<td width="122">
																																				<p>
																																						<a class="smallplainlink" href="javascript:document.email.submit();">
																																								<b>
																																										<font color="#5c81a7">将此页作为电子邮件发送</font>
																																								</b>
																																						</a>
																																				</p>
																																		</td>
																																</tr>
																																<noscript>
																																		<tr valign="top">
																																				<td width="8">
																																						<img alt="" height="1" width="8" src="//www.ibm.com/i/c.gif" />
																																				</td>
																																				<td width="16">
																																						<img alt="" width="16" height="16" src="//www.ibm.com/i/c.gif" />
																																				</td>
																																				<td class="small" width="122">
																																						<p>
																																								<span class="ast">未显示需要 JavaScript 的文档选项</span>
																																						</p>
																																				</td>
																																		</tr>
																																</noscript>
																														</tbody>
																												</form>
																												<tr valign="top">
																														<td width="8">
																																<font color="#5c81a7">
																																		<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" />
																																</font>
																														</td>
																														<td width="16">
																																<font color="#5c81a7">
																																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/dn.gif" width="16" vspace="3" border="0" />
																																</font>
																														</td>
																														<td width="122">
																																<p>
																																		<a class="smallplainlink" href="http://www-128.ibm.com/developerworks/cn/java/j-sr1.html#download">
																																				<b>
																																						<font color="#996699">样例代码</font>
																																				</b>
																																		</a>
																																</p>
																														</td>
																												</tr>
																										</table>
																								</td>
																						</tr>
																				</tbody>
																		</table>
																</td>
														</tr>
												</tbody>
										</table>
										<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
										<!-- 03/20/06 updated by gretchen -->
										<br />
										<table cellspacing="0" cellpadding="0" width="150" border="0">
												<tbody>
														<tr>
																<td class="v14-header-2-small">最新推荐</td>
														</tr>
												</tbody>
										</table>
										<table class="v14-gray-table-border" cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td class="no-padding" width="150">
																		<table cellspacing="0" cellpadding="0" width="143" border="0">
																				<tbody>
																						<tr valign="top">
																								<td width="8">
																										<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" />
																								</td>
																								<td>
																										<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/fw_bold.gif" width="16" vspace="3" border="0" />
																								</td>
																								<td width="125">
																										<p>
																												<a class="smallplainlink" href="http://www-128.ibm.com/developerworks/cn/kickstart/">
																														<font color="#5c81a7">Java 应用开发源动力 － 下载免费软件，快速启动开发</font>
																												</a>
																										</p>
																								</td>
																						</tr>
																				</tbody>
																		</table>
																</td>
														</tr>
												</tbody>
										</table>
										<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<p>级别: 中级</p>
		<p>
				<a href="http://www-128.ibm.com/developerworks/cn/java/j-sr1.html#author">
						<font color="#996699">George Franciscus</font>
				</a>, 首席顾问, Nexcel<br /></p>
		<p>2005 年 10 月 17 日</p>
		<blockquote>
				<i>Struts Recipes</i> 的合著者 George Franciscus 带您一步步地把 Velocity 模板引擎集成进 Struts 应用程序。结果是一个快速、灵活的 JSP 替代物，同时带有希望从 Struts 得到的所有方便。</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>Java™ 服务器页面（JSP）技术是如此普及，以至于人们忘记了在创建 Web 页面时还有其他选择。但是最近，有些开发人员已经转向模板引擎，以获得在 JSP 中得不到的灵活性。虽然用 JSP 和模板引擎都可以把数据嵌入 HTML，但是每种技术都有自己的处理方式。Velocity 模板是一个特别流行的 JSP 替代品。Velocity 提供了平缓的学习曲线和巨大的易用性。开发人员喜欢它简洁的语法，而且性能分析也证明它的性能超出 JSP。Velocity 也非常容易集成进 Struts 应用程序。</p>
		<p>在这篇文章中，我将介绍如何在 Struts 应用程序中集成和使用 Velocity 模板引擎。我会首先提供一个公式，然后逐步展开它。生成的应用程序组合了 Struts 和 Velocity —— 一个第一流的组合，可能会让您怀疑自己对 JSP 的忠诚！</p>
		<p>请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-sr1.html#download"><font color="#996699">下载</font></a> 一节，在开始之前下载这篇文章的源代码，以及 Struts、Velocity 和 Velocity 工具包。请注意，本文假设您熟悉使用 Struts 框架进行 MVC 编程。</p>
		<p>
				<a name="N10069">
						<span class="atitle">
								<font face="Arial" size="4">关于模板引擎</font>
						</span>
				</a>
		</p>
		<p>在开始集成 Struts 和 Velocity 的简单任务之前，让我们先确保您理解模板引擎和它们在视图生成中的角色。模板引擎作为整体概念，Velocity 作为具体实现，它们的生命在 HTML 之外。Velocity 把数据合并到文本主体中不同的点上。文本可以是文字、电子邮件或 HTML。由于采用这种方式，Velocity 模板引擎有点儿像 Microsoft Word 的“邮件合并”特性。邮件合并允许您方便地把动态数据（例如姓名、地址和电话号码）合并到信件中。在早期的日子里，组织用这项特性生成大型邮件列表并把它们送到邮局，导致垃圾邮件的产生！</p>
		<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="N10075">
																				<b>Velocity 是什么？</b>
																		</a>
																		<br />
																		<p>Velocity 是一个基于 Java 的模板引擎，它提供了简单的基于模板的语言，可以用类似脚本的方式引用对象。Velocity 促进了分离团队成员之间的责任：允许 Web 设计人员专注于视图（即页面的观感），而 Java 程序员专注于后端代码。把 Java 代码从页面布局中分离出来，会让 Web 应用程序未来更易维护。当 Velocity 与 Sruts 这样的 MVC 框架结合时，就成了 JSP 或 PHP 可行的替代。</p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>在 Web 应用程序中，Velocity 实现的目标与 JSP 相同：可以用它在向 <code><font face="新宋体">HttpServletResponse</font></code> 的 <code><font face="新宋体">OutputStream</font></code> 发送之前生成要发送的 HTML。在 Struts 应用程序中使用 Velocity 的一种方式是在 Struts 的 <code><font face="新宋体">Action</font></code> 内部写入响应，然后返回 null 的 <code><font face="新宋体">ActionForward</font></code>。虽然这种技术可行，但却有严重的缺陷：无法使用 <i>struts-config.xml</i> 文件把响应抽象出来。把视图放在 <code><font face="新宋体">Action</font></code> 内部，意味着如果想要修改响应，就必须修改 <code><font face="新宋体">Action</font></code>。</p>
		<p>因为这种技术剥夺了 Struts 最好的一项特性（即从视图中抽象出重点的能力），所以我更愿意把所有响应指向一个 servlet，由它负责访问 Velocity 模板，合并上下文的数据，生成响应，然后再送回浏览器。稍后就会学到，Velocity 的设计者们已经把这些步骤全都捆绑在了一起：您需要做的只是跟着我来看如何一步步地实现它们。如果您还没有 <a href="http://www-128.ibm.com/developerworks/cn/java/j-sr1.html#download"><font color="#996699">访问“下载”一节</font></a>，现在是访问的时候了。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-sr1.html#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N100A4">
						<span class="atitle">
								<font face="Arial" size="4">Velocity 的五步</font>
						</span>
				</a>
		</p>
		<p>把 Struts 与 Velocity 模板引擎组合起来很简单，也很直接；实际上，只要用五步就可以实现：</p>
		<ol>
				<li>把 Velocity JAR 放在类路径中。 
</li>
				<li>修改 web.xml 文件让它识别 Velocity servlet。 
</li>
				<li>把 Velocity toolbox.xml 放在应用程序的 WEB-INF 目录下。 
</li>
				<li>修改 struts-config，把它的视图指向 Velocity 模板而不是 JSP。 
</li>
				<li>为每个需要显示的页面创建 Velocity 模板。 </li>
		</ol>
		<p>我将用一个熟悉的搜索用例来演示 Struts 与 Velocity 的集成。在这个示例中，一个简单的应用程序允许用户按照图书的 ISBN 编号搜索图书。应用程序的结果页面显示与 ISBN 编号匹配的图书。</p>
		<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="N100C5">
																				<b>放弃 Struts 标记 —— 不！</b>
																		</a>
																		<br />
																		<p>现在，您可能会想，是不是需要放弃那些过去让您节约了许多编码时间的很好的 Struts 标记。如果不使用 JSP，那么肯定没有使用 Struts 的 JSP 标记！幸运的是，您可以使用 Velocity 工具。Velocity 的 Struts 工具提供了所有您熟悉的 Struts 方便特性，但是添加了 Velocity 的灵活性。</p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<a name="N100CF">
						<span class="smalltitle">
								<strong>
										<font face="Arial" size="3">第 1 步：把 Velocity JAR 放在 WEB-INF/lib 下</font>
								</strong>
						</span>
				</a>
		</p>
		<p>如果您还没下载 Velocity，那么现在需要下载它。Velocity 本身是很棒的，但是它的工具包可以帮助您把工作做得更好更快。特别是 Struts 工具模拟了您以前熟悉的 Struts 标记。请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-sr1.html#download"><font color="#996699">下载</font></a> 一节下载 Velocity 模板引擎和 Velocity 工具。</p>
		<p>请注意不同时候，需要的 jar 也会略有不同。在这里我不想列出一个 JAR 列表，只是想建议您访问 Velocity 的主页（请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-sr1.html#resources"><font color="#996699">参考资料</font></a>）并阅读那里的安装指南。一旦得到了需要的 JAR，只需把它们放在 WEB-INF\lib 下面即可。</p>
		<p>
				<a name="N100E4">
						<span class="smalltitle">
								<strong>
										<font face="Arial" size="3">第 2 步：修改 web.xml，让它识别 Velocity 的 servlet</font>
								</strong>
						</span>
				</a>
		</p>
		<p>下一步是修改 Struts 的 web.xml 文件，让它识别 Velocity 的 servlet 并把所有以 <i>.vm</i> 结尾的资源请求定向到 Velocity servlet，如清单 1 所示。</p>
		<br />
		<a name="N100F5">
				<b>清单 1. 修改 web.xml，声明 Velocity servlet</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">				
&lt;servlet&gt;
  &lt;servlet-name&gt;velocity&lt;/servlet-name&gt; <span class="boldcode"><strong>|(1)</strong></span>
  &lt;servlet-class&gt; <span class="boldcode"><strong>|(2)</strong></span>
         org.apache.velocity.tools.view.servlet.VelocityViewServlet 
  &lt;/servlet-class&gt;                                            

  &lt;init-param&gt; <span class="boldcode"><strong>|(3)</strong></span>
    &lt;param-name&gt;org.apache.velocity.toolbox&lt;/param-name&gt; 
    &lt;param-value&gt;/WEB-INF/toolbox.xml&lt;/param-value&gt;      
 &lt;/init-param&gt;                                                 

 &lt;load-on-startup&gt;10&lt;/load-on-startup&gt; <span class="boldcode"><strong>|(4)</strong></span>
&lt;/servlet&gt;

&lt;!-- Map *.vm files to Velocity --&gt;
&lt;servlet-mapping&gt; <span class="boldcode"><strong>|(5)</strong></span>
  &lt;servlet-name&gt;velocity&lt;/servlet-name&gt;
  &lt;url-pattern&gt;*.vm&lt;/url-pattern&gt;      
&lt;/servlet-mapping&gt; 
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>让我们来看看清单 1 中发生了什么：</p>
		<ul>
				<li>（1）声明了 Velocity servlet 并给了它一个 <i>velocity</i> 句柄。 
</li>
				<li>（2）声明了 Velocity servlet 的类名。 </li>
		</ul>
		<p>Velocity servlet 接受“toolbox”参数。toolbox 是声明应用程序的可用工具的位置。因此，在清单 1 中，我还做了以下工作：</p>
		<ul>
				<li>（3）告诉 <code><font face="新宋体">VelocityServlet</font></code> 在哪里可以找到 toolbox 的配置。<br /><br /></li>
				<li>（4）设置了 <code><font face="新宋体">load-on-startup</font></code> 标记，确保在正确的时间装入 Velocity servlet。任何大于或等于 0 的值都会迫使容器通过调用 servlet 的 <code><font face="新宋体">init()</font></code> 方法来装入它。放在 <code><font face="新宋体">load-on-startup</font></code> 标记体中的值决定了不同的 servlet 的 <code><font face="新宋体">init</font></code> 方法调用的次序。例如，0 在 1 之前调用，而 1 在 2 之前调用。缺少的标记或负值允许 servlet 容器根据自己的选择装入 servlet。<br /><br /></li>
				<li>（5）声明了 servlet 映射，强迫所有用 <i>.vm</i> 结尾的资源请求定向到 Velocity servlet。请注意（5）中的&lt;servlet-name&gt; 必须与（1）中的&lt;servlet-name&gt; 匹配。交错的声明和映射会在日志中生成错误。 </li>
		</ul>
		<p>
				<a name="N10148">
						<span class="smalltitle">
								<strong>
										<font face="Arial" size="3">第 3 步：把 toolbox.xml 放在 WEB-INF 下</font>
								</strong>
						</span>
				</a>
		</p>
		<p>利用 Velocity，可以使用（或创建）包含许多工具的工具箱。用来登记类的工具箱中包含有用的函数，常常会用到。幸运的是，Velocity 提供了许多预先构建好的工具。还创建了许多 Struts 工具来模拟原始的 Struts 标记。如果发现需要构建自己的工具，也可以自由地构建。在清单 2 中显示的 toolbox.xml 可以在 Velocity 工具下载中找到。这个文件应当随 Velocity JAR 一起放在 WEB-INF 下。</p>
		<br />
		<a name="N10156">
				<b>清单 2. toolbox.xml</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">				
&lt;?xml version="1.0"?&gt;
&lt;toolbox&gt;
  &lt;tool&gt;
     &lt;key&gt;link&lt;/key&gt;
     &lt;scope&gt;request&lt;/scope&gt;
     &lt;class&gt;
       org.apache.velocity.tools.struts.StrutsLinkTool
     &lt;/class&gt;
  &lt;/tool&gt;
  &lt;tool&gt;
     &lt;key&gt;msg&lt;/key&gt;
     &lt;scope&gt;request&lt;/scope&gt;
     &lt;class&gt;
       org.apache.velocity.tools.struts.MessageTool
     &lt;/class&gt;
  &lt;/tool&gt;
  &lt;tool&gt;
     &lt;key&gt;errors&lt;/key&gt;
     &lt;scope&gt;request&lt;/scope&gt;
     &lt;class&gt;
       org.apache.velocity.tools.struts.ErrorsTool
     &lt;/class&gt;
  &lt;/tool&gt;
  &lt;tool&gt;
     &lt;key&gt;form&lt;/key&gt;
     &lt;scope&gt;request&lt;/scope&gt;
     &lt;class&gt;
       org.apache.velocity.tools.struts.FormTool
     &lt;/class&gt;
  &lt;/tool&gt;
  &lt;tool&gt;
     &lt;key&gt;tiles&lt;/key&gt;
     &lt;scope&gt;request&lt;/scope&gt;
     &lt;class&gt;
       org.apache.velocity.tools.struts.TilesTool
     &lt;/class&gt;
  &lt;/tool&gt;
  &lt;tool&gt;
     &lt;key&gt;validator&lt;/key&gt;
     &lt;scope&gt;request&lt;/scope&gt;
     &lt;class&gt;
       org.apache.velocity.tools.struts.ValidatorTool
     &lt;/class&gt;
  &lt;/tool&gt;
&lt;/toolbox&gt;
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="N1015D">
						<span class="smalltitle">
								<strong>
										<font face="Arial" size="3">第 4 步：修改 struts-config</font>
								</strong>
						</span>
				</a>
		</p>
		<p>下一步是修改 struts-config.xml，指向 Velocity 视图而不是 JSP。新的配置文件如清单 3 所示。</p>
		<br />
		<a name="N1016B">
				<b>清单 3. 针对 Velocity 视图修改后的 struts-config.xml </b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">				
&lt;?xml version="1.0" encoding="ISO-8859-1" ?&gt;

&lt;!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.0//EN"
          "http://jakarta.apache.org/struts/dtds/struts-config_1_0.dtd"&gt;

&lt;struts-config&gt;
    &lt;form-beans&gt;
        &lt;form-bean name="searchForm" type="app.SearchForm"/&gt; 
    &lt;/form-beans&gt;

    &lt;global-forwards&gt;
        &lt;forward name="welcome" path="/welcome.do"/&gt;
    &lt;/global-forwards&gt;
 
   &lt;action-mappings&gt;
        &lt;action 
            path="/welcome"
            type="org.apache.struts.actions.ForwardAction"
            parameter="/pages/search.vm"/&gt; <span class="boldcode"><strong>|(1)</strong></span>

        &lt;action 
            path="/search"
            type="app.SearchAction"
            name="searchForm"    
            scope="request"
            input="/pages/search.vm"&gt; <span class="boldcode"><strong>|(2)</strong></span>
            &lt;forward name="success" 
              path="/pages/results.vm"/&gt; <span class="boldcode"><strong>|(3)</strong></span>
        &lt;/action&gt;
    &lt;/action-mappings&gt;
&lt;/struts-config&gt;
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>清单 3 看起来就像一个非常典型的 Struts 应用程序，只有一个小小的不同。响应没有把客户转向到 JSP，而直接转向到 <i>.vm</i> 文件（请参阅清单 3 中的引用 1、2 和 3）。在大多数情况下，把 Struts 应用程序从 JSP 迁移到 Velocity 视图，需要做的仅仅是全局搜索，把 <i>.jsp</i> 替换成 <i>.vm</i>。其他所有东西都可以保持不变！模板可以同样保存在以前保存 JSP 的位置；所需要做的只是用 Velocity 命令代替 JSP 标记。</p>
		<p>
				<a name="N10187">
						<span class="smalltitle">
								<strong>
										<font face="Arial" size="3">第 5 步：创建 Velocity 模板</font>
								</strong>
						</span>
				</a>
		</p>
		<p>在清单 4 中，可以看到示例应用程序搜索页面的 Velocity 模板。</p>
		<br />
		<a name="N10195">
				<b>清单 4. 搜索页面的 Velocity 模板</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">				
&lt;HTML&gt;
  &lt;HEAD&gt;
    &lt;TITLE&gt;Search&lt;/TITLE&gt;
  &lt;/HEAD&gt;
  &lt;BODY&gt;
    $!errors.msgs()|<span class="boldcode"><strong>|(1)</strong></span>
    &lt;FORM method="POST" 
      action="$link.setAction('/search')"&gt; <span class="boldcode"><strong>|(2)</strong></span>
      &lt;h2&gt;Book Search&lt;/h2&gt;
      ISBN:&lt;INPUT type="text" name="isbn"&gt;
      &lt;INPUT type="submit" value="Submit" name="submit"&gt;
    &lt;/FORM&gt;
  &lt;/BODY&gt;
&lt;/HTML&gt;
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>清单 4 是一个没有 JSP 或 Struts 标记的典型的 HTML 页面。但是，以下元素看起来可能不是那么熟悉：</p>
		<ul>
				<li>（1）用 <code><font face="新宋体">$!errors.msgs()</font></code> 得到错误消息队列中的错误消息。 
</li>
				<li>（2）用 <code><font face="新宋体">$link.setAction('/search')</font></code> 获得搜索转发的 URL。 </li>
		</ul>
		<p>这就成功了 —— 模板剩下的部分看起来几乎与以前熟悉的 HTML 文件相同。清单 5 显示了应用程序结果页面的模板。</p>
		<br />
		<a name="N101BD">
				<b>清单 5. 结果页面的 Velocity 模板</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">				
&lt;html&gt;
  &lt;body&gt;

  &lt;h1&gt;Book Details&lt;/h1&gt;
  &lt;a href="$link.setForward("searchEntry")"&gt;Search again&lt;/a&gt; <span class="boldcode"><strong>|(1)</strong></span>

  &lt;h3&gt;$book.title&lt;/h3&gt; <span class="boldcode"><strong>|(2)</strong></span>

    &lt;b&gt;ISBN:&lt;/b&gt;$book.isbn&lt;br&gt;<span class="boldcode"><strong>|(3)</strong></span>
    &lt;b&gt;Title:&lt;/b&gt;$book.title&lt;br&gt;<span class="boldcode"><strong>|(4)</strong></span>
    &lt;b&gt;Author:&lt;/b&gt;$book.author&lt;br&gt;<span class="boldcode"><strong>|(5)</strong></span>
    &lt;b&gt;Price:&lt;/b&gt;$book.price&lt;br&gt;<span class="boldcode"><strong>|(6)</strong></span>
    &lt;b&gt;No Pages:&lt;/b&gt;$book.pages&lt;br&gt;<span class="boldcode"><strong>|(7)</strong></span>
    &lt;b&gt;Description:&lt;/b&gt;$book.description&lt;br&gt;<span class="boldcode"><strong>|(8)</strong></span>
    &lt;b&gt;Publisher:&lt;/b&gt;$book.publisher&lt;br&gt;<span class="boldcode"><strong>|(9)</strong></span>
  &lt;/body&gt;
&lt;html&gt;
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>可以注意到，清单 5 中不包含 JSP 标记或 Struts 标记。我们来详细看看它：</p>
		<ul>
				<li>（1）用 Struts 的链接工具把 <code><font face="新宋体">&lt;a&gt;</font></code> 标记的 <i>href</i> 设置为 Struts 转发。 
</li>
				<li>（2）访问 <code><font face="新宋体">$book title</font></code> 属性。 
</li>
				<li>（3）访问 <code><font face="新宋体">$book isbn</font></code> 属性。 
</li>
				<li>（4）再次访问 <code><font face="新宋体">$book title</font></code> 属性。 
</li>
				<li>（5）访问 <code><font face="新宋体">$book author</font></code> 属性。 
</li>
				<li>（6）访问 <code><font face="新宋体">$book price</font></code> 属性。 
</li>
				<li>（7）访问 <code><font face="新宋体">$book pages</font></code> 属性。 
</li>
				<li>（8）访问 <code><font face="新宋体">$book description</font></code> 属性。 
</li>
				<li>（9）访问 <code><font face="新宋体">$book publisher</font></code> 属性。 </li>
		</ul>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-sr1.html#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10227">
						<span class="atitle">
								<font face="Arial" size="4">讨论</font>
						</span>
				</a>
		</p>
		<p>这就是把 Struts 与 Velocity 模板引擎集成的全部工作。表面看起来非常简单（实际上也很简单），但是请想想是什么让这个集成能够工作的呢？</p>
		<p>Struts 动作映射可以定义任何视图，不仅限于 JSP。在这篇文章中，我只是把动作映射修改为以 <i>vm</i> 结尾而不是以 <i>jsp</i> 结尾的返回文件。然后，我声明了 Velocity servlet，并告诉 Servlet 容器把以 <i>vm</i> 结尾的文件发送给 <code><font face="新宋体">VelocityViewServlet</font></code>。</p>
		<p>
				<code>
						<font face="新宋体">VelocityViewServlet</font>
				</code> 把 Velocity 命令表示成 HTML 响应。通过这种方式，<code><font face="新宋体">VelocityViewServlet</font></code> 充当了视图响应的拦截器。Struts 控制器把视图转发给 <code><font face="新宋体">VelocityViewServlet</font></code>，后者在向客户端发送响应之前处理 <i>vm</i> 文件。请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-sr1.html#resources"><font color="#996699">参考资料</font></a> 获得关于将 Velocity 视图集成进 Struts 应用程序的更多内容。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-sr1.html#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10257">
						<span class="atitle">
								<font face="Arial" size="4">结束语</font>
						</span>
				</a>
		</p>
		<p>正如在本文中看到的，Struts 与 Velocity 的集成很简单。只需五个步骤就可以把所有东西连在一起。针对不同的引擎和场景，采用模板引擎而不是 JSP 的优势各有不同。在 Velocity 的情况下，优势就是简单性、容易学习以及更好的性能。</p>
		<br />
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-sr1.html#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<span class="atitle">
						<a name="download">
								<font face="Arial" size="4">下载</font>
						</a>
				</span>
		</p>
		<table class="data-table-1" cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<th>描述</th>
								<th>名字</th>
								<th style="TEXT-ALIGN: right">大小</th>
								<th>下载方法</th>
						</tr>
						<tr>
								<td class="tb-row">Sample code</td>
								<td nowrap="">j-sr1-source.zip</td>
								<td style="TEXT-ALIGN: right" nowrap="">3 MB</td>
								<td nowrap=""> <a class="fbox" href="ftp://www6.software.ibm.com/software/developer/library/j-sr1-source.zip"><b><font color="#5c81a7">FTP</font></b></a></td>
						</tr>
				</tbody>
		</table>
		<table cellspacing="0" cellpadding="0" border="0">
				<tbody>
						<tr valign="top">
								<td colspan="5">
										<font color="#5c81a7">
												<img height="12" alt="" src="http://www.ibm.com/i/c.gif" width="12" border="0" />
										</font>
								</td>
						</tr>
						<tr>
								<td>
										<font color="#5c81a7">
												<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/fw.gif" width="16" />
										</font>
								</td>
								<td>
										<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/whichmethod.html">
												<font color="#5c81a7">关于下载方法的信息</font>
										</a>
								</td>
								<td>
										<font color="#5c81a7">
												<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="50" />
										</font>
								</td>
								<td>
										<font color="#5c81a7">
												<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/sout.gif" width="16" />
										</font>
								</td>
								<td>
										<a class="fbox" href="http://www.adobe.com/products/acrobat/readstep2.html">
												<font color="#5c81a7">Get Adobe® Reader®</font>
										</a>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/landy/aggbug/44754.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/landy/" target="_blank">独孤过客</a> 2006-05-06 16:02 <a href="http://www.blogjava.net/landy/archive/2006/05/06/44754.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HttpClient-基于Java的网络编程</title><link>http://www.blogjava.net/landy/archive/2006/05/06/44753.html</link><dc:creator>独孤过客</dc:creator><author>独孤过客</author><pubDate>Sat, 06 May 2006 08:01:00 GMT</pubDate><guid>http://www.blogjava.net/landy/archive/2006/05/06/44753.html</guid><wfw:comment>http://www.blogjava.net/landy/comments/44753.html</wfw:comment><comments>http://www.blogjava.net/landy/archive/2006/05/06/44753.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/landy/comments/commentRss/44753.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/landy/services/trackbacks/44753.html</trackback:ping><description><![CDATA[
		<p>
				<a name="IDADCG0">
						<span class="atitle">HttpClient简介</span>
				</a>
		</p>
		<p>HTTP 协议可能是现在 Internet 上使用得最多、最重要的协议了，越来越多的 Java 应用程序需要直接通过 HTTP 协议来访问网络资源。虽然在 JDK 的 java.net 包中已经提供了访问 HTTP 协议的基本功能，但是对于大部分应用程序来说，JDK 库本身提供的功能还不够丰富和灵活。HttpClient 是 Apache Jakarta Common 下的子项目，用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包，并且它支持 HTTP 协议最新的版本和建议。HttpClient 已经应用在很多的项目中，比如 Apache Jakarta 上很著名的另外两个开源项目 Cactus 和 HTMLUnit 都使用了 HttpClient，更多使用 HttpClient 的应用可以参见<a href="http://wiki.apache.org/jakarta-httpclient/HttpClientPowered"><font color="#0000ff">http://wiki.apache.org/jakarta-httpclient/HttpClientPowered</font></a>。HttpClient 项目非常活跃，使用的人还是非常多的。目前 HttpClient 版本是在 2005.10.11 发布的 3.0 RC4 。</p>
		<div>
				<table style="TABLE-LAYOUT: fixed" cellspacing="0" cellpadding="0" width="90%" border="0">
						<tbody>
						</tbody>
				</table>
		</div>
		<div>
				<table class="no-print" cellspacing="0" cellpadding="0" align="right">
						<tbody>
								<tr align="right">
										<td style="LEFT: 0px; WORD-WRAP: break-word">
												<table style="TABLE-LAYOUT: fixed" cellspacing="0" cellpadding="0" border="0">
														<tbody>
														</tbody>
												</table>
										</td>
								</tr>
						</tbody>
				</table>
		</div>
		<div>
				<br />
		</div>
		<p>
				<a name="IDAOCG0">
						<span class="atitle">HttpClient 功能介绍</span>
				</a>
		</p>
		<p>以下列出的是 HttpClient 提供的主要的功能，要知道更多详细的功能可以参见 HttpClient 的主页。</p>
		<ul>
				<li>实现了所有 HTTP 的方法（GET,POST,PUT,HEAD 等） 
</li>
				<li>支持自动转向 
</li>
				<li>支持 HTTPS 协议 
</li>
				<li>支持代理服务器等</li>
		</ul>
		<p>下面将逐一介绍怎样使用这些功能。首先，我们必须安装好 HttpClient。</p>
		<ul>
				<li>HttpClient 可以在<a href="http://jakarta.apache.org/commons/httpclient/downloads.html"><font color="#0000ff">http://jakarta.apache.org/commons/httpclient/downloads.html</font></a>下载 
</li>
				<li>HttpClient 用到了 Apache Jakarta common 下的子项目 logging，你可以从这个地址<a href="http://jakarta.apache.org/site/downloads/downloads_commons-logging.cgi"><font color="#0000ff">http://jakarta.apache.org/site/downloads/downloads_commons-logging.cgi</font></a>下载到 common logging，从下载后的压缩包中取出 commons-logging.jar 加到 CLASSPATH 中 
</li>
				<li>HttpClient 用到了 Apache Jakarta common 下的子项目 codec，你可以从这个地址<a href="http://jakarta.apache.org/site/downloads/downloads_commons-codec"><font color="#0000ff">http://jakarta.apache.org/site/downloads/downloads_commons-codec</font></a>.cgi 下载到最新的 common codec，从下载后的压缩包中取出 commons-codec-1.x.jar 加到 CLASSPATH 中</li>
		</ul>
		<p style="TEXT-INDENT: 2em">HttpClient 基本功能的使用</p>
		<p>
				<a name="IDASDG0">
						<span class="smalltitle">GET 方法</span>
				</a>
		</p>
		<p>使用 HttpClient 需要以下 6 个步骤：</p>
		<p>1. 创建 HttpClient 的实例</p>
		<p>2. 创建某种连接方法的实例，在这里是 GetMethod。在 GetMethod 的构造函数中传入待连接的地址</p>
		<p>3. 调用第一步中创建好的实例的 execute 方法来执行第二步中创建好的 method 实例</p>
		<p>4. 读 response</p>
		<p>5. 释放连接。无论执行方法是否成功，都必须释放连接</p>
		<p>6. 对得到后的内容进行处理</p>
		<p>根据以上步骤，我们来编写用GET方法来取得某网页内容的代码。</p>
		<ul>
				<li>大部分情况下 HttpClient 默认的构造函数已经足够使用。 
<table style="TABLE-LAYOUT: fixed" cellspacing="0" cellpadding="5" width="90%" bgcolor="#eeeeee" border="1"><tbody><tr><td style="LEFT: 0px; WORD-WRAP: break-word"><pre><code class="section">HttpClient httpClient = new HttpClient();</code></pre></td></tr></tbody></table><br /></li>
				<li>创建GET方法的实例。在GET方法的构造函数中传入待连接的地址即可。用GetMethod将会自动处理转发过程，如果想要把自动处理转发过程去掉的话，可以调用方法setFollowRedirects(false)。 
<table style="TABLE-LAYOUT: fixed" cellspacing="0" cellpadding="5" width="90%" bgcolor="#eeeeee" border="1"><tbody><tr><td style="LEFT: 0px; WORD-WRAP: break-word"><pre><code class="section">GetMethod getMethod = new GetMethod("http://www.ibm.com/");</code></pre></td></tr></tbody></table><br /></li>
				<li>调用实例httpClient的executeMethod方法来执行getMethod。由于是执行在网络上的程序，在运行executeMethod方法的时候，需要处理两个异常，分别是HttpException和IOException。引起第一种异常的原因主要可能是在构造getMethod的时候传入的协议不对，比如不小心将"http"写成"htp"，或者服务器端返回的内容不正常等，并且该异常发生是不可恢复的；第二种异常一般是由于网络原因引起的异常，对于这种异常 （IOException），HttpClient会根据你指定的恢复策略自动试着重新执行executeMethod方法。HttpClient的恢复策略可以自定义（通过实现接口HttpMethodRetryHandler来实现）。通过httpClient的方法setParameter设置你实现的恢复策略，本文中使用的是系统提供的默认恢复策略，该策略在碰到第二类异常的时候将自动重试3次。executeMethod返回值是一个整数，表示了执行该方法后服务器返回的状态码，该状态码能表示出该方法执行是否成功、需要认证或者页面发生了跳转（默认状态下GetMethod的实例是自动处理跳转的）等。 
<table style="TABLE-LAYOUT: fixed" cellspacing="0" cellpadding="5" width="90%" bgcolor="#eeeeee" border="1"><tbody><tr><td style="LEFT: 0px; WORD-WRAP: break-word"><pre><code class="section">//设置成了默认的恢复策略，在发生异常时候将自动重试3次，在这里你也可以设置成自定义的恢复策略getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,     		new DefaultHttpMethodRetryHandler()); //执行getMethodint statusCode = client.executeMethod(getMethod);if (statusCode != HttpStatus.SC_OK) {  System.err.println("Method failed: " + getMethod.getStatusLine());}</code></pre></td></tr></tbody></table><br /></li>
				<li>在返回的状态码正确后，即可取得内容。取得目标地址的内容有三种方法：第一种，getResponseBody，该方法返回的是目标的二进制的byte流；第二种，getResponseBodyAsString，这个方法返回的是String类型，值得注意的是该方法返回的String的编码是根据系统默认的编码方式，所以返回的String值可能编码类型有误，在本文的"字符编码"部分中将对此做详细介绍；第三种，getResponseBodyAsStream，这个方法对于目标地址中有大量数据需要传输是最佳的。在这里我们使用了最简单的getResponseBody方法。 
<table style="TABLE-LAYOUT: fixed" cellspacing="0" cellpadding="5" width="90%" bgcolor="#eeeeee" border="1"><tbody><tr><td style="LEFT: 0px; WORD-WRAP: break-word"><pre><code class="section">byte[] responseBody = method.getResponseBody();</code></pre></td></tr></tbody></table><br /></li>
				<li>释放连接。无论执行方法是否成功，都必须释放连接。 
<table style="TABLE-LAYOUT: fixed" cellspacing="0" cellpadding="5" width="90%" bgcolor="#eeeeee" border="1"><tbody><tr><td style="LEFT: 0px; WORD-WRAP: break-word"><pre><code class="section">method.releaseConnection();</code></pre></td></tr></tbody></table><br /></li>
				<li>处理内容。在这一步中根据你的需要处理内容，在例子中只是简单的将内容打印到控制台。 
<table style="TABLE-LAYOUT: fixed" cellspacing="0" cellpadding="5" width="90%" bgcolor="#eeeeee" border="1"><tbody><tr><td style="LEFT: 0px; WORD-WRAP: break-word"><pre><code class="section">System.out.println(new String(responseBody));</code></pre></td></tr></tbody></table><br /></li>
		</ul>
		<p>下面是程序的完整代码。</p>
		<p>
				<br />
				<a name="IDA5EG0">
						<b>
						</b>
				</a>
				<br />
		</p>
		<table style="TABLE-LAYOUT: fixed" cellspacing="0" cellpadding="5" width="90%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td style="LEFT: 0px; WORD-WRAP: break-word">
										<pre>
												<code class="section">package test;import java.io.IOException;import org.apache.commons.httpclient.*;import org.apache.commons.httpclient.methods.GetMethod;import org.apache.commons.httpclient.params.HttpMethodParams;public class GetSample{  public static void main(String[] args) {  //构造HttpClient的实例  HttpClient httpClient = new HttpClient();  //创建GET方法的实例  GetMethod getMethod = new GetMethod("http://www.ibm.com");  //使用系统提供的默认的恢复策略  getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,    new DefaultHttpMethodRetryHandler());  try {   //执行getMethod   int statusCode = httpClient.executeMethod(getMethod);   if (statusCode != HttpStatus.SC_OK) {    System.err.println("Method failed: "      + getMethod.getStatusLine());   }   //读取内容    byte[] responseBody = getMethod.getResponseBody();   //处理内容   System.out.println(new String(responseBody));  } catch (HttpException e) {   //发生致命的异常，可能是协议不对或者返回的内容有问题   System.out.println("Please check your provided http address!");   e.printStackTrace();  } catch (IOException e) {   //发生网络异常   e.printStackTrace();  } finally {   //释放连接   getMethod.releaseConnection();  } }}</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p style="TEXT-INDENT: 2em">POST方法</p>
		<p>根据RFC2616，对POST的解释如下：POST方法用来向目的服务器发出请求，要求它接受被附在请求后的实体，并把它当作请求队列（Request-Line）中请求URI所指定资源的附加新子项。POST被设计成用统一的方法实现下列功能：</p>
		<ul>
				<li>对现有资源的注释（Annotation of existing resources） 
</li>
				<li>向电子公告栏、新闻组，邮件列表或类似讨论组发送消息 
</li>
				<li>提交数据块，如将表单的结果提交给数据处理过程 
</li>
				<li>通过附加操作来扩展数据库</li>
		</ul>
		<p>调用HttpClient中的PostMethod与GetMethod类似，除了设置PostMethod的实例与GetMethod有些不同之外，剩下的步骤都差不多。在下面的例子中，省去了与GetMethod相同的步骤，只说明与上面不同的地方，并以登录清华大学BBS为例子进行说明。</p>
		<ul>
				<li>构造PostMethod之前的步骤都相同，与GetMethod一样，构造PostMethod也需要一个URI参数，在本例中，登录的地址是http://www.newsmth.net/bbslogin2.php。在创建了PostMethod的实例之后，需要给method实例填充表单的值，在BBS的登录表单中需要有两个域，第一个是用户名（域名叫id），第二个是密码（域名叫passwd）。表单中的域用类NameValuePair来表示，该类的构造函数第一个参数是域名，第二参数是该域的值；将表单所有的值设置到PostMethod中用方法setRequestBody。另外由于BBS登录成功后会转向另外一个页面，但是HttpClient对于要求接受后继服务的请求，比如POST和PUT，不支持自动转发，因此需要自己对页面转向做处理。具体的页面转向处理请参见下面的"自动转向"部分。代码如下： 
<table style="TABLE-LAYOUT: fixed" cellspacing="0" cellpadding="5" width="90%" bgcolor="#eeeeee" border="1"><tbody><tr><td style="LEFT: 0px; WORD-WRAP: break-word"><pre><code class="section">String url = "http://www.newsmth.net/bbslogin2.php";PostMethod postMethod = new PostMethod(url);// 填入各个表单域的值NameValuePair[] data = { new NameValuePair("id", "youUserName"),				new NameValuePair("passwd", "yourPwd") };// 将表单的值放入postMethod中postMethod.setRequestBody(data);// 执行postMethodint statusCode = httpClient.executeMethod(postMethod);// HttpClient对于要求接受后继服务的请求，象POST和PUT等不能自动处理转发// 301或者302if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {    // 从头中取出转向的地址    Header locationHeader = postMethod.getResponseHeader("location");    String location = null;    if (locationHeader != null) {     location = locationHeader.getValue();     System.out.println("The page was redirected to:" + location);    } else {     System.err.println("Location field value is null.");    }    return;}</code></pre></td></tr></tbody></table></li>
		</ul>
		<p style="TEXT-INDENT: 2em">下面介绍在使用HttpClient过程中常见的一些问题。</p>
		<p>
				<a name="IDA5FG0">
						<span class="smalltitle">字符编码</span>
				</a>
		</p>
		<p>某目标页的编码可能出现在两个地方，第一个地方是服务器返回的http头中，另外一个地方是得到的html/xml页面中。</p>
		<ul>
				<li>在http头的Content-Type字段可能会包含字符编码信息。例如可能返回的头会包含这样子的信息：Content-Type: text/html; charset=UTF-8。这个头信息表明该页的编码是UTF-8，但是服务器返回的头信息未必与内容能匹配上。比如对于一些双字节语言国家，可能服务器返回的编码类型是UTF-8，但真正的内容却不是UTF-8编码的，因此需要在另外的地方去得到页面的编码信息；但是如果服务器返回的编码不是UTF-8，而是具体的一些编码，比如gb2312等，那服务器返回的可能是正确的编码信息。通过method对象的getResponseCharSet()方法就可以得到http头中的编码信息。 
</li>
				<li>对于象xml或者html这样的文件，允许作者在页面中直接指定编码类型。比如在html中会有这样的标签；或者在xml中会有<li>这样的标签，在这些情况下，可能与http头中返回的编码信息冲突，需要用户自己判断到底那种编码类型应该是真正的编码。</li></li>
				<p>
						<a name="IDAIGG0">
								<span class="smalltitle">自动转向</span>
						</a>
				</p>
				<p>根据RFC2616中对自动转向的定义，主要有两种：301和302。301表示永久的移走（Moved Permanently），当返回的是301，则表示请求的资源已经被移到一个固定的新地方，任何向该地址发起请求都会被转到新的地址上。302表示暂时的转向，比如在服务器端的servlet程序调用了sendRedirect方法，则在客户端就会得到一个302的代码，这时服务器返回的头信息中location的值就是sendRedirect转向的目标地址。</p>
				<p>HttpClient支持自动转向处理，但是象POST和PUT方式这种要求接受后继服务的请求方式，暂时不支持自动转向，因此如果碰到POST方式提交后返回的是301或者302的话需要自己处理。就像刚才在POSTMethod中举的例子：如果想进入登录BBS后的页面，必须重新发起登录的请求，请求的地址可以在头字段location中得到。不过需要注意的是，有时候location返回的可能是相对路径，因此需要对location返回的值做一些处理才可以发起向新地址的请求。</p>
				<p>另外除了在头中包含的信息可能使页面发生重定向外，在页面中也有可能会发生页面的重定向。引起页面自动转发的标签是： 
</p>
				<meta http-equiv="refresh" content="5; url=http://www.ibm.com/us" />。如果你想在程序中也处理这种情况的话得自己分析页面来实现转向。需要注意的是，在上面那个标签中url的值也可以是一个相对地址，如果是这样的话，需要对它做一些处理后才可以转发。<p><a name="IDAQGG0"><span class="smalltitle">处理HTTPS协议</span></a></p><p>HttpClient提供了对SSL的支持，在使用SSL之前必须安装JSSE。在Sun提供的1.4以后的版本中，JSSE已经集成到JDK中，如果你使用的是JDK1.4以前的版本则必须安装JSSE。JSSE不同的厂家有不同的实现。下面介绍怎么使用HttpClient来打开Https连接。这里有两种方法可以打开https连接，第一种就是得到服务器颁发的证书，然后导入到本地的keystore中；另外一种办法就是通过扩展HttpClient的类来实现自动接受证书。</p><p style="TEXT-INDENT: 2em">方法1，取得证书，并导入本地的keystore：</p><ol><li>安装JSSE （如果你使用的JDK版本是1.4或者1.4以上就可以跳过这一步）。本文以IBM的JSSE为例子说明。先到IBM网站上下载JSSE的安装包。然后解压开之后将ibmjsse.jar包拷贝到<java-home>\lib\ext\目录下。 
<li>取得并且导入证书。证书可以通过IE来获得： 
<p>1． 用IE打开需要连接的https网址，会弹出如下对话框：</p><br /><a name="IDA3GG0"><b></b></a><br /><img style="BORDER-RIGHT: black 1px solid; BORDER-TOP: black 1px solid; BORDER-LEFT: black 1px solid; BORDER-BOTTOM: black 1px solid" height="301" src="http://tech.ccidnet.com/col/attachment/2006/3/611581.png" width="384" /><br /><p>2． 单击"View Certificate"，在弹出的对话框中选择"Details"，然后再单击"Copy to File"，根据提供的向导生成待访问网页的证书文件</p><br /><a name="IDALHG0"><b></b></a><br /><img style="BORDER-RIGHT: black 1px solid; BORDER-TOP: black 1px solid; BORDER-LEFT: black 1px solid; BORDER-BOTTOM: black 1px solid" height="476" src="http://tech.ccidnet.com/col/attachment/2006/3/611583.png" width="409" /><br /><p>3． 向导第一步，欢迎界面，直接单击"Next"，</p><br /><a name="IDAZHG0"><b></b></a><br /><img style="BORDER-RIGHT: black 1px solid; BORDER-TOP: black 1px solid; BORDER-LEFT: black 1px solid; BORDER-BOTTOM: black 1px solid" height="386" src="http://tech.ccidnet.com/col/attachment/2006/3/611585.png" width="503" /><br /><p>4． 向导第二步，选择导出的文件格式，默认，单击"Next"，</p><br /><a name="IDAKAO0"><b></b></a><br /><img style="BORDER-RIGHT: black 1px solid; BORDER-TOP: black 1px solid; BORDER-LEFT: black 1px solid; BORDER-BOTTOM: black 1px solid" height="386" src="http://tech.ccidnet.com/col/attachment/2006/3/611587.png" width="503" /><br /><p>5． 向导第三步，输入导出的文件名，输入后，单击"Next"，</p><br /><a name="IDAYAO0"><b></b></a><br /><img style="BORDER-RIGHT: black 1px solid; BORDER-TOP: black 1px solid; BORDER-LEFT: black 1px solid; BORDER-BOTTOM: black 1px solid" height="454" src="http://tech.ccidnet.com/col/attachment/2006/3/611589.png" width="506" /><br /><p>6． 向导第四步，单击"Finish"，完成向导</p><br /><a name="IDAGBO0"><b></b></a><br /><img style="BORDER-RIGHT: black 1px solid; BORDER-TOP: black 1px solid; BORDER-LEFT: black 1px solid; BORDER-BOTTOM: black 1px solid" height="386" src="http://tech.ccidnet.com/col/attachment/2006/3/611591.png" width="503" /><br /><p>7． 最后弹出一个对话框，显示导出成功</p><br /><a name="IDAUBO0"><b></b></a><br /><img style="BORDER-RIGHT: black 1px solid; BORDER-TOP: black 1px solid; BORDER-LEFT: black 1px solid; BORDER-BOTTOM: black 1px solid" height="100" src="http://tech.ccidnet.com/col/attachment/2006/3/611593.png" width="183" /><br /></li><li><p>用keytool工具把刚才导出的证书倒入本地keystore。Keytool命令在<java-home>\bin\下，打开命令行窗口，并到<java-home>\lib\security\目录下，运行下面的命令：</java-home></java-home></p><table style="TABLE-LAYOUT: fixed" cellspacing="0" cellpadding="5" width="90%" bgcolor="#eeeeee" border="1"><tbody><tr><td style="LEFT: 0px; WORD-WRAP: break-word"><pre><code class="section">keytool -import -noprompt -keystore cacerts -storepass changeit -alias yourEntry1 -file your.cer</code></pre></td></tr></tbody></table><br /><p>其中参数alias后跟的值是当前证书在keystore中的唯一标识符，但是大小写不区分；参数file后跟的是刚才通过IE导出的证书所在的路径和文件名；如果你想删除刚才导入到keystore的证书，可以用命令：</p><table style="TABLE-LAYOUT: fixed" cellspacing="0" cellpadding="5" width="90%" bgcolor="#eeeeee" border="1"><tbody><tr><td style="LEFT: 0px; WORD-WRAP: break-word"><pre><code class="section">keytool -delete -keystore cacerts -storepass changeit -alias yourEntry1</code></pre></td></tr></tbody></table><br /></li><li>写程序访问https地址。如果想测试是否能连上https，只需要稍改一下GetSample例子，把请求的目标变成一个https地址。 
<table style="TABLE-LAYOUT: fixed" cellspacing="0" cellpadding="5" width="90%" bgcolor="#eeeeee" border="1"><tbody><tr><td style="LEFT: 0px; WORD-WRAP: break-word"><pre><code class="section">GetMethod getMethod = new GetMethod("https://www.yourdomain.com");</code></pre></td></tr></tbody></table><br /><p>运行该程序可能出现的问题：</p><p>1. 抛出异常java.net.SocketException: Algorithm SSL not available。出现这个异常可能是因为没有加JSSEProvider，如果用的是IBM的JSSE Provider，在程序中加入这样的一行：</p><table style="TABLE-LAYOUT: fixed" cellspacing="0" cellpadding="5" width="90%" bgcolor="#eeeeee" border="1"><tbody><tr><td style="LEFT: 0px; WORD-WRAP: break-word"><pre><code class="section"> if(Security.getProvider("com.ibm.jsse.IBMJSSEProvider") == null) Security.addProvider(new IBMJSSEProvider()); </code></pre></td></tr></tbody></table><br /><p>或者也可以打开<java-home>\lib\security\java.security，在行</java-home></p><table style="TABLE-LAYOUT: fixed" cellspacing="0" cellpadding="5" width="90%" bgcolor="#eeeeee" border="1"><tbody><tr><td style="LEFT: 0px; WORD-WRAP: break-word"><pre><code class="section">security.provider.1=sun.security.provider.Sunsecurity.provider.2=com.ibm.crypto.provider.IBMJCE</code></pre></td></tr></tbody></table><br /><p>后面加入security.provider.3=com.ibm.jsse.IBMJSSEProvider</p><p>2. 抛出异常java.net.SocketException: SSL implementation not available。出现这个异常可能是你没有把ibmjsse.jar拷贝到<java-home>\lib\ext\目录下。</java-home></p><p>3. 抛出异常javax.net.ssl.SSLHandshakeException: unknown certificate。出现这个异常表明你的JSSE应该已经安装正确，但是可能因为你没有把证书导入到当前运行JRE的keystore中，请按照前面介绍的步骤来导入你的证书。</p></li></java-home></li></ol><p style="TEXT-INDENT: 2em">方法２，扩展HttpClient类实现自动接受证书</p><p>因为这种方法自动接收所有证书，因此存在一定的安全问题，所以在使用这种方法前请仔细考虑您的系统的安全需求。具体的步骤如下：</p><ul><li>提供一个自定义的socket factory（test.MySecureProtocolSocketFactory）。这个自定义的类必须实现接口org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory，在实现接口的类中调用自定义的X509TrustManager(test.MyX509TrustManager)，这两个类可以在随本文带的附件中得到 
</li><li>创建一个org.apache.commons.httpclient.protocol.Protocol的实例，指定协议名称和默认的端口号 
<table style="TABLE-LAYOUT: fixed" cellspacing="0" cellpadding="5" width="90%" bgcolor="#eeeeee" border="1"><tbody><tr><td style="LEFT: 0px; WORD-WRAP: break-word"><pre><code class="section">Protocol myhttps = new Protocol("https", new MySecureProtocolSocketFactory (), 443);</code></pre></td></tr></tbody></table><br /></li><li>注册刚才创建的https协议对象 
<table style="TABLE-LAYOUT: fixed" cellspacing="0" cellpadding="5" width="90%" bgcolor="#eeeeee" border="1"><tbody><tr><td style="LEFT: 0px; WORD-WRAP: break-word"><pre><code class="section">Protocol.registerProtocol("https ", myhttps);</code></pre></td></tr></tbody></table><br /></li><li>然后按照普通编程方式打开https的目标地址，代码请参见test.NoCertificationHttpsGetSample</li></ul><p><a name="IDAJDO0"><span class="smalltitle">处理代理服务器</span></a></p><p>HttpClient中使用代理服务器非常简单，调用HttpClient中setProxy方法就可以，方法的第一个参数是代理服务器地址，第二个参数是端口号。另外HttpClient也支持SOCKS代理。</p><p><br /><a name="IDAPDO0"><b></b></a><br /></p><table style="TABLE-LAYOUT: fixed" cellspacing="0" cellpadding="5" width="90%" bgcolor="#eeeeee" border="1"><tbody><tr><td style="LEFT: 0px; WORD-WRAP: break-word"><pre><code class="section">httpClient.getHostConfiguration().setProxy(hostName,port);</code></pre></td></tr></tbody></table><br /><table style="TABLE-LAYOUT: fixed" cellspacing="0" cellpadding="0" width="90%" border="0"><tbody></tbody></table><br /><p><a name="IDAWDO0"><span class="atitle">结论</span></a></p><p>从上面的介绍中，可以知道HttpClient对http协议支持非常好，使用起来很简单，版本更新快，功能也很强大，具有足够的灵活性和扩展性。对于想在Java应用中直接访问http资源的编程人员来说，HttpClient是一个不可多得的好工具。</p></ul>
<img src ="http://www.blogjava.net/landy/aggbug/44753.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/landy/" target="_blank">独孤过客</a> 2006-05-06 16:01 <a href="http://www.blogjava.net/landy/archive/2006/05/06/44753.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何使用Java编写NT服务</title><link>http://www.blogjava.net/landy/archive/2006/05/06/44752.html</link><dc:creator>独孤过客</dc:creator><author>独孤过客</author><pubDate>Sat, 06 May 2006 07:57:00 GMT</pubDate><guid>http://www.blogjava.net/landy/archive/2006/05/06/44752.html</guid><wfw:comment>http://www.blogjava.net/landy/comments/44752.html</wfw:comment><comments>http://www.blogjava.net/landy/archive/2006/05/06/44752.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/landy/comments/commentRss/44752.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/landy/services/trackbacks/44752.html</trackback:ping><description><![CDATA[
		<div>内容简介：本文通过例子讲解了如何利用Java的特性快速编写安全可靠的NT服务,并展示了Java的多线程如何实施，以及如何应用套接字实现网络服务。<br /><br />关键词：Java  JntSvc.exe NT服务 多线程 套接字编程<br /><br /> <br /><br />一、NT服务介绍<br /><br />所谓NT服务，实际上是一类特殊的应用程序所谓NT服务，实际上就是一个可以在系统启动时自动在一定身份下启动的伴随系统长时间存在的进程。象FTP server、HTTP server、脱机打印等都是采用NT服务的形式提供的。这实际上类似Unix的root daemon进程。NT服务归纳起来，NT服务又以下几个特征：<br /><br />1、可以自启动，不需要交互启动。这对于服务器来说是一个重要的特征。当然，你可以决定服务是否自启动，甚至可以屏蔽某个服务。<br />    2、NT服务没有用户界面，基本上类似一个DOS 程序，因为NT服务必须长时间运行，所以不想普通win32进程一样有自己的界面。但是NT服务可以同用户有界面交互，这是一类特殊的服务进程。可以通过NT的任务管理器来看到服务进程。<br />    3、NT服务通过SCM（Services Control Manager）接口来管理，安装、启动、停止、撤除等都需要SCM的接口功能来进行。控制面板的服务控制器就是利用SCM接口来管理系统中的所有服务的。实际上，还有一些可以控制服务的程序或者命令，有net.exe 、服务器管理器等 、SCM.exe等。<br />    4、这些进程都以一定的身份运行，以方便进行服务器资源的存取。一般情况下使用域中的LocalSystem账号运行，此账号对本机上的大多数资源（除非特别禁止）有完全的存取权限，这样可以保证服务程序的“强大”。但是，也有些服务采用特别的账号运行，你也可以特别设定一个服务的帐号。<br />    5、由系统自动以线程方式运行，一般情况下不过多占用系统资源，这同普通的进程有所区别，如果不采用线程方式，一般进程往往消耗整个CPU资源。一般需要时时存在，又不能过多消耗资源的任务以服务来实现最合适。<br /><br /> <br /><br />二、Java编写服务的准备<br /><br />1、作为本地化的实现，实现NT服务的Java程序当然不是100%纯Java，单靠标准类库是无法实现我们的编写NT服务的目的，所以MS提供了一套SDK for Java(本文采用的是Microsoft SDK for Java 4.0)，提到了如何利用MS提供的扩展类库和相应的工具，实现符合Windows平台需要的程序。其中包括了实现NT服务的所需要的类库API框架以及将Java编译的class文件组装成标准的NT服务程序的工具。SDK的下载路径可以从www.microsoft.com/java/查找到。<br /><br />2、安装完SDK后可以看到在安装目录下有jntsvc目录，此目录就包含了service.zip文件，它实际上是一个NT services的类库框架，封装了一些NT服务实现细节，使得我们可以按照框架舒服实现我们关心的细节。将service.zip展开至开发机器的系统安装Service库到Java扩展库\Winnt\java\TrustLib下，如果在其他操作系统下进行开发，参照此系统目录进行安装文件。<br /><br />3、在该目录下还有一个jntsvc.exe文件,也就是Java NT Service的意思啦。她可以帮助您实现将按照SDK提供的框架实现的编译后的class文件组装成一个标准的NT服务可执行文件。JntSvc帮助我们在已经编译好的.class文件基础上设置了所有NT服务程序必须的特征，是很重要的工具，得到NT服务取决于如何有效利用她。为了我们能够方便从任何其他目录的控制台窗口调用她，我们将JntSvc.exe所在的目录全路径加入path环境变量。这可以通过设置系统属性的高级属性页当中进行环境变量的设定。<br /><br />4、按照要求，我们写好各项代码，然后编译编写Java程序，得到class文件。我们当然不会在Vj Studio中启动她，因为它目前还没有可执行文件的入口，系统无法启动她。为了得到NT服务程序，我们需要在class文件所在目录的控制台窗口执行一个命令：X：&gt;jntsvc *.class /OUT:ECHOSvc.exe /SVCMAIN:EchoSvc          "/SERVICENAME:ECHOSvc"。具体的Jntsvc的参数我们可以看一看jntsvc -?得到，这里的意思大概是：将当前目录下的所有class文件组装成一个NT服务进程exe文件，文件名为EchoSvc.exe,服务的启动入口在echosvc.class中，在注册表中相应的服务名称为/Servicename参数指定的EchoSvc。如果有多个多个NT服务需要组装在一个Exe文件中，还可以在 /Out参数后指定每一个服务展示名称。/SVCMAIN参数指定服务的入口，所谓入口是指服务启动之初是从哪一个类的实例开始的。"/SERVICENAME:"参数指定了该服务将以什么名称出现。这些参数都是jntsvc.exe实用工具需要组装服务所必须的信息，根据这些信息将编译后的.class文件按照win32格式要求得到一个可执行文件。<br /><br />需要注意的是，这个exe文件的运行必须要有JVM存在，她实际上是通过解释.class来实现服务提供的。如果需要另外的扩展包，可以通过在/Classpath参数指定另外的扩展包的位置。所以在安装Java编写得到的NT服务的机器上必须存在JVM。如果是拥有IE5.x那么不用操心这个问题，IE核心组件已经包括了JVM；但是如果是IE6版本，则需要到MS的网站上下载JVM。如果您讲SDK for Java安装在服务器上就更方便了。<br /><br />5、如果没有什么错误，您将得到一个可执行文件echosvc.exe。像大多数服务可执行文件一样，它可以将自己安装到系统中: echosvc.exe ?install，这一个过程将会往系统注册表添加一些项目，特别是关于服务的项目，SCM也可以列出这个服务了。我们可以在控制台下采用DOS NT服务控制命令Net start/stop来测试服务是否真像普通服务一样可以按照标准方式来控制,当然在服务管理器当中启停该服务更不会有问题。<br /><br /> <br /><br />三、Echo服务的样例<br /><br />当系统载入服务进程时，入口是在EchoSvc的构造函数中，我们可以看到此构造函数带有同一般程序的入口main()类似的参数。<br />import com.ms.service.* ;<br /><br /> public class EchoSvc extends Service <br /><br />{     static Thread mainSvc=null ; //定义服务主线程<br /><br />       public  EchoSvc (String[] args) //构造此服务<br /><br />       {<br /><br />         CheckPoint(1000);    <br /><br />              setRunning(ACCEPT_SHUTDOWN | ACCEPT_PAUSE_CONTINUE |ACCEPT_STOP); // 该项服务接受的关于服务控制的命令<br /><br />              mainSvc = new Thread((Runnable) new  MainSvcThread());<br /><br />        mainSvc.start();     <br /><br />       System.out.println( "The Echo Service Was Started Successfully!");//纪录事件，可以通过事件察看器看到<br /><br />       }<br /><br />}<br /><br />CheckPoint是 Service的同步方法，指示系统正改变服务的状态，需要让系统等待1秒。这里我们启动的是一个线程，实际上相当于一个进程，她是服务进程的主线程。在这个线程中我们响应SCM对此服务的控制。大致的表达为：<br /><br />public class MainSvcThread implements Runnable //实现线程控制<br /><br />{     <br /><br />public static boolean STOP = false;  //由系统来控制的内部变量，决定着服务进程（线程）的启动、暂停等<br /><br />      public static boolean PAUSE = false; <br /><br />  <br /><br />         public void run()<br /><br />         {<br /><br />        while (!STOP)<br /><br />                 {  <br /><br />                        while (!PAUSE &amp;&amp; !STOP) <br /><br />                        {<br /><br />                              。。。//此处为服务控制逻辑，下面会充实此处<br /><br />                      }<br /><br />                try <br /><br />                {Thread.sleep(5000);//休眠5秒后实现暂停或者停止} <br /><br />                catch (InterruptedException e) <br /><br />{ }<br /><br />              }<br /><br />            try <br /><br />                     {Thread.sleep(1000);}<br /><br />                     catch (InterruptedException ie) <br /><br />                     {}<br /><br />         }<br /><br />         }  //Run结束  <br /><br />}<br /><br />在服务逻辑控制当中，我们会具体实现Echo服务。我们的Echo服务监听2002端口，接收客户端任何一行输入，然后加上“Echo:”后返回。如果客户端输入一个quit词组那么服务认为这是客户关闭此套接字的命令，会自动关闭当前的套接字连接，停止对当前连接的服务。具体的实现(EchoThread.java的代码)：<br /><br />public void run()<br /><br />       {<br /><br />        String line;<br /><br />        DataInputStream in;<br /><br />        PrintWriter out;<br /><br />        boolean exitflag=false;<br /><br /> <br /><br />       try<br /><br />       {<br /><br />        in=new DataInputStream(so.getInputStream()) ;//获取套接字的输入流<br /><br />        out=new PrintWriter(new DataOutputStream(so.getOutputStream())) ;<br /><br />      out.println("You have connected to EchoSvc!");  //发送问候<br /><br />        out.flush(); <br /><br />        while((line=in.readLine())!=null) //读取<br /><br />         {<br /><br />               line=line.trim();<br /><br />               if (line.equalsIgnoreCase("quit") )<br /><br />               {<br /><br />           out.println("ECHO:" + line );<br /><br />                 out.flush();<br /><br />return;<br /><br />}<br /><br />               else<br /><br />               {<br /><br />               out.println("ECHO:" + line );<br /><br />               out.flush(); <br /><br />               }<br /><br />         }<br /><br />        in.close();<br /><br />        out.close();<br /><br />}<br /><br />catch(IOException ioe)<br /><br />              {}<br /><br />}<br /><br />Echo服务主要就是将客户发送的字符回显给客户，并加上Echo:的前缀，以表明是从服务器返回的内容。如果客户输入“quit”那么表示这是要求服务器停止服务的表现。<br /><br />如何调试NT服务进程工程。如果直接将此函数调用来提供客户端的ECHO套接字服务,逻辑上是没有什么错误，但是就是无法支持多个用户同时访问。为了能够提供多服务，允许同时又多个用户连接此服务器（这种情况在很多网络服务都不可少），我们可以将此逻辑在由MainSvcTread创建的线程中实现,而且可以允许多个用户同时访问此服务。具体的表达在MainSvcTread的run函数中实现：<br /><br />while(ListenThreadCount&lt;maxSocket) //如果当前启动的线程数在系统允许的范围内<br /><br />{<br /><br />          server=li.accept(); //监听<br /><br />          EchoThread p=new EchoThread(server,this);//创建实现该服务的具体逻辑对象，是一个支持线程的类<br /><br />          Thread t=new Thread(g,(Runnable)p) ; //将当前线程并入线成组<br /><br />          t.start(); //启动服务线程<br /><br />          ListenThreadCount++; //修改当前线程数量<br /><br />       }<br /><br />参照上面提到的工具Jntsvc.exe可以帮助你讲编译好的.class文件组装成exe文件，运行此文并加上-install参数可以自动帮助您讲些好的服务添加到注册表中，可以通过服务管理器或者相当的实用程序来如同其他服务一样来进行控制了。撤除服务采用-uninstall参数。<br /><br />本例程采用套接字、多线程实现技术来解释实现Java编写NT服务，实际上类似这样的很多网络方面的服务都可以按照此规范实现，譬如POP3服务、FTP服务，甚至WWW服务等。我们也接触过像Tomcat、Jrun等Java应用服务器在NT平台的启动往往采用NT服务形式，那么通过此例你也可以尝试编写自己的Java服务应用。<br /><br />    最后，如果需要调试NT服务的逻辑，可以采用一个变通的办法。我们在EchoSvc.java中添加一个Main静态方法，然后产生一个EchoSvc的实例，这样就是一个标准的VJ产生的Exe文件，利用Vj的调试功能我们可以排除隐藏的错误。一旦调通后，我们注释掉main静态方法，编译后就可以得到一个调试好的NT服务。<br /><br /> <br /><br />四、为什么要采用Java编写NT服务<br /><br />比较VC等“原装”NT服务开发方式而言，Java开发模式可以更快捷，因为几乎所有得服务框架通过扩展Services类就可以达到，省下不少复杂的细节处理。Java语言提供了丰富的类库，可以为自己使用，可以提高效率，而且编写的程序结构清晰容易理解，方便以后维护。<br /><br />Java提供的异常处理模式，可以让我们写好结构良好，更加安全的代码。试想如果编写的服务进程由于采用VC编写却忘记对某块内存的释放，那么服务启动后一段时间由于内存泄漏造成服务性能下降，甚至系统崩溃；但是Java本身的语言特性可以使我们不用时刻提防内存管理，可以更加关注服务逻辑本身，是的实现起来更加有效率。<br /><br />采用VC如果编写多线程服务进程，虽然可以实现，但是会相当麻烦。而服务进程多线程几乎是每一个性能良好的服务必备特征，Java语言本身可以提供这方面良好的支持，同时Java自身对网络的天然良好支持，使各种网络套接字编程容易。<br /><br />最后，如果不采用其他扩展库，我们很容易将此服务逻辑实现在其他操作系统上。一个编写好的NT服务程序，可以在去掉对Ms的相关本地化扩展实现的类引用后，方便移植到其他例如Linux等平台上，尽可能向Java的“一次编写、到处可运行”的理想境界靠拢。<br /><br /> <br /><br />五、源码<br /><br />/*所附的ZIP文件报含示例的全部工程文件，还有编译后的NT服务的可执行文件，您可以直接测试此服务exe文件的安装、服务启停*/<br /><br />/*EchoSvc.java*/<br /><br />import com.ms.service.* ;<br /><br />public class EchoSvc extends Service <br /><br />{<br /><br />       static Thread mainSvc=null ; //定义主线程<br /><br /> <br /><br />       public  EchoSvc (String[] args) //构造服务<br /><br />       {<br /><br />                CheckPoint(1000);    //服务是系统的一部分，作为Log纪录，可以帮助用户理解系统故障<br /><br />                     setRunning(ACCEPT_SHUTDOWN | ACCEPT_PAUSE_CONTINUE |ACCEPT_STOP);<br /><br />                     mainSvc = new Thread((Runnable) new  MainSvcThread());<br /><br />            mainSvc.start();     <br /><br />                     System.out.println( "The Echo Service Was Started Successfully!");<br /><br />       }<br /><br />}<br /><br />/*-------------- EchoSvc.java源码结束-------------------*/<br /><br /> <br /><br />/*MainSvcThread.java*/<br /><br />import java.io.*;<br /><br />import java.net.*;<br /><br />public class MainSvcThread implements Runnable //实现线程控制多线程接口<br /><br />{     /将启动一组线程来监听多个服务请求<br /><br />         public static boolean STOP = false;  //由系统来控制的内部变量，决定着服务进程（线程）的启动、暂停等<br /><br />      public static boolean PAUSE = false; <br /><br />         public int ListenThreadCount=0;  //本服务支持的当前线程数量<br /><br />         int maxSocket=10;  //最大支持的同时连结数<br /><br />         int SvcPort=2002;  //服务监听的端口<br /><br />         <br /><br />         public void run()<br /><br />         {<br /><br />        try<br /><br />               {<br /><br />           while (!STOP)<br /><br />                 {  <br /><br />                        while (!PAUSE &amp;&amp; !STOP) <br /><br />                        {<br /><br />                               {//创建监听服务器<br /><br />                             Socket server;  <br /><br />                             ServerSocket  li=new ServerSocket(SvcPort);  //创建服务器端套接字<br /><br />                             ThreadGroup g=new ThreadGroup("EchoThreads"); //创建一组线程<br /><br />                    System.out.println("Echo service starting...");  //记录在Log中<br /><br />                             while(ListenThreadCount&lt;maxSocket)<br /><br />                                      {<br /><br />                                             server=li.accept();  //监听<br /><br />                                             EchoThread p=new EchoThread(server,this); //创建服务单线程<br /><br />                                             Thread t=new Thread(g,(Runnable)p) ; //创建新线程<br /><br />                                             t.start(); //启动服务线程<br /><br />                                             ListenThreadCount++; //当前线程的数量<br /><br />                                      }<br /><br />                      }<br /><br />                   try <br /><br />                   {<br /><br />                     Thread.sleep(5000);//暂停5秒<br /><br />                    } <br /><br />                    catch (InterruptedException e) <br /><br />{   }<br /><br />              }<br /><br />               try <br /><br />                         {<br /><br />                           Thread.sleep(1000);<br /><br />                         }<br /><br />                        catch (InterruptedException ie) <br /><br />                       {  }<br /><br />          }<br /><br />              }<br /><br />              catch (IOException ioe)<br /><br />              {} <br /><br />         }  //Run结束  <br /><br />}<br /><br />/*-------------- MainSvcThread.java源码结束-------------------*/<br /><br /> <br /><br />/*EchoThread.java*/<br /><br />import java.io.*;<br /><br />import java.net.*;<br /><br />/*实现每一个客户连接到此NT服务时的服务器端的线程单元逻辑*/<br /><br />public class EchoThread implements Runnable   //实现线程接口<br /><br />{<br /><br />    Socket so=null;//套接字<br /><br />       MainSvcThread p;  //一个指向父线程的指针,EchoThread的线程是服务线程的创建的子线程<br /><br />       public void run()<br /><br />              {<br /><br />               String line;<br /><br />               DataInputStream in; //套接字上的输入流<br /><br />               PrintWriter out;   //套接字上的输出流，带缓冲<br /><br />               boolean exitflag=false;<br /><br />              try<br /><br />              {<br /><br />               in=new DataInputStream(so.getInputStream()) ;//获取套接字的输入流<br /><br />               out=new PrintWriter(new DataOutputStream(so.getOutputStream())) ;<br /><br />            out.println("You have connected to EchoSvc!");  //发送问候<br /><br />               out.flush();   //必须刷新缓冲区内的内容<br /><br /> <br /><br />               while((line=in.readLine())!=null &amp;&amp; ! exitflag)<br /><br />                {<br /><br />                      line=line.trim();<br /><br />                      if (line.equalsIgnoreCase("quit") )<br /><br />                      {//如果是退出命令,则关闭当前套接字上的输入输出流<br /><br />                            in.close();<br /><br />                out.flush();<br /><br />                            out.close();<br /><br />p.ListenThreadCount --; //主线程的服务线程单元数量控制<br /><br />                            return;   //退出当前的服务逻辑线程单元<br /><br />                      }<br /><br />                      else<br /><br />                      {<br /><br />                      out.println("ECHO:" + line );<br /><br />                      out.flush(); <br /><br />                      }<br /><br />                 }<br /><br />          in.close();<br /><br />                out.close();<br /><br />                p.ListenThreadCount --;<br /><br />              }<br /><br />              catch(IOException ioe)<br /><br />              {}<br /><br />       }<br /><br />       <br /><br />  EchoThread(Socket s,MainSvcThread parent)<br /><br />       {<br /><br />              so=s;<br /><br />              p= parent;<br /><br />       }<br /><br />}<br /><br />/*-------------- EchoThread.java源码结束-------------------*/<br /></div>
<img src ="http://www.blogjava.net/landy/aggbug/44752.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/landy/" target="_blank">独孤过客</a> 2006-05-06 15:57 <a href="http://www.blogjava.net/landy/archive/2006/05/06/44752.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>What is AspectJ</title><link>http://www.blogjava.net/landy/archive/2006/05/06/44751.html</link><dc:creator>独孤过客</dc:creator><author>独孤过客</author><pubDate>Sat, 06 May 2006 07:56:00 GMT</pubDate><guid>http://www.blogjava.net/landy/archive/2006/05/06/44751.html</guid><wfw:comment>http://www.blogjava.net/landy/comments/44751.html</wfw:comment><comments>http://www.blogjava.net/landy/archive/2006/05/06/44751.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/landy/comments/commentRss/44751.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/landy/services/trackbacks/44751.html</trackback:ping><description><![CDATA[
		<div>
				<blockquote>网上出现了很多讲解AspectJ的资料，但大多是从讲解AspectJ语法开始,本文从另一个角度讲解AspectJ，作者着重介绍了AspectJ的设计思路和运行原理。</blockquote>
				<p>
						<a name="1">
								<span class="atitle">
										<font size="4">1. 序</font>
								</span>
						</a>
				</p>
				<p>Aspect Oriented Programming (AOP)是近来一个比较热门的话题。 </p>
				<p>AspectJ是AOP的Java语言的实现，获得了Java程序员的广泛关注。 </p>
				<p>关于AspectJ和AOP的具体资料，请从下列链接中查找： </p>
				<p>
						<a href="http://www.eclipse.org/aspectj/">
								<font color="#5c81a7">http://www.eclipse.org/aspectj/</font>
						</a>
						<br />
						<a href="http://www.parc.com/research/csl/projects/aspectj/">
								<font color="#5c81a7">http://www.parc.com/research/csl/projects/aspectj/</font>
						</a>
						<br />
						<a href="http://aosd.net/">
								<font color="#5c81a7">http://aosd.net/</font>
						</a>
				</p>
				<p>网上出现了很多讲解AspectJ的资料，但大多是从讲解AspectJ语法开始，然后讲解如何应用AspectJ，如何分离软件开发过程的不同方面（Aspect）--Log，Session，Authentication and Authorization，Transaction，等等。 </p>
				<p>初次接触AspectJ的读者看到这些资料（或者语法手册），会感到AspectJ有些神秘。他们想知道，AspectJ是如何做到这些的？AspectJ是怎样工作的？AspectJ需要特殊的运行环境吗？ </p>
				<p>本文从另一个角度讲解AspectJ，本文从讲解AspectJ的设计思路、运行原理入手，回答上述问题。 </p>
				<p>本文讲解的主要内容，按照概念的重要程度，排列如下： </p>
				<ol>
						<li>AspectJ是一个代码生成工具（Code Generator）。 
</li>
						<li>AspectJ语法就是用来定义代码生成规则的语法。您如果使用过Java Compiler Compiler (JavaCC)，您会发现，两者的代码生成规则的理念惊人相似。 
</li>
						<li>AspectJ有自己的语法编译工具，编译的结果是Java Class文件，运行的时候，classpath需要包含AspectJ的一个jar文件（Runtime lib）。 
</li>
						<li>AspectJ和xDoclet的比较。AspectJ和EJB Descriptor的比较。 </li>
				</ol>
				<p>本文的原则是，只细讲其他资料没有讲到的东西，其他资料讲过的东西，不讲或略讲。以节省网络资源，更为了节省大家宝贵的时间。J </p>
				<br />
				<table cellspacing="0" cellpadding="0" width="100%" border="0">
						<tbody>
								<tr>
										<td>
												<img style="WIDTH: 500px; CURSOR: pointer" onclick="javascript:window.open(this.src);" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" onload="javascript:if(this.width&gt;500)this.style.width=500;" />
										</td>
								</tr>
						</tbody>
				</table>
				<table class="no-print" cellspacing="0" cellpadding="0" align="right">
						<tbody>
								<tr align="right">
										<td>
												<table cellspacing="0" cellpadding="0" border="0">
														<tbody>
																<tr>
																		<td valign="center">
																				<img style="CURSOR: pointer" onclick="javascript:window.open(this.src);" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" onload="javascript:if(this.width&gt;500)this.style.width=500;" border="0" />
																				<br />
																		</td>
																		<td valign="top" align="right">
																				<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/l-aspectJ/#main">
																						<b>
																								<font color="#996699">回页首</font>
																						</b>
																				</a>
																		</td>
																</tr>
														</tbody>
												</table>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<br />
				<p>
						<a name="2">
								<span class="atitle">
										<font size="4">2．Aspect Oriented Programming (AOP)</font>
								</span>
						</a>
				</p>
				<p>本节简单介绍AOP的概念，解释我们为什么需要AOP。 </p>
				<p>AOP是Object Oriented Programming（OOP）的补充。</p>
				<p>OOP能够很好地解决对象的数据和封装的问题，却不能很好的解决Aspect（"方面"）分离的问题。下面举例具体说明。</p>
				<p>比如，我们有一个Bank（银行）类。Bank有两个方法，deposit（存钱）和withdraw（取钱）。 </p>
				<p>类和方法的定义如下： </p>
				<p>
				</p>
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code class="section">
																<font face="Lucida Console">Code 2.1 Bank.java
class Bank{
public float deposit(AccountInfo account, float money){
  // 增加account账户的钱数，返回账户里当前的钱数
}

public float withdraw(AccountInfo account, float money){
  // 减少account账户的钱数，返回取出的钱数
}
};
</font>
														</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>这两个方法涉及到用户的账户资金等重要信息，必须要非常小心，所以编写完上面的商业逻辑之后，项目负责人又提出了新的要求--给Bank类的每个重要方法加上安全认证特性。 </p>
				<p>于是，我们不得不分别在上面的两个方法中加入安全认证的代码。 </p>
				<p>类和方法的定义如下：（新增加的代码用不同的背景标出） </p>
				<p>
				</p>
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code class="section">
																<font face="Lucida Console">Code 2.2 Bank.java
class Bank{
public float deposit(AccountInfo account, float money){
  // 验证account是否为合法用户
  // 增加account账户的钱数，返回账户里当前的钱数
}

public float withdraw(AccountInfo account, float money){
  // 验证account是否为合法用户
  // 减少account账户的钱数，返回取出的钱数
}
};
</font>
														</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>这两个方法都需要操作数据库，为了保持数据完整性，项目负责人又提出了新的要求--给Bank类的每个操作数据库的方法加上事务控制。 </p>
				<p>于是，我们不得不分别在上面的两个方法中加入安全认证的代码。 </p>
				<p>类和方法的定义如下：（新增加的代码用不同的背景标出） </p>
				<p>
				</p>
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code class="section">
																<font face="Lucida Console">Code 2.3 Bank.java
class Bank{
public float deposit(AccountInfo account, float money){
  // 验证account是否为合法用户
  // Begin Transaction
  // 增加account账户的钱数，返回账户里当前的钱数
  // End Transaction
}

public float withdraw(AccountInfo account, float money){
  // 验证account是否为合法用户
  // Begin Transaction
  // 减少account账户的钱数，返回取出的钱数
  // End Transaction
}
};
</font>
														</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>我们看到，这些与商业逻辑无关的重复代码遍布在整个程序中。实际的工程项目中涉及到的类和函数，远远不止两个。如何解决这种问题？ </p>
				<p>我们首先来看看OOP能否解决这个问题。 </p>
				<p>我们利用Design Pattern的Template Pattern，可以抽出一个框架，改变上面的例子的整个设计结构。 </p>
				<p>类和方法的定义如下： </p>
				<p>
				</p>
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code class="section">
																<font face="Lucida Console">Code 2.4 Base.java
abstract class Base{
public float importantMethod(AccountInfo account, float money){
  // 验证account是否为合法用户
  // Begin Transaction
  
  float result = yourBusiness(account, money)

  // End Transaction
  return result;	
}

protected abstract float yourBusiness(AccountInfo account, float money);
};

Code 2.5 BankDeposit.java
class BankDeposit extends Base{ 
protected float yourBusiness(AccountInfo account, float money){
  // 增加account账户的钱数，返回账户里当前的钱数
}
};

Code 2.6 BankWithdraw.java
class BankWithdraw extends Base{ 
protected float yourBusiness(AccountInfo account, float money){
  // 减少account账户的钱数，返回取出的钱数
}
};
</font>
														</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>这里我们用一种很勉强的方法实现了认证和事务代码的重用。而且，有心的读者可能会注意到，这种方法的前提是，强制所有的方法都遵守同样的signature。 </p>
				<p>如果有一个转账方法transfer(AccountInfo giver, AccountInfo receiver, float money)，由于transfer方法的signature不同于yourBusiness的signature，这个方法无法使用上面的框架。 </p>
				<p>这个例子中提到的认证，事务等方面，就是AOP所关心的Aspect。 </p>
				<p>AOP就是为了解决这种问题而出现的。AOP的目的就是--Separation of Aspects (or Separation of Concerns). </p>
				<p>下面的章节，解释EJB Descriptor，AspectJ，xDoclet等工具如何解决Separation of Aspects的问题。 </p>
				<br />
				<table cellspacing="0" cellpadding="0" width="100%" border="0">
						<tbody>
								<tr>
										<td>
												<img style="WIDTH: 500px; CURSOR: pointer" onclick="javascript:window.open(this.src);" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" onload="javascript:if(this.width&gt;500)this.style.width=500;" />
										</td>
								</tr>
						</tbody>
				</table>
				<table class="no-print" cellspacing="0" cellpadding="0" align="right">
						<tbody>
								<tr align="right">
										<td>
												<table cellspacing="0" cellpadding="0" border="0">
														<tbody>
																<tr>
																		<td valign="center">
																				<img style="CURSOR: pointer" onclick="javascript:window.open(this.src);" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" onload="javascript:if(this.width&gt;500)this.style.width=500;" border="0" />
																				<br />
																		</td>
																		<td valign="top" align="right">
																				<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/l-aspectJ/#main">
																						<b>
																								<font color="#996699">回页首</font>
																						</b>
																				</a>
																		</td>
																</tr>
														</tbody>
												</table>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<br />
				<p>
						<a name="3">
								<span class="atitle">
										<font size="4">3．EJB Descriptor</font>
								</span>
						</a>
				</p>
				<p>如果我们使用EJB实现上面的例子，Bank类可以作为一个Stateless Session Bean实现。 </p>
				<p>在Bank的代码中只用考虑商业逻辑，不用考虑认证和事务等方面。 </p>
				<p>认证和事务等方面在EJB Descriptor中定义，由EJB Container提供这些方面的实现。 </p>
				<p>我们来看一下，如何使用EJB Descriptor描述上面的例子。 </p>
				<p>EJB Descriptor包括一个ejb-jar.xml文件。ejb-jar.xml文件包含两大部分，enterprise-beans和assembly-descriptor部分。enterprise-beans部分包含EJB的定义--JNDI Name，EJB Home, Interface, Bean Class Path等；assembly-descriptor部分包括配置信息的定义--安全角色，事务控制等等。 </p>
				<p>下面给出上面例子对应的模拟EJB Descriptor。 </p>
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code class="section">
																<font face="Lucida Console">&lt;ejb-jar&gt;
&lt;enterprise-beans&gt;
  &lt;session&gt;
     &lt;ejb-name&gt;Bank&lt;/ejb-name&gt;
     …
     &lt;ejb-class&gt;example.Bank&lt;/ejb-class&gt;
     &lt;session-type&gt;Stateless&lt;/session-type&gt;
     &lt;transaction-type&gt;Container&lt;/transaction-type&gt;
&lt;security-role-ref&gt;
&lt;role-name&gt;bank-account&lt;/role-name&gt;
&lt;/security-role-ref&gt;
  &lt;/session&gt;
&lt;/enterprise-beans&gt;

&lt;assembly-descriptor&gt;
  &lt;security-role&gt;
    &lt;role-name&gt;bank-account&lt;/role-name&gt;
  &lt;/security-role&gt;

&lt;method-permission&gt;
&lt;role-name&gt;employee&lt;/role-name&gt;
&lt;method&gt;
&lt;ejb-name&gt;Bank&lt;/ejb-name&gt;
&lt;method-name&gt;deposit&lt;/method-name&gt;
&lt;/method&gt;
&lt;method&gt;
&lt;ejb-name&gt;Bank&lt;/ejb-name&gt;
&lt;method-name&gt;withdraw&lt;/method-name&gt;
&lt;/method&gt;
&lt;/method-permission&gt;

&lt;container-transaction&gt;
&lt;method&gt;
&lt;ejb-name&gt;Bank&lt;/ejb-name&gt;
&lt;method-name&gt;deposit&lt;/method-name&gt;
&lt;/method&gt;
&lt;method&gt;
&lt;ejb-name&gt;Bank&lt;/ejb-name&gt;
&lt;method-name&gt;withdraw&lt;/method-name&gt;
&lt;/method&gt;

&lt;trans-attribute&gt;Required&lt;/trans-attribute&gt;
&lt;/container-transaction&gt;
&lt;/assembly-descriptor&gt;
&lt;/ejb-jar&gt;
</font>
														</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>本文后面会讲到如何用AspectJ实现上例中的Separation of Aspects。 </p>
				<p>读者可以比较一下AspectJ语法和EJB Descriptor定义之间的对应关系。 </p>
				<p>两者都提供了类名、方法名的匹配规则，能够把类的方法映射到认证，事务等Aspect（方面）。 </p>
				<br />
				<table cellspacing="0" cellpadding="0" width="100%" border="0">
						<tbody>
								<tr>
										<td>
												<img style="WIDTH: 500px; CURSOR: pointer" onclick="javascript:window.open(this.src);" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" onload="javascript:if(this.width&gt;500)this.style.width=500;" />
										</td>
								</tr>
						</tbody>
				</table>
				<table class="no-print" cellspacing="0" cellpadding="0" align="right">
						<tbody>
								<tr align="right">
										<td>
												<table cellspacing="0" cellpadding="0" border="0">
														<tbody>
																<tr>
																		<td valign="center">
																				<img style="CURSOR: pointer" onclick="javascript:window.open(this.src);" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" onload="javascript:if(this.width&gt;500)this.style.width=500;" border="0" />
																				<br />
																		</td>
																		<td valign="top" align="right">
																				<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/l-aspectJ/#main">
																						<b>
																								<font color="#996699">回页首</font>
																						</b>
																				</a>
																		</td>
																</tr>
														</tbody>
												</table>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<br />
				<p>
						<a name="4">
								<span class="atitle">
										<font size="4">4．AspectJ</font>
								</span>
						</a>
				</p>
				<p>这一节我们来看看AspectJ如何实现上例中的Separation of Aspects。 </p>
				<p>使用AspectJ，我们不用对原有的代码做任何修改，就可以为代码提供不同的Aspect（方面）--比如，认证，事务等。 </p>
				<p>我们只需要提供两个不同的Aspect--认证Aspect和事务Aspect。 </p>
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code class="section">
																<font face="Lucida Console">Code 4.1 AuthAspect.java
aspect AuthAspect{
  pointcut bankMethods() : execution (* Bank.deposit(…)) || execution (* Bank. withdraw (…));

  Object around(): bankMethods(){
  // 验证account是否为合法用户

  return proceed();
  }
};

Code 4.2 TransactionAspect.java
aspect TransactionAspect{
  pointcut bankMethods() : execution(* Bank.deposit(…)) || execution (* Bank. withdraw (…));

  Object around(): bankMethods(){
  // Begin Transaction
  Object result = proceed();
  // End Transaction
  return result;
  }
};
</font>
														</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>如果您暂时不能理解这段代码，没有关系，后面会讲到，这些aspect的定义，不过是定义了一些代码生成规则。 </p>
				<p>我们用AspectJ编译器编译Bank文件和含有aspect的这个文件，出来的结果就是带有安全认证和事务处理的Bank类。编译出来的这个Bank类调用了AspectJ Runtime Lib，所以，如果你要运行这个Bank类，你需要把AspectJ Runtime Lib设置在你的classpath里面。 </p>
				<p>我们来看看，AspectJ编译器为我们做了什么事情。 </p>
				<ol>
						<li>首先，AspectJ从文件列表里取出所有的文件名，然后读取这些文件，进行分析。 
</li>
						<li>AspectJ发现一些文件含有aspect的定义，在这个例子里，就是AuthAspect和TransactionAspect的定义；这些aspect就是代码生成规则。 
</li>
						<li>AspectJ根据这些aspect代码生成规则，修改添加你的源代码。在这个例子里，就是修改添加Bank文件。 
</li>
						<li>AspectJ读取AuthAspect的定义，发现了一个pointcut--bankMethods()；这个pointcut的定义是execution(* Bank.deposit(…)) || execution(* Bank. withdraw (…))，表示所有对Bank类的deposit和withdraw方法的执行点。 
</li>
						<li>AspectJ继续读取AuthAspect的定义，发现了一个around()，这在AspectJ中叫做Advice，我不明白为什么叫这个名字，不过没关系，我们只要知道它是干什么的就行了。Advice允许你在某个类的方法的调用之前或调用之后，加入另外的代码。Code 4.1所示代码中的around()的" // 验证account是否为合法用户"部分，就是要加入的代码。这段代码要加在哪里呢？around()后面跟了一个pointcut--bankMethods()。根据这个pointcut，AspectJ会把这段代码加入到Bank.deposit和Bank.withdraw两个方法的执行之前。达到的效果就如同Code 2.2所示。 
</li>
						<li>AspectJ读取TransactionAspect的定义，象第（4）步一样，发现了发现了一个pointcut--bankMethods()。 
</li>
						<li>AspectJ继续读取AuthAspect的定义，发现了一个around()。这次AspectJ把"Begin Transaction"和"End Transaction"两段代码加在Bank.deposit和Bank. withdraw两个方法的执行前后。达到的效果就如同Code 2.3所示。 </li>
				</ol>
				<p>如何验证这一点？您可以到 <a href="http://www.eclipse.org/aspectj/"><font color="#5c81a7">http://www.eclipse.org/aspectj/</font></a>下载安装AspectJ，编译里面的Sample，把编译结果反编译一下，就可以看到AspetJ自动生成的代码。 </p>
				<p>我们看到，AspectJ是一种代码自动生成工具。你编写一段通用的代码，比如认证方面的代码，事务方面的代码，然后根据AspectJ语法定义一套代码生成规则（aspect定义），AspectJ就会帮助你自动把这段通用代码分布到对应的代码里面去，简单快捷，算无遗策。 </p>
				<p>无独有偶，一个著名的编译器生成工具--Java Compiler Compiler (JavaCC)，也采用了非常相似的代码生成机制。JavaCC允许你在语法定义规则文件中，加入你自己的Java代码，用来处理读入的各种语法元素。 </p>
				<p>AspectJ令你的代码更精简，结构更良好。AspectJ的好处，我就不多说了，网上很多精彩的文章探讨AspectJ的各种用途。 </p>
				<p>下面介绍一个著名的代码自动生成器--xDoclet，和EJB Descriptor，AspectJ之间的联系和比较。 </p>
				<br />
				<table cellspacing="0" cellpadding="0" width="100%" border="0">
						<tbody>
								<tr>
										<td>
												<img style="WIDTH: 500px; CURSOR: pointer" onclick="javascript:window.open(this.src);" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" onload="javascript:if(this.width&gt;500)this.style.width=500;" />
										</td>
								</tr>
						</tbody>
				</table>
				<table class="no-print" cellspacing="0" cellpadding="0" align="right">
						<tbody>
								<tr align="right">
										<td>
												<table cellspacing="0" cellpadding="0" border="0">
														<tbody>
																<tr>
																		<td valign="center">
																				<img style="CURSOR: pointer" onclick="javascript:window.open(this.src);" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" onload="javascript:if(this.width&gt;500)this.style.width=500;" border="0" />
																				<br />
																		</td>
																		<td valign="top" align="right">
																				<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/l-aspectJ/#main">
																						<b>
																								<font color="#996699">回页首</font>
																						</b>
																				</a>
																		</td>
																</tr>
														</tbody>
												</table>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<br />
				<p>
						<a name="5">
								<span class="atitle">
										<font size="4">5．xDoclet</font>
								</span>
						</a>
				</p>
				<p>我们知道，Doclet用来生成Javadoc，xDoclet是Doclet的扩展，不仅仅能生成Javadoc，还能够生成源代码和配置信息等。 </p>
				<p>Doclet和xDoclet的工作原理，就是处理源代码中的注释中的tag，生成相应的信息。这些tag都以@开头，你可以自己定义tag和对tag的处理，生成自定义的信息。 </p>
				<p>（这里提一下Apache Maven Project。Maven是一种Project Build工具。用Maven进行管理的项目，能够同时生成Javadoc和XRef。XRef是Source Code Cross Reference。) </p>
				<p>JBoss就利用xDoclet为EJB自动生成EJB Home和EJB Object Interface源文件，和EJB Descriptor文件。 </p>
				<p>在Sourceforge.net上看到一个叫做Barter的开源项目，利用xDoclet为类方法生成AspectJ代码。 </p>
				<p>请注意，EJB Descriptor和AspectJ都是把方方面面的Aspects集中在一处进行管理，而xDoclet的思想是处理散布在源代码中的各种tag。 </p>
				<p>xDoclet在生成EJB Descriptor和AspectJ等方面的应用，正应了中国的一句古话--分久必合，合久必分。 </p>
				<br />
				<table cellspacing="0" cellpadding="0" width="100%" border="0">
						<tbody>
								<tr>
										<td>
												<img style="WIDTH: 500px; CURSOR: pointer" onclick="javascript:window.open(this.src);" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" onload="javascript:if(this.width&gt;500)this.style.width=500;" />
										</td>
								</tr>
						</tbody>
				</table>
				<table class="no-print" cellspacing="0" cellpadding="0" align="right">
						<tbody>
								<tr align="right">
										<td>
												<table cellspacing="0" cellpadding="0" border="0">
														<tbody>
																<tr>
																		<td valign="center">
																				<img style="CURSOR: pointer" onclick="javascript:window.open(this.src);" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" onload="javascript:if(this.width&gt;500)this.style.width=500;" border="0" />
																				<br />
																		</td>
																		<td valign="top" align="right">
																				<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/l-aspectJ/#main">
																						<b>
																								<font color="#996699">回页首</font>
																						</b>
																				</a>
																		</td>
																</tr>
														</tbody>
												</table>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<br />
				<p>
						<a name="6">
								<span class="atitle">
										<font size="4">6．总结</font>
								</span>
						</a>
				</p>
				<p>开源项目的出现，打破了软件技术领域的众多壁垒，推动软件技术进程的日新月异。 </p>
				<p>同时，一些新名词，新概念也层出不穷，令人眼花缭乱，无所适从。其实，很多东西都是换汤不换药，我们理解应用这些新技术的时候，要抓住本质，要破除迷信，破除任何人为的神秘感。 </p>
				<p>举个例子，现在炒作的很热的一些概念，"Web Service"，还有"Grid Computation"（网格计算），都是基于原有的各种技术发展出来的。媒体和技术文章不应该人为地制造任何神秘感。 </p>
				<p>互联网时代的权威，不是说出来的，而是做出来的。 </p>
				<p>另外，围绕着一些有前途的新技术，总会出现大量的"快速入门手册"，有些简直就是对该技术帮助文档的翻译，而且，有难度的地方没有翻译出来，大家都明白的地方翻译得非常详尽，详尽到了没有必要的地步。这种因为市场需求而产生的应景时文，大量地出现在技术文章领域。 </p>
				<p>笔者对本文的期望是，决不迷信，决不重复。并试图引入一种洁净的，毫无废话的文风。笔者期待一针见血的驳斥和批评。 </p>
		</div>
<img src ="http://www.blogjava.net/landy/aggbug/44751.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/landy/" target="_blank">独孤过客</a> 2006-05-06 15:56 <a href="http://www.blogjava.net/landy/archive/2006/05/06/44751.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ethereal抓包实时分析可行性研究</title><link>http://www.blogjava.net/landy/archive/2006/05/06/44750.html</link><dc:creator>独孤过客</dc:creator><author>独孤过客</author><pubDate>Sat, 06 May 2006 07:55:00 GMT</pubDate><guid>http://www.blogjava.net/landy/archive/2006/05/06/44750.html</guid><wfw:comment>http://www.blogjava.net/landy/comments/44750.html</wfw:comment><comments>http://www.blogjava.net/landy/archive/2006/05/06/44750.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/landy/comments/commentRss/44750.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/landy/services/trackbacks/44750.html</trackback:ping><description><![CDATA[
		<div id="art" style="MARGIN: 15px" width="100%">
				<div>Ethereal是一个功能强大的抓包工具，它提供的GUI工具能将经过网卡的信令捕获并实时显示，但是在实际应用中，我们还可能要对捕获的日志进行分析，以获得自己关心的信令的统计结果，但是这样就面临着以下几个问题： <br />1. 当Ethereal自身提供的简单统计功能不能满足需求时，我们该怎么办？ <br />2. Ethereal的GUI工具生成的日志是它专有的libpcap格式，不适合人类阅读，我们该怎么分析它？ <br />本文针对上述问题提供了一整套的解决方案。 <br /><br />一. 用Ethereal实时捕获信令。 <br /><br />Ethereal提供了从命令行定制启动的方案。我们可以利用这个特点将capture file输出到指定的目录，这个capture file将被Ethereal实时更新。 <br />下面是我写的一个windows bat文件，用该文件能做到最简单地启动Ethereal截包，不用用户学习怎样配置Ethereal。 <br /><br />………………………………………………………………………………………………………… <br />rem @echo off <br />set ETHEREAL_HOME="D:\Program Files\Ethereal\ethereal.exe" <br />set NETWORK_CARD="\Device\NPF_{D239E06D-D86E-4CFC-A360-0D74CDD21CAE}" <br />set ETHEREAL_OPT=-i %NETWORK_CARD% <br />set ETHEREAL_OPT=%ETHEREAL_OPT% -klSQ <br />set FILTER_STR="port 6000 or port 6001 or port 6002 or port 6003 or port 6004 or port 6005 or port 6006 or port 6007 or port 6008" <br />rem set ETHEREAL_OPT=%ETHEREAL_OPT% -f %FILTER_STR% <br />set ETHEREAL_OPT=%ETHEREAL_OPT% -o capture.real_time_update:TRUE -o capture.auto_scroll:TRUE -o capture.show_info:FALSE -o print.format:text -o print.destination:file -o print.file:ethereal.out <br />rem -a filesize:1000 files:5 -b filesize:1000 files:5 <br />call %ETHEREAL_HOME% %ETHEREAL_OPT% -w c:\ethereal.out <br />………………………………………………………………………………………………………… <br />将上面这段script存为bat文件后，设置好ETHEREAL_HOME和网卡即可启动Ethereal截包。 <br /><br />二. 实时分析Ethereal的中间人实现。 <br /><br />“计算机科学中的所有问题都能通过中间人的方式解决。”这是精通EJB中强调了很多次的名言。 <br />在上节所示的脚本中我们将Ethereal的存放日志的文件放在了“c:\ethereal.out”目录下，这个文件能被Ethereal实时更新，但是它的内容却是不可读的，我们可用Ethereal提供的Tethereal工具将此文件转换为适合人类阅读的文本。但是这个工具仅能将标准的capture file解析成可读文本并在标准输出设备显示（一般为显示器），没有找到将其另存为文本的方法，我们也不需要此方法。可以用java.lang.Runtime.exec()方法执行“tethereal -r infile.cap -V”，获得这个进程的对象后我们可以得到这个进程对象的输出流对象，接下来我们可以从这个输出流中读出结果进行分析。 <br /><br />三. 得到实时的统计结果 <br />可以对从输出流中得到的可读结果进行分析，获得自己想要的统计结果。我们可以用一个线程以一定的时间间隔刷新此输出流，已达到用户认为的实时分析的效果。 <br /><br />参考： <br />http://www.ethereal.com <br />java doc <br /></div>
				<div> </div>
				<div> </div>
				<div>
						<span id="c_3467">
								<p>后来想到的更好的方案:</p>
								<p>这种方式有一个显著的缺点，如果用户截包时间的变长，ethereal保存log的文件越来越大，将导致每次刷新输出流越来越耗资源，最后将导致工具无法使用。</p>
								<p>新的解决方案就是用ethereal的命令行版本，tethereal就可以完美避免类似问题。</p>
								<p>用java的runtime.exec()调用此脚本：</p>
								<p>－－－－－－－－－－－－－－－－－－－</p>
								<p>set TETHEREAL_HOME="D:\Program Files\Ethereal\tethereal.exe"<br />rem call cmd /k %TETHEREAL_HOME% -r c:\ethereal.out -R tcp -T text -V<br />call cmd /k %TETHEREAL_HOME% -r c:\ethereal.out -T text -V</p>
								<p>－－－－－－－－－－－－－－－－</p>
								<p>ethereal每截到一个数据包，便会将次包送给输出流。这样就能真正做到实时分析了。</p>
						</span>
				</div>
		</div>
<img src ="http://www.blogjava.net/landy/aggbug/44750.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/landy/" target="_blank">独孤过客</a> 2006-05-06 15:55 <a href="http://www.blogjava.net/landy/archive/2006/05/06/44750.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>防止任意形式的重复提交</title><link>http://www.blogjava.net/landy/archive/2006/05/06/44749.html</link><dc:creator>独孤过客</dc:creator><author>独孤过客</author><pubDate>Sat, 06 May 2006 07:54:00 GMT</pubDate><guid>http://www.blogjava.net/landy/archive/2006/05/06/44749.html</guid><wfw:comment>http://www.blogjava.net/landy/comments/44749.html</wfw:comment><comments>http://www.blogjava.net/landy/archive/2006/05/06/44749.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.blogjava.net/landy/comments/commentRss/44749.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/landy/services/trackbacks/44749.html</trackback:ping><description><![CDATA[
		<div>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
						<font size="3">
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">Struts</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">Token</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">机制可以解决这个问题。</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /?>
										<o:p>
										</o:p>
								</span>
						</font>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 18.0pt">
						<span lang="EN-US" style="mso-bidi-font-size: 10.5pt; mso-fareast-font-family: 'Times New Roman'">
								<span style="mso-list: Ignore">
										<font face="Times New Roman">
												<font size="3">1．</font>
												<span style="FONT: 7pt 'Times New Roman'">  </span>
										</font>
								</span>
						</span>
						<font size="3">
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">防止通过超链接重复访问</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">Struts Action</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<o:p>
										</o:p>
								</span>
						</font>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt">
						<font size="3">
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如果我们要防止</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">A</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的默认页面</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">J</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">中指向</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">K</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的超链接重复提交数据，按照下列步骤即可：</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<o:p>
										</o:p>
								</span>
						</font>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l0 level2 lfo1; tab-stops: list 39.0pt">
						<span lang="EN-US" style="mso-bidi-font-size: 10.5pt; mso-fareast-font-family: 'Times New Roman'">
								<span style="mso-list: Ignore">
										<font face="Times New Roman">
												<font size="3">a．</font>
												<span style="FONT: 7pt 'Times New Roman'">  </span>
										</font>
								</span>
						</span>
						<font size="3">
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如果</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">J</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是从</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">Struts Action</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">转发而来，我们要在该</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">Struts Action</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">execute</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法中添加下面的一行：</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<o:p>
										</o:p>
								</span>
						</font>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt">
						<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
								<font size="3">
										<font face="Times New Roman">
												<span style="mso-spacerun: yes">    </span>
												<span style="COLOR: blue">saveToken(request);<o:p></o:p></span>
										</font>
								</font>
						</span>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l0 level2 lfo1; tab-stops: list 39.0pt">
						<span lang="EN-US" style="mso-bidi-font-size: 10.5pt; mso-fareast-font-family: 'Times New Roman'">
								<span style="mso-list: Ignore">
										<font face="Times New Roman">
												<font size="3">b．</font>
												<span style="FONT: 7pt 'Times New Roman'">  </span>
										</font>
								</span>
						</span>
						<font size="3">
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如果</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">J</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">不是从</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">Struts Action</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">转发而来，那么新建一个</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">Struts Action</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，在该</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">Struts Action</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">excute</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法中增加上面的一行，然后再从该</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">action</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">转到</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">J</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">页面。</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<o:p>
										</o:p>
								</span>
						</font>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l0 level2 lfo1; tab-stops: list 39.0pt">
						<span lang="EN-US" style="mso-bidi-font-size: 10.5pt; mso-fareast-font-family: 'Times New Roman'">
								<span style="mso-list: Ignore">
										<font face="Times New Roman">
												<font size="3">c．</font>
												<span style="FONT: 7pt 'Times New Roman'">  </span>
										</font>
								</span>
						</span>
						<font size="3">
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">J</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">页面中使用</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">Struts</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">标签生成指向</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">K</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的超链接，如：</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<o:p>
										</o:p>
								</span>
						</font>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt">
						<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
								<span style="mso-spacerun: yes">
										<font face="Times New Roman" size="3">   </font>
								</span>
						</span>
						<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">&lt;html:link action="/deleteLayoutAction?layoutId=0" </span>
						<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: red; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">transaction="true"</span>
						<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">&gt;delete&lt;/html:link&gt;<o:p></o:p></span>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt">
						<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">
								<span style="mso-spacerun: yes">   </span>
						</span>
						<span style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Courier New'; mso-hansi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-bidi-font-family: 'Courier New'">注意红色字体部分。</span>
						<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-font-kerning: 0pt">
								<o:p>
								</o:p>
						</span>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l0 level2 lfo1; tab-stops: list 39.0pt">
						<span lang="EN-US" style="mso-bidi-font-size: 10.5pt; mso-fareast-font-family: 'Times New Roman'">
								<span style="mso-list: Ignore">
										<font face="Times New Roman">
												<font size="3">d．</font>
												<span style="FONT: 7pt 'Times New Roman'">  </span>
										</font>
								</span>
						</span>
						<font size="3">
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">&lt;html:link&gt;</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">标签指向的</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">action</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">excute</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法中加入下面的代码：</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<o:p>
										</o:p>
								</span>
						</font>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt">
						<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
								<font face="Times New Roman">
										<font size="3">
												<span style="mso-spacerun: yes">   </span>
												<span style="COLOR: blue">if (!isTokenValid(request)) {<o:p></o:p></span>
										</font>
								</font>
						</span>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt">
						<font size="3">
								<span lang="EN-US" style="COLOR: blue; mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">
												<span style="mso-tab-count: 3">                     </span>return mapping.findForward("</font>
								</span>
								<span style="COLOR: blue; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">这种情况下就是重复提交，转到相应的页面</span>
								<span lang="EN-US" style="COLOR: blue; mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">");<o:p></o:p></font>
								</span>
						</font>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt">
						<span lang="EN-US" style="COLOR: blue; mso-bidi-font-size: 10.5pt">
								<font face="Times New Roman">
										<font size="3">
												<span style="mso-tab-count: 2">              </span>}<o:p></o:p></font>
								</font>
						</span>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt">
						<font size="3">
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">e</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">．</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">All Done.<o:p></o:p></font>
								</span>
						</font>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 18.0pt">
						<span lang="EN-US" style="mso-bidi-font-size: 10.5pt; mso-fareast-font-family: 'Times New Roman'">
								<span style="mso-list: Ignore">
										<font face="Times New Roman">
												<font size="3">2．</font>
												<span style="FONT: 7pt 'Times New Roman'">  </span>
										</font>
								</span>
						</span>
						<font size="3">
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">防止通过表单重复提交数据。</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<o:p>
										</o:p>
								</span>
						</font>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l0 level2 lfo1; tab-stops: list 39.0pt">
						<span lang="EN-US" style="mso-bidi-font-size: 10.5pt; mso-fareast-font-family: 'Times New Roman'">
								<span style="mso-list: Ignore">
										<font face="Times New Roman">
												<font size="3">a．</font>
												<span style="FONT: 7pt 'Times New Roman'">  </span>
										</font>
								</span>
						</span>
						<font size="3">
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如果</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">J</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是从</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">Struts Action</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">转发而来，我们要在该</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">Struts Action</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">execute</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法中添加下面的一行：</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<o:p>
										</o:p>
								</span>
						</font>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt">
						<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
								<font size="3">
										<font face="Times New Roman">
												<span style="mso-spacerun: yes">    </span>
												<span style="COLOR: blue">saveToken(request);<o:p></o:p></span>
										</font>
								</font>
						</span>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l0 level2 lfo1; tab-stops: list 39.0pt">
						<span lang="EN-US" style="mso-bidi-font-size: 10.5pt; mso-fareast-font-family: 'Times New Roman'">
								<span style="mso-list: Ignore">
										<font face="Times New Roman">
												<font size="3">b．</font>
												<span style="FONT: 7pt 'Times New Roman'">  </span>
										</font>
								</span>
						</span>
						<font size="3">
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如果</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">J</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">不是从</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">Struts Action</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">转发而来，那么新建一个</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">Struts Action</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，在该</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">Struts Action</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">excute</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法中增加上面的一行，然后再从该</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">action</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">转到</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">J</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">页面。</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<o:p>
										</o:p>
								</span>
						</font>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l0 level2 lfo1; tab-stops: list 39.0pt">
						<span lang="EN-US" style="mso-bidi-font-size: 10.5pt; mso-fareast-font-family: 'Times New Roman'">
								<span style="mso-list: Ignore">
										<font face="Times New Roman">
												<font size="3">c．</font>
												<span style="FONT: 7pt 'Times New Roman'">  </span>
										</font>
								</span>
						</span>
						<font size="3">
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">J</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">页面中表单</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">Action</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">属性指向的</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">Struts action</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">excute</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法中加入下面的代码：</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<o:p>
										</o:p>
								</span>
						</font>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt">
						<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
								<font face="Times New Roman">
										<font size="3">
												<span style="mso-spacerun: yes">   </span>
												<span style="COLOR: blue">if (!isTokenValid(request)) {<o:p></o:p></span>
										</font>
								</font>
						</span>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt">
						<span lang="EN-US" style="COLOR: blue; mso-bidi-font-size: 10.5pt">
								<font face="Times New Roman">
										<font size="3">
												<span style="mso-spacerun: yes">           </span>saveToken(request);<o:p></o:p></font>
								</font>
						</span>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt">
						<font size="3">
								<span lang="EN-US" style="COLOR: blue; mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">
												<span style="mso-tab-count: 3">                     </span>return mapping.findForward("</font>
								</span>
								<span style="COLOR: blue; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">这种情况下就是重复提交，转到相应的页面</span>
								<span lang="EN-US" style="COLOR: blue; mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">");<o:p></o:p></font>
								</span>
						</font>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt">
						<span lang="EN-US" style="COLOR: blue; mso-bidi-font-size: 10.5pt">
								<font face="Times New Roman">
										<font size="3">
												<span style="mso-spacerun: yes">   </span>saveToken(request);<o:p></o:p></font>
								</font>
						</span>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt">
						<span lang="EN-US" style="COLOR: blue; mso-bidi-font-size: 10.5pt">
								<font face="Times New Roman">
										<font size="3">
												<span style="mso-tab-count: 2">              </span>}<o:p></o:p></font>
								</font>
						</span>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt">
						<font size="3">
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">e</font>
								</span>
								<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">．</span>
								<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
										<font face="Times New Roman">All Done.<o:p></o:p></font>
								</span>
						</font>
				</p>
		</div>
<img src ="http://www.blogjava.net/landy/aggbug/44749.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/landy/" target="_blank">独孤过客</a> 2006-05-06 15:54 <a href="http://www.blogjava.net/landy/archive/2006/05/06/44749.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Integrated cas with liferay</title><link>http://www.blogjava.net/landy/archive/2006/05/06/44748.html</link><dc:creator>独孤过客</dc:creator><author>独孤过客</author><pubDate>Sat, 06 May 2006 07:53:00 GMT</pubDate><guid>http://www.blogjava.net/landy/archive/2006/05/06/44748.html</guid><wfw:comment>http://www.blogjava.net/landy/comments/44748.html</wfw:comment><comments>http://www.blogjava.net/landy/archive/2006/05/06/44748.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/landy/comments/commentRss/44748.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/landy/services/trackbacks/44748.html</trackback:ping><description><![CDATA[
		<div id="art" style="MARGIN: 15px" width="100%">
				<div>借花献佛：</div>
				<div>We found some way that somehow, solves the liferay integration with cas. The solution is this when you login in to liferay just in the try to call the login page of cas manually<br /><br />1) Change the view.jsp page. make the form method to get<br />2) change touch_protected.jsp. Add<br />&lt;% String query=request.getQueryString();%&gt; <br /><br />3) change touch_protected.jsp again. Add<br />&lt;body onLoad=”self.location=’&lt;%= CTX_PATH%&gt;/portal/protected?&lt;%=query%&gt;$mode=portal’;”&gt; <br />We will use this mode later on CAS login page<br /><br />3) Change top_bar.jsp and add<br /><br />&lt;c:if test="&lt;%= signedIn %&gt;"&gt;<br />&lt;a href="&lt;%= Http.getProtocol(request) %&gt;://&lt;%= request.getServerName() %&gt;:&lt;%=request.getServerPort()%&gt;/html/common/logout2.jsp" class="bg" &gt;&lt;bean:message key="sign-out" /&gt;&lt;/a&gt;<br /><br />&lt;/c:if&gt;<br /><br />4) Change web.xml and add:<br />&lt;filter&gt;<br />&lt;filter-name&gt;CAS Filter&lt;/filter-name&gt;<br />&lt;filter-class&gt;edu.yale.its.tp.cas.client.filter.CASFilter&lt;/filter-class&gt;<br />&lt;init-param&gt;<br />&lt;param-name&gt;edu.yale.its.tp.cas.client.filter.loginUrl&lt;/param-name&gt;<br />&lt;param-value&gt;https://casserver:8443/cas/login&lt;/param-value&gt;<br />&lt;/init-param&gt;<br />&lt;init-param&gt;<br />&lt;param-name&gt;edu.yale.its.tp.cas.client.filter.validateUrl&lt;/param-name&gt;<br />&lt;param-value&gt;https://casserver:8443/cas/proxyValidate&lt;/param-value&gt;<br />&lt;/init-param&gt;<br />&lt;init-param&gt;<br />&lt;param-name&gt;edu.yale.its.tp.cas.client.filter.logout&lt;/param-name&gt;<br />&lt;param-value&gt;https://casserver:8443/cas/logout&lt;/param-value&gt;<br />&lt;/init-param&gt;<br />&lt;init-param&gt;<br />&lt;param-name&gt;edu.yale.its.tp.cas.client.filter.serverName&lt;/param-name&gt;<br />&lt;param-value&gt;casserver&lt;/param-value&gt;<br />&lt;/init-param&gt;<br />&lt;/filter&gt;<br /><br />&lt;filter-mapping&gt;<br />&lt;filter-name&gt;CAS Filter&lt;/filter-name&gt;<br />&lt;url-pattern&gt;/c/portal/protected/*&lt;/url-pattern&gt;<br />&lt;/filter-mapping&gt;<br /><br />6) We should define a logout2.jsp which calls the cas logout url not liferay logout.<br /><br />NOW WE SHOULD GO TO CAS-SERVER. We should use the mode paramater here to do some tricks. Remmeber there are other applications that want to use the normal login page, only we(liferay users) need to make a hidden view of this page.<br /><br />5) change the the login.jsp and header.jsp. You must configure the CAS login page to view itself in while it login page is loaded in liferay. just add this on the header.jsp<br />String mode="standard";<br />String username=""; <br />String password="";<br />String url = request.getParameter("service");<br />if (!url.equals(null)){<br />int pos=url.lastIndexOf('?');<br />int pos1=url.indexOf("mode=portal",pos);<br />if (pos1!=-1)<br />{<br />mode="portal"; <br />}<br /><br />now use the mode parameter to create a login form which all hidden filed<br /><br />&lt;%<br />if (mode.equals("portal"))<br />{<br />%&gt;<br />&lt;script language="JavaScript"&gt;<br />function submitForm() {<br />document.login_form.username.value ="&lt;%=username%&gt;";<br />document.login_form.password.value ="&lt;%=password%&gt;";<br />document.login_form.submit();<br />}<br />&lt;/script&gt;<br /><br />&lt;body onLoad="submitForm()" &gt;<br />&lt;form method="post" name="login_form"&gt;<br />&lt;input type="hidden" name="username" maxlength="20" size="12" dir="ltr"&gt;<br />&lt;input type="hidden" name="password" maxlength="20" size="14" dir="ltr"&gt;<br />&lt;input type="hidden" name="lt" value="&lt;%= request.getAttribute("edu.yale.its.tp.cas.lt") %&gt;" /&gt;<br />&lt;/form&gt;<br /><br />&lt;%<br />}<br />else{<br />//rest of the page<br /></div>
		</div>
<img src ="http://www.blogjava.net/landy/aggbug/44748.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/landy/" target="_blank">独孤过客</a> 2006-05-06 15:53 <a href="http://www.blogjava.net/landy/archive/2006/05/06/44748.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>