﻿<?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 EE</title><link>http://www.blogjava.net/yifeng/category/34013.html</link><description>光是知道是不够的，必须要加以应用；光是希望是不够的，非去做不可。</description><language>zh-cn</language><lastBuildDate>Tue, 15 Sep 2009 18:23:06 GMT</lastBuildDate><pubDate>Tue, 15 Sep 2009 18:23:06 GMT</pubDate><ttl>60</ttl><item><title>M800 International Toll Free 4001 Launched Successfully</title><link>http://www.blogjava.net/yifeng/archive/2009/09/16/291806.html</link><dc:creator>忆风</dc:creator><author>忆风</author><pubDate>Tue, 15 Sep 2009 17:17:00 GMT</pubDate><guid>http://www.blogjava.net/yifeng/archive/2009/09/16/291806.html</guid><wfw:comment>http://www.blogjava.net/yifeng/comments/291806.html</wfw:comment><comments>http://www.blogjava.net/yifeng/archive/2009/09/16/291806.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yifeng/comments/commentRss/291806.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yifeng/services/trackbacks/291806.html</trackback:ping><description><![CDATA[<img src="http://www.blogjava.net/images/blogjava_net/yifeng/I400/2009-8-1914-05-43.png" border="0" alt="" />
<div><img src="http://www.blogjava.net/images/blogjava_net/yifeng/I400/2009-8-1914-09-47.png" border="0" alt="" /><br />
</div>
<div><img src="http://www.blogjava.net/images/blogjava_net/yifeng/I400/2009-8-1914-10-22.png" border="0" alt="" /><br />
</div>
<div><img src="http://www.blogjava.net/images/blogjava_net/yifeng/I400/2009-8-1914-11-44.png" border="0" alt="" /><br />
</div>
<div><img src="http://www.blogjava.net/images/blogjava_net/yifeng/I400/2009-8-1914-12-19.png" border="0" alt="" /><br />
</div>
<div><img src="http://www.blogjava.net/images/blogjava_net/yifeng/I400/2009-8-1914-13-35.png" border="0" alt="" /><br />
</div>
<div><img src="http://www.blogjava.net/images/blogjava_net/yifeng/I400/2009-8-1914-15-58.png" border="0" alt="" /><br />
</div>
<div><img src="http://www.blogjava.net/images/blogjava_net/yifeng/I400/2009-8-1917-36-06.png" border="0" alt="" /><br />
</div>
<div><img src="http://www.blogjava.net/images/blogjava_net/yifeng/I400/2009-8-1914-30-49.png" border="0" alt="" /><br />
</div>
<div><img src="http://www.blogjava.net/images/blogjava_net/yifeng/I400/2009-8-1914-31-27.png" border="0" alt="" /><br />
</div>
<img src ="http://www.blogjava.net/yifeng/aggbug/291806.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yifeng/" target="_blank">忆风</a> 2009-09-16 01:17 <a href="http://www.blogjava.net/yifeng/archive/2009/09/16/291806.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>RBAC模型（转载）</title><link>http://www.blogjava.net/yifeng/archive/2009/08/18/291655.html</link><dc:creator>忆风</dc:creator><author>忆风</author><pubDate>Tue, 18 Aug 2009 09:18:00 GMT</pubDate><guid>http://www.blogjava.net/yifeng/archive/2009/08/18/291655.html</guid><wfw:comment>http://www.blogjava.net/yifeng/comments/291655.html</wfw:comment><comments>http://www.blogjava.net/yifeng/archive/2009/08/18/291655.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yifeng/comments/commentRss/291655.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yifeng/services/trackbacks/291655.html</trackback:ping><description><![CDATA[<span  style="font-family: 'times new roman'; ">
<p style="color: #000000; ">访问控制策略一般有以下几种方式：</p>
<div class="itemizedlist" style="padding-top: 0px; padding-bottom: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">
<ul type="disc" style="color: #000000; padding-top: 0px; padding-bottom: 0px; margin-top: auto; margin-right: auto; margin-bottom: auto; margin-left: auto; ">
    <li style="color: #000000; ">
    <p style="color: #000000; ">自主型访问控制（Discretionary Access Control-DAC）：用户/对象来决定访问权限。信息的所有者来设定谁有权限来访问信息以及操作类型（读、写、执行。。。）。是一种基于身份的访问控制。例如UNIX权限管理。</p>
    </li>
    <li style="color: #000000; ">
    <p style="color: #000000; ">强制性访问控制（Mandatory Access Control-MAC）：系统来决定访问权限。安全属性是强制型的规定，它由安全管理员或操作系统根据限定的规则确定的，是一种规则的访问控制。</p>
    </li>
    <li style="color: #000000; ">
    <p style="color: #000000; ">基于角色的访问控制（格/角色/任务）：角色决定访问权限。用组织角色来同意或拒绝访问。比MAC、DAC更灵活，适合作为大多数公司的安全策略，但对一些机密性高的政府系统部适用。</p>
    </li>
    <li style="color: #000000; ">
    <p style="color: #000000; ">规则驱动的基于角色的访问控制：提供了一种基于约束的访问控制，用一种灵活的规则描述语言和一种ixn的信任规则执行机制来实现。</p>
    </li>
    <li style="color: #000000; ">
    <p style="color: #000000; ">基于属性证书的访问控制：访问权限信息存放在用户属性证书的权限属性中，每个权限属性描述了一个或多个用户的访问权限。但用户对某一资源提出访问请求时，系统根据用户的属性证书中的权限来判断是否允许或句句</p>
    </li>
</ul>
</div>
<p style="color: #000000; ">模型的主要元素</p>
<div class="itemizedlist" style="padding-top: 0px; padding-bottom: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">
<ul type="disc" style="color: #000000; padding-top: 0px; padding-bottom: 0px; margin-top: auto; margin-right: auto; margin-bottom: auto; margin-left: auto; ">
    <li style="color: #000000; ">
    <p style="color: #000000; ">可视化授权策略生成器</p>
    </li>
    <li style="color: #000000; ">
    <p style="color: #000000; ">授权语言控制台</p>
    </li>
    <li style="color: #000000; ">
    <p style="color: #000000; ">用户、组、角色管理模块</p>
    </li>
    <li style="color: #000000; ">
    <p style="color: #000000; ">API接口</p>
    </li>
    <li style="color: #000000; ">
    <p style="color: #000000; ">授权决策引擎</p>
    </li>
    <li style="color: #000000; ">
    <p style="color: #000000; ">授权语言解释器</p>
    </li>
</ul>
</div>
<div class="sect1" lang="zh-cn">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="color: #000000; font-weight: 500; margin-top: 10px; padding-top: 15px; font-size: 22px; clear: both; "><a name="d0e4641" style="color: #003399; width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>H.1.&nbsp;RBAC模型介绍</h2>
</div>
</div>
</div>
<p style="color: #000000; ">RBAC(Role-Based Access Control - 基于角色的访问控制)模型是20世纪90年代研究出来的一种新模型，但从本质上讲，这种模型是对前面描述的访问矩阵模型的扩展。这种模型的基本概念是把许可权（Permission）与角色（Role）联系在一起，用户通过充当合适角色的成员而获得该角色的许可权。</p>
<p style="color: #000000; ">这种思想世纪上早在20世纪70年代的多用户计算时期就被提出来了，但直到20世纪90年代中后期，RBAC才在研究团体中得到一些重视。本章将重点介绍美国George Mason大学的RBAC96模型。</p>
</div>
<div class="sect1" lang="zh-cn">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="color: #000000; font-weight: 500; margin-top: 10px; padding-top: 15px; font-size: 22px; clear: both; "><a name="d0e4648" style="color: #003399; width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>H.2.&nbsp;有关概念</h2>
</div>
</div>
</div>
<p style="color: #000000; ">在实际的组织中，为了完成组织的业务工作，需要在组织内部设置不同的职位，职位既表示一种业务分工，又表示一种责任与权利。根据业务分工的需要，支援被划分为不同群体，各个群体的人根据其工作任务的需要被赋予不同的职责和权利，每个人有权了解与使用与自己任务相关的信息与资源，对于那些不应该被知道的信息则应该限制他们访问。这就产生了访问控制的需求。</p>
<p style="color: #000000; ">例如，在一个大学中，有校长、副校长、训练部长、组织处长、科研处长、教保处长等不同的职位，在通常情况下，职位所赋予的权利是不变的，但在某个职位上工作的人可以根据需要调整。RBAC模型对组织内部的这些关系与访问控制要求给出了非常恰当的描述。</p>
<div class="sect2" lang="zh-cn">
<div class="titlepage">
<div>
<div>
<h3 class="title" style="color: #000000; font-weight: bold; margin-top: 10px; padding-top: 15px; font-size: 18px; "><a name="d0e4655" style="color: #003399; width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>H.2.1.&nbsp;什么是角色</h3>
</div>
</div>
</div>
<p style="color: #000000; ">在RBAC模型中，工作职位被描述为&#8220;角色&#8221;，职位所具有的权利称为许可权。角色是RBAC模型中的核心概念，围绕这一概念实现了访问控制策略的形式化。特殊的用户集合和许可权的集合通过角色这一媒介在某个特定的时间内联系在一起。而角色确实相对稳定的，因为任何组织的分工、活动或功能一般是很少经常改变的。</p>
<p style="color: #000000; ">可以有不同的动机去构造一个角色。角色可以表示完成特殊任务的资格，例如，是一个医师还是一个药师；橘色也可以表示一种权利与责任，如工程监理。权利与责任不同于资格，例如，Alice可能有资格领导几个部门，但他只能被分配负责一个部门的领导。通过多个用户的轮转，角色可以映射特殊责任的分配，例如，医师可以转换为管理者。RBAC的模式及其实现可以方便的适应这种角色概念的多种表现。</p>
<p style="color: #000000; ">在实际的计算机信息系统中，角色由系统管理员定义，角色的增加与删除、角色权利的增加与减少等uanli工作都是由系统管理员完成的。根据RBAC的要求，用户被分配为某个特定角色后，就被赋予了该角色所拥有的权利和责任，这种授权方式是强制性的，用户只能被动的接受，不能自主的决定为角色增加或减少权力，也不能把自己角色的权利转首给用户，显然，这是一种非自主型的访问控制模式。</p>
</div>
<div class="sect2" lang="zh-cn">
<div class="titlepage">
<div>
<div>
<h3 class="title" style="color: #000000; font-weight: bold; margin-top: 10px; padding-top: 15px; font-size: 18px; "><a name="d0e4664" style="color: #003399; width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>H.2.2.&nbsp;角色与用户组</h3>
</div>
</div>
</div>
<p style="color: #000000; ">角色与用户组有何区别？</p>
<p style="color: #000000; ">两者的主要区别是：用户组是用户的集合，但不可许可权的集合；而角色却同时具有用户集合和许可权集合的概念，角色的作用是把这两个集合联系在一起的中间媒介。</p>
<p style="color: #000000; ">在一个系统中，如果用户组的许可权和成员仅可以被系统安全员修改的话，在这种机制下，用户组的机制是非常接近于角色的概念的。角色也可以在用户组的基础上实现，这有利于保持原有系统中的控制关系。在这种情况下，角色相当于一个策略不见，与用户组的授权及责任关系相联系，而用户组是实现角色的机制，因此，两者之间是策略与实现机制之间的关系。</p>
</div>
</div>
<p style="color: #000000; ">虽然RBAC是一种无确定性质策略的模型，但它支持公认的安全原则：最小特权原则、责任分离原则和数据抽象原则。最小特权原则得到支持，是因为在RBAC模型中可以通过限制分配给角色权限的多少和大小来实现，分配给与某用户对应的角色的权限只要不超过该用户完成其任务的需要就可以了。</p>
<p style="color: #000000; ">责任分离原则的实现，是因为在RBAC模型中可以通过在完成敏感任务过程中分配两个责任上互相约束的两个角色来实现，例如在清查账目时，只需要设置财务管理员和会计连个角色参加就可以了。</p>
<p style="color: #000000; ">数据抽象是借助于抽象许可权这样的概念实现的，如在账目管理活动中，可以使用信用，借方等抽象许可权，而不是使用操作系统提供的读、写、执行等具体的许可权。但RBAC并不强迫实现这些原则，安全管理员可以允许配置 RBAC模型使它不支持这些原则。因此，RBAC支持数据抽象的程度与RBAC模型的实现细节有关。</p>
<p style="color: #000000; ">在20世纪90年代期间，大量的专家学者和专门研究单位对RBAC的概念进行了深入研究，先后提出了许多类型的RBAC模型，其中以美国George Mason大学信息安全技术实验室（LIST）提出的RBAC96模型最具有系统性，得到普遍的公认。</p>
<p style="color: #000000; ">RBAC96是一个模型族，其中包括RBAC<sub>0</sub>~RBAC<sub>3</sub>四个概念性模型。基本模型RBAC<sub>0</sub>定义了完全支持RBAC概念的任何系统的最低需求。RBAC<sub>1</sub>和RBAC<sub>2</sub>两者都包含RBAC<sub>0</sub>，但各自都增加了独立的特点，它们被成为高级模型。在RBAC<sub>1</sub>中增加了角色分级的概念，一个角色可以从另一个角色继承许可权。RBAC<sub>2</sub>增加了一些限制，强调在RBAC的不同组件中在配置方面的一些限制。</p>
<p style="color: #000000; ">RBAC<sub>1</sub>和RBAC<sub>2</sub>之间是不可比的。RBAC<sub>3</sub>被成为统一模型，它包含了RBAC<sub>1</sub>和RBAC<sub>2</sub>，利用传递性，也把RBAC<sub>0</sub>包括在内。这些模型构成了RBAC96模型族。图ap08-01表示了族内各模型间的关系，图ap08-02是RBAC<sub>3</sub>模型的概念示意图。</p>
<div class="figure" style="text-align: center; "><a name="d0e4730" style="color: #003399; width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>
<div class="figure-contents">
<div><img src="http://family168.com/oa/springsecurity/shared/images/ap08-01.png" alt="RBAC96内各模型间的关系" /></div>
</div>
<p class="title" style="color: #000000; "><strong>图&nbsp;H.1.&nbsp;RBAC96内各模型间的关系</strong></p>
</div>
<br class="figure-break" />
<div class="figure" style="text-align: center; "><a name="d0e4734" style="color: #003399; width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>
<div class="figure-contents">
<div><img src="http://family168.com/oa/springsecurity/shared/images/ap08-02.png" alt="RBAC96模型族" /></div>
</div>
<p class="title" style="color: #000000; "><strong>图&nbsp;H.2.&nbsp;RBAC96模型族</strong></p>
</div>
<br class="figure-break" />
<div class="sect1" lang="zh-cn">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="color: #000000; font-weight: 500; margin-top: 10px; padding-top: 15px; font-size: 22px; clear: both; "><a name="d0e4738" style="color: #003399; width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>H.3.&nbsp;基本模型RBAC<sub>0</sub></h2>
</div>
</div>
</div>
<p style="color: #000000; ">RBAC<sub>0</sub>的模型结构可以参看图ap08-02，但需要把途中的限制和角色等级两部分不包含在RBAC<sub>0</sub>模型中。该模型中包括用户（U）、角色（R）和许可权（P）的那个三类实体集合，此外还有一个会话集合（S）。</p>
<p style="color: #000000; ">其中用户代表一个组织的职员；角色表示该组织内部的一项任务的功能或某个工作职务，它也表示该角色成员所拥有的权利和职责；许可权是用户对系统中各课题访问或操作的权利，客体是指系统中的数据客体和资源客体，例如，目录、文件、记录、端口、设备、内存或子网都是客体。</p>
<p style="color: #000000; ">许可权因客体不同而不同，例如，对于目录、文件、设备、端口等类客体的操作权是读、写、执行等；对应数据库管理系统的客体是关系、元素、属性、记录、库文件、视图等，相应的操作权是Select、Update、Delete、Insert等；在会计应用中，相应的操作权是预算、信用、转移、创建和删除一个账目等。</p>
<p style="color: #000000; ">图ap08-02说明了关系用户指派UA（User Assignment）与许可权指派PA（Permission Assignment）的含义，两者都是多对多的关系。RBAC的关键就在于这两个关系，通过它们，一个用户将最终获得某些许可权并执行的权力。从图中角色的位置可以看粗，它是用户能够获取许可权的中间媒介。</p>
<p style="color: #000000; ">会话集中的每个会话表示一个用户可以对应多个角色（指向角色有两个箭头）。在某个会话的持续期间，一个用户可以同时激活多个角色，而该用户所获得的许可权是所有这些角色的所拥有许可权的并集。</p>
<p style="color: #000000; ">每个用户可以同时打开多个回话，每个会话都可以在工作站屏幕上用一个窗口显示。每个会话可以有不同活动角色的组合。RBAC<sub>0</sub>的这一特点将受到最小特权原则的限制。如果一个用户在一次会话中激活所有角色的权利超过该用户被允许的权利，将受到最小权利原则的限制。</p>
<div class="sect2" lang="zh-cn">
<div class="titlepage">
<div>
<div>
<h3 class="title" style="color: #000000; font-weight: bold; margin-top: 10px; padding-top: 15px; font-size: 18px; "><a name="d0e4764" style="color: #003399; width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>H.3.1.&nbsp;RBAC<sub>0</sub>模型的形式定义如下</h3>
</div>
</div>
</div>
<p style="color: #000000; ">定义1 RBAC<sub>0</sub>模型由以下描述确定：</p>
<p style="color: #000000; ">U、R、P、S分别表示用户集合、角色集合、许可权集合和会话集合。</p>
<p style="color: #000000; ">PA P&#215;R表示许可权与角色之间多对多的指派关系。</p>
<p style="color: #000000; ">UA U&#215;R表示用户与角色之间多对多的指派关系。</p>
<p style="color: #000000; ">用户：S&#8594;U 每个会话s<sub>i</sub>到单个用户user(s<sub>i</sub>)的映射函数（常量代表会话的声明周期）。</p>
<p style="color: #000000; ">角色：S&#8594;2<sup>R</sup>&nbsp;每个会话s<sub>i</sub>到角色子集roles(s<sub>i</sub>) {r|user(s<sub>i</sub>, r')&#8712;UA}（能随时间改变）的映射函数，会话s<sub>i</sub>有许可权U<sub>r</sub>&#8712;roles(s<sub>i</sub>){p|(p,r')&#8712;PA}。</p>
<p style="color: #000000; ">在使用RBAC<sub>0</sub>模型时，应该要求每个许可权和每个用户至少应该被分配给一个角色。两个角色被分配的许可权完全一样是可能的，但仍是两个完全独立的角色，用户也有类似情况。角色可以适当的被看做是一种语义结构，是访问控制策略形式化的基础。</p>
<p style="color: #000000; ">RBAC<sub>0</sub>把许可权处理未非解释符号，因为其精确含义只能由实现确定且与系统有关。RBAC<sub>0</sub>中的许可权只能应用于数据和资源类客体，但不能应用于模型本身的组件。修改集合U、R、P和关系PA和UA的权限称为管理权限，后面将介绍RBAC的管理模型。因此，在RBAC<sub>0</sub>中假定只有安全管理员才能修改这些组件。</p>
<p style="color: #000000; ">会话是由单个用户控制的，在模型中，用户可以创建会话，并有选择的激活用户角色的某些子集。在一个会话中的角色的激活是由用户来决断的，会话的终止也是由用户初始化的。RBAC<sub>0</sub>不允许由一个会话去创建另一个会话，会话只能由用户创建。</p>
</div>
</div>
<div class="sect1" lang="zh-cn">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="color: #000000; font-weight: 500; margin-top: 10px; padding-top: 15px; font-size: 22px; clear: both; "><a name="d0e4833" style="color: #003399; width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>H.4.&nbsp;角色分级模型RBAC<sub>1</sub></h2>
</div>
</div>
</div>
<p style="color: #000000; ">RBAC<sub>1</sub>模型的特色是模型中的角色是分级的，不同级别的角色由不同的职责与权力，橘色的级别形成偏序关系。图ap08-03说明了角色等级的概念。在途中位置处于较高处的角色的等级高于较低位置角色的等级。利用角色的分级概念可以限制继承的范围（scope）。</p>
<div class="figure" style="text-align: center; "><a name="d0e4843" style="color: #003399; width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>
<div class="figure-contents">
<div><img src="http://family168.com/oa/springsecurity/shared/images/ap08-03.png" alt="角色分级的概念" /></div>
</div>
<p class="title" style="color: #000000; "><strong>图&nbsp;H.3.&nbsp;角色分级的概念</strong></p>
</div>
<br class="figure-break" />
<p style="color: #000000; ">图中项目成员的等级最低，角色程序员和测试员的等级都高于角色项目成员，并都可以继承项目成员的权利；角色管理员具有最高的等级，它可以继承测试员和程序员的权利。为了满足实际组织中一个角色不完全继承另一个角色所有权利与责任的需求，模型中引入了私有角色的概念，如图中的测试员'和程序员'分别是测试员和程序员的私有uese，它们可以分别继承测试员和程序员的某些专用权利。</p>
<p style="color: #000000; ">显然，角色的等级关系具有自反性（自己可以继承自己）、传递性（A继承B，B继承C，则A继承C）和反对称性（A继承B，B继承A，则A=B），因此是偏序关系，下面是RBAC<sub>1</sub>的形式定义。</p>
<div class="sect2" lang="zh-cn">
<div class="titlepage">
<div>
<div>
<h3 class="title" style="color: #000000; font-weight: bold; margin-top: 10px; padding-top: 15px; font-size: 18px; "><a name="d0e4854" style="color: #003399; width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>H.4.1.&nbsp;定义2：RBAC<sub>1</sub>由以下内容确定</h3>
</div>
</div>
</div>
<p style="color: #000000; ">U、R、P、S分别表示用户集合、角色集合、许可权集合和会话集合。</p>
<p style="color: #000000; ">PA P&#215;R表示许可权与角色之间多对多的指派关系。</p>
<p style="color: #000000; ">UA U&#215;R表示用户与角色之间多对多的指派关系。</p>
<p style="color: #000000; ">RH R&#215;R是对R的偏序关系，称为角色等级或角色支配关系，也可用&#8805;符号表示。</p>
<p style="color: #000000; ">用户：S&#8594;U 每个会话s<sub>i</sub>到单个用户user(s<sub>i</sub>)的映射函数（常量代表会话的声明周期）。</p>
<p style="color: #000000; ">角色：S&#8594;2<sup>R</sup>&nbsp;每个会话s<sub>i</sub>到角色子集roles(s<sub>i</sub>) {r|(r'&#8805;r)[user(s<sub>i</sub>, r')&#8712;UA]}（能随时间改变）的映射函数，会话s<sub>i</sub>有许可权U<sub>r</sub>&#8712;roles(s<sub>i</sub>){p|(r''&#8804;r)[(p,r'')&#8712;PA]}。</p>
</div>
</div>
<div class="sect1" lang="zh-cn">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="color: #000000; font-weight: 500; margin-top: 10px; padding-top: 15px; font-size: 22px; clear: both; "><a name="d0e4899" style="color: #003399; width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>H.5.&nbsp;限制模型RBAC<sub>2</sub></h2>
</div>
</div>
</div>
<p style="color: #000000; ">RBAC<sub>2</sub>模型是在RBAC<sub>0</sub>模型增加限制后形成的，它与RBAC<sub>1</sub>并不兼容。RBAC<sub>2</sub>定义如下：</p>
<div class="sect2" lang="zh-cn">
<div class="titlepage">
<div>
<div>
<h3 class="title" style="color: #000000; font-weight: bold; margin-top: 10px; padding-top: 15px; font-size: 18px; "><a name="d0e4918" style="color: #003399; width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>H.5.1.&nbsp;定义3：</h3>
</div>
</div>
</div>
<p style="color: #000000; ">除了在RBAC<sub>0</sub>中增加了一些限制因素外，RBAC<sub>2</sub>未加改变的来自于RBAC<sub>0</sub>，这些限制是用于确定RBAC<sub>0</sub>中各个组件的值是否是可接受的，只有那些可接受的值才是允许的。</p>
<p style="color: #000000; ">RBAC<sub>2</sub>中引入的限制可以施加到RBAC<sub>0</sub>模型中的所有关系和组件上。RBAC<sub>2</sub>中的一个基本限制时互斥角色的限制，互斥角色是指各自权限尅一互相制约的两个角色。对于这类角色一个用户在某一次活动中只能被分配其中的一个角色，不能同时获得两个角色的使用权。</p>
<p style="color: #000000; ">例如，在审计活动中，一个角色不能同时被指派给会计角色和审计员角色。又如，在公司中，经理和副经理的角色也是互斥的，合同或支票只能由经理签字，不能由副经理签字。在为公司建立的RBAC<sub>2</sub>模型中，一个用户不能同时兼得经理和副经理两个角色。模型汇总的互斥限制可以支持权责分离原则的实现。</p>
<p style="color: #000000; ">更一般化而言，互斥限制可以控制在不同的角色组合中用户的成员关系是否是可接受的。例如，一个用户可以既是项目A的程序言，也可以是项目B的测试员和项目C的验收员，但他不能同时成为同一个项目中的这3个角色。RBAC<sub>2</sub>模型可以对这种情况进行限制。</p>
<p style="color: #000000; ">另一个用户指派限制的例子是一个角色限制其最大成员数，这被称为角色的基数限制。例如，一个单位的最高领导只能为1人，中层干部的数量也是有限的，一旦分配给这些角色的用户数超过了角色基数的限制，就不再接受新配给的用户了。</p>
<p style="color: #000000; ">限制角色的最小基数实现起来有些困难。例如，如果规定占用某个角色的最小用户数，问题是系统如何在任何时刻都能知道这些占用者中的某个人没有消失，如果消失的话，系统又应该如何去做。</p>
<p style="color: #000000; ">在为用户指派某个角色A时，在有的情况下要求该用户必须是角色B的一个成员，B角色成为角色A的先决角色。先决角色（Prerequisite Roles）的概念来自于能力和适应性。对先决绝对的限制成为先决限制。一个通俗的例子是，一个数学副教授应该从数学讲师中提拔，讲师是任副教授的先决角色。但在实际系统中，不兼容角色之间的先决限制的情况也会发生。</p>
<p style="color: #000000; ">在图ap08-03中，可以限制只有本项目的成员才有资格担任程序员的角色，通常在一个系统中，先决角色比新指派的角色的级别要低一些。但有的情况下，却要求只有当用户不是某个特殊角色时，才能担任另一个角色A。如，需要执行回避策略时需要这样做，例如，本课题组成员不应当是本项目成果鉴定委员会的成员。这类限制也可以推广到许可权方面。</p>
<p style="color: #000000; ">由于用户与角色的作用会与会话联系在一起，因此对会话也可以施加限制。例如，可以允许一个用户被指派给两个角色，但不允许在同一时间内把该用户在两个角色中都激活。另外，还可以限制一个用户在同一时间内可以激活的会话的数量，相应的，对该用户所激活的会话中所分配许可权的数量也可以施加限制。</p>
<p style="color: #000000; ">前面提到的继承概念也可以视为一种限制。被分配给低级别角色的权限，也必须分配给该角色的所有上级角色。或等价的，一个指派给较高级别的角色的用户必须指派给该角色的所有下级角色。因此从某种角度上讲，RBAC<sub>1</sub>模型是冗余的，它被包含在RBAC<sub>2</sub>中。但RBAC<sub>1</sub>模型比较简洁，用继承代替限制可使概念更清晰。</p>
<p style="color: #000000; ">实现时可以用函数来实现限制，当为用户指定角色或为角色分配权限时就调用这些函数进行检查，根据函数返回的结果决定分配是否满足限制的要求，通常只对那些可被有效检查和那些惯例性的一些简单限制给与实现，因为这些限制可以保持较长的时间。</p>
<p style="color: #000000; ">模型中的限制机制的有效性建立在每个用户只有唯一标识符的基础上，如果一个实际系统支持用户拥有多标识符，限制将会失效。同样，如果同一个操作可以有两个以上的许可权来比准，那么，RBAC系统也无法实施加强的基本限制和责任分离饿限制。因此要求用户与其标识符，许可与对应的操作之间一一对应。</p>
</div>
</div>
<div class="sect1" lang="zh-cn">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="color: #000000; font-weight: 500; margin-top: 10px; padding-top: 15px; font-size: 22px; clear: both; "><a name="d0e4981" style="color: #003399; width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>H.6.&nbsp;统一模型RBAC<sub>3</sub></h2>
</div>
</div>
</div>
<p style="color: #000000; ">RBAC<sub>3</sub>把RBAC<sub>1</sub>和RBAC<sub>2</sub>组合在一起，提供角色的分级和继承的能力。但把这两种概念组合在一起也引起一些新问题。</p>
<p style="color: #000000; ">限制也可以应用于角色等级本身，由于角色间的等级关系满足偏序关系，这种限制对模型而言是本质性的，可能会影响这种偏序关系。例如，附加的限制可能会限制一个给定角色的应有的下级角色的数量。</p>
<p style="color: #000000; ">两个或多个角色由可能被限制成没有公共的上级角色或下级角色。这些类型的限制在概念角色等级的权力已经被分散化的情况下是有用哦，但是安全主管却希望对所有允许这些改变的方法加以限制。</p>
<p style="color: #000000; ">在限制和角色的等级之间也会产生敏感的相互影响。在图ap08-03的环境中，一个项目成员不允许同时担任程序言与测试员的角色，但项目管理员所处的位置显然是违反了该限制。在某种情况i下由高等级的角色违反这种限制是可接受的，但在其他情况下又不允许这种违反现象发生。</p>
<p style="color: #000000; ">从严格性的角度来讲，模型的规则不应该是一些情况下不允许而在另一情况下是允许的。类似的情况也会发生在对基数的限制上。假定限制一个用户之多能分配给一个橘色，那么对图中的测试员的一个指派能够未被这种限制吗？换句话说，基数限制是不是只能用于直接成员，是否也能应用于继承成员上？</p>
<p style="color: #000000; ">私有角色的概念可以说明这些限制是有用的。同样在图ap08-03的环境中，可以把测试员'，程序员'和项目管理员3个角色说明为互斥的，它们处于同一等级，没有共同的上级角色，所以管理员角色没有违反互斥限制。通常私有角色和其他角色之间没有公共上级角色，因为它们是这个等级的最大元素，所以私有角色之间互斥关系可以无冲突的定义。</p>
<p style="color: #000000; ">诸私有角色之间的相同部分可以被说明为具有0成员的最大技术限制。根据这种方法，测试员必须被指派给测试员'这个角色，而测试员角色就作为与管理员角色共享许可权的一种工具。</p>
<p style="color: #000000; ">在前面的讨论中，我们都假设RBAC的所有组件都是由单个的安全员来管理里。但是，对于一个大系统而言，系统中的角色可能成百上千，再加上它们之间的复杂关系，使得集中式的管理任务成为非常可怕的工作，因此通常由几个管理员小组来完成。能否用RBAC管理自己本身呢？</p>
<p style="color: #000000; ">RBAC的管理模型示于图ap08-04。该图的上半部分本质上与图ap08-02相同，图中的限制时针对所有成分的，图的下半部分是对上半部分关于管理角色AR和管理许可权AP与正规角色集R和许可权集P是分别不可相交的。这个模型显示，正规许可权只能分配给正规角色（RBAC模型中定义的角色），管理许可权只能分配给管理角色。</p>
</div>
<div class="sect1" lang="zh-cn">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="color: #000000; font-weight: 500; margin-top: 10px; padding-top: 15px; font-size: 22px; clear: both; "><a name="d0e5013" style="color: #003399; width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>H.7.&nbsp;定义4</h2>
</div>
</div>
</div>
<p style="color: #000000; ">管理许可权AP有权改变组成RBAC<sub>0</sub>、RBAC<sub>1</sub>、RBAC<sub>2</sub>或RBAC<sub>3</sub>的所有成分，但正规许可权P不能。管理许可权与正规许可权不相交，即AP&#8745;P=。管理许可权和正规许可权只能分别分配给管理角色AR和正规角色R，并且AR&#8745;R=。</p>
<div class="figure" style="text-align: center; "><a name="d0e5030" style="color: #003399; width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>
<div class="figure-contents">
<div><img src="http://family168.com/oa/springsecurity/shared/images/ap08-04.png" alt="管理模型示意图" /></div>
</div>
<p class="title" style="color: #000000; "><strong>图&nbsp;H.4.&nbsp;管理模型示意图</strong></p>
</div>
<br class="figure-break" />
<p style="color: #000000; ">在图ap08-04的上半部可以对应RBAC<sub>0</sub>、RBAC<sub>1</sub>、RBAC<sub>2</sub>和RBAC<sub>3</sub>模型，类似地下半部可以对应ARBAC<sub>0</sub>、ARBAC<sub>1</sub>、ARBAC<sub>2</sub>和ARBAC<sub>3</sub>模型，此处的A表示&#8220;管理&#8221;。ARBAC<sub>0</sub>~ARBAC<sub>3</sub>形成了RBAC的管理模型族，成为ARBAC97。通常我们期望管理模型比RBAC模型本身简单一些，因此可以利用ARBAC<sub>0</sub>管理RBAC<sub>3</sub>，而不是用ARBAC<sub>3</sub>去管理RBAC<sub>0</sub>模型。</p>
</div>
<div class="sect1" lang="zh-cn">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="color: #000000; font-weight: 500; margin-top: 10px; padding-top: 15px; font-size: 22px; clear: both; "><a name="d0e5078" style="color: #003399; width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>H.8.&nbsp;在ARBAC97中，包括三种组件</h2>
</div>
</div>
</div>
<p style="color: #000000; ">URA87：用户-角色指派。该组件涉及用户-指派关系UA的管理，该关系把用户与角色关联在一起。对该关系的修改权由管理角色控制，这样，管理角色中的成员有权管理正规角色中的成员关系。把一个用户指定为管理角色是在URA97以外完成的，并假定是由安全员完成的。</p>
<p style="color: #000000; ">PRA97：许可权-角色指派。该组件涉及角色-许可权的指派与撤销。从角色观点来看，用户和许可权有类似的特点，它们都是由角色联系在一起的实在实体。因此，可以把PRA97看做是URA97的对偶组件。</p>
<p style="color: #000000; ">RRA97：角色-角色指派。为了便于对角色的管理，对角色又进行了分类。该组件涉及3类角色，它们是：</p>
<div class="orderedlist">
<ol type="1" style="color: #000000; ">
    <li style="color: #000000; ">
    <p style="color: #000000; ">能力（Abilities）角色——进以许可权和其他能力做成成员的角色。</p>
    </li>
    <li style="color: #000000; ">
    <p style="color: #000000; ">组（Groups）角色——仅以用户和其他组为成员的一类角色。</p>
    </li>
    <li style="color: #000000; ">
    <p style="color: #000000; ">UP-角色——表示用户与许可权的角色，这类角色对其成员没有限制，成员可以使用户、角色、许可权、能力、组或其他UP-角色。</p>
    </li>
</ol>
</div>
<p style="color: #000000; ">区别这三类模型的主要原因是可以应用不同的管理模型去建立不同类型角色之间的关系。区分的动因首先是对能力的考虑，能力是许可权的集合，可以把该集合中所有许可权作为一个单位指派给一个角色。类似的，组是用户的集合，可以把该集合中所有许可权作为一个单位指派给一个角色。组和能力角色都似乎可以划分等级的。</p>
<p style="color: #000000; ">在一个UP-角色中，一个能力是否是其的一个成员是由UP-角色是否支配该能力决定的，如果支配就是，否则就不是。相反的，如果一个UP-角色被一个组角色支配，则这个组就是该UP-角色的成员。</p>
<p style="color: #000000; ">对ARBAC97管理模型的研究还在继续之中，对能力-指派与组-指派的形式化已基本完成，对UP-角色概念的研究成果还未形式化。</p>
</div>
<div class="sect1" lang="zh-cn">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="color: #000000; font-weight: 500; margin-top: 10px; padding-top: 15px; font-size: 22px; clear: both; "><a name="d0e5103" style="color: #003399; width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>H.9.&nbsp;RBAC模型的特点</h2>
</div>
</div>
</div>
<p style="color: #000000; ">符合各类组织机构的安全管理需求。RBAC模型支持最小特权原则、责任分离原则，这些原则是任何组织的管理工作都需要的。这就使得RBAC模型由广泛的应用前景。</p>
<p style="color: #000000; ">RBAC模型支持数据抽象原则和继承概念。由于目前主流程序设计语言都支持面向对象技术，RBAC的这一特性便于在实际系统中应用实现。</p>
<p style="color: #000000; ">模型中概念与实际系统紧密对应。RBAC模型中的角色、用户和许可权等概念都是实际系统实际存在的实体，便于设计者建立现存的或待建系统的RBAC模型。</p>
<p style="color: #000000; ">RBAC模型仍素具访问控制类模型，本质是对访问矩阵模型的扩充，能够很好的解决系统中主体对客气的访问控制访问权力的分配与控制问题，但模型没有提供信息流控制机制，还不能完全满足信息系统的全部安全需求。</p>
<p style="color: #000000; ">虽然也有人认为可以用RBAC去仿真基于格的访问控制系统（LBAC），但RBAC对系统内部信息流的控制不是直观的，需要模型外的功能支持。有关信息流控制的作用域原理将在第四章介绍，届时读者可以进一步理解RBAC模型的这种缺陷。</p>
<p style="color: #000000; ">RBAC模型没有提供操作顺序控制机制。这一缺陷使得RBAC模型很难应用关于那些要求有严格操作次序的实体系统，例如，在购物控制系统中要求系统对购买步骤的控制，在客户未付款之前不应让他把商品拿走。RBAC模型要求把这种控制机制放到模型外去实现。</p>
<p style="color: #000000; ">RBAC96模型和RBAC97uanli模型都故意回避了一些问题，如是否允许一个正在会话的用户再创建一个新会话，管理模型不支持用户和许可权的增加与删除等管理工作灯，都是需要解决而未提供支持的问题，这些问题都还在研究中，但是如果缺少这些能力的支持，模型的而应用也将受到影响。相反，访问绝阵模型提供了用户和权限修改功能，因此，不能说RBAC模型能够完全取代访问矩阵模型。</p>
</div>
</span>
<img src ="http://www.blogjava.net/yifeng/aggbug/291655.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yifeng/" target="_blank">忆风</a> 2009-08-18 17:18 <a href="http://www.blogjava.net/yifeng/archive/2009/08/18/291655.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HttpClient  POST的中文编码问题</title><link>http://www.blogjava.net/yifeng/archive/2009/01/22/252281.html</link><dc:creator>忆风</dc:creator><author>忆风</author><pubDate>Wed, 21 Jan 2009 16:55:00 GMT</pubDate><guid>http://www.blogjava.net/yifeng/archive/2009/01/22/252281.html</guid><wfw:comment>http://www.blogjava.net/yifeng/comments/252281.html</wfw:comment><comments>http://www.blogjava.net/yifeng/archive/2009/01/22/252281.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/yifeng/comments/commentRss/252281.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yifeng/services/trackbacks/252281.html</trackback:ping><description><![CDATA[<br />
在用到HttpClient的基本请求和响应时候，发现默认的编码是&#8220;<tt>ISO-8859-1</tt>&#8221;，这样就存在中文乱码问题了，解决办法如下，记录一下：<br />
<br />
http://hc.apache.org/httpclient-3.x/charencodings.html#Request_Response_Body<br />
<br />
三种形式：<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img alt="" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><span style="color: #000000">postMethod.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET,&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">UTF-8</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img alt="" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;postMethod.addRequestHeader(</span><span style="color: #000000">"</span><span style="color: #000000">Content-Type</span><span style="color: #000000">"</span><span style="color: #000000">,</span><span style="color: #000000">"</span><span style="color: #000000">text/html;charset=UTF-8</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img alt="" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;postMethod.setRequestHeader(</span><span style="color: #000000">"</span><span style="color: #000000">Content-Type</span><span style="color: #000000">"</span><span style="color: #000000">,&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">text/html;charset=UTF-8</span><span style="color: #000000">"</span><span style="color: #000000">);</span></div>
<img src ="http://www.blogjava.net/yifeng/aggbug/252281.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yifeng/" target="_blank">忆风</a> 2009-01-22 00:55 <a href="http://www.blogjava.net/yifeng/archive/2009/01/22/252281.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>tomcat 的jvm 内存溢出问题的解决</title><link>http://www.blogjava.net/yifeng/archive/2008/12/16/246734.html</link><dc:creator>忆风</dc:creator><author>忆风</author><pubDate>Tue, 16 Dec 2008 13:42:00 GMT</pubDate><guid>http://www.blogjava.net/yifeng/archive/2008/12/16/246734.html</guid><wfw:comment>http://www.blogjava.net/yifeng/comments/246734.html</wfw:comment><comments>http://www.blogjava.net/yifeng/archive/2008/12/16/246734.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yifeng/comments/commentRss/246734.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yifeng/services/trackbacks/246734.html</trackback:ping><description><![CDATA[最近在熟悉一个开发了有几年的项目，需要把数据库从mysql移植到oracle，首先把jdbc的连接指向mysql，打包放到<span clas**e1?>tomcat</span>里面，可以跑起来，没有问题，可是当把jdbc连接指向oracle的时候，<span clas**e1?>tomcat</span>就连续抛java.lang.OutOfMemoryError的错误，上网google了一下，了解了一下<span clas**e1?>tomcat</span>的运行机制，也解决了问题，share出来，以备查。 <br />
<br />
1、首先是：java.lang.OutOfMemoryError: Java heap space <br />
<br />
解释： <br />
<br />
Heap size 设置 <br />
<br />
JVM堆的设置是指java程序运行过程中JVM可以调配使用的内存空间的设置.JVM在启动的时候会自动设置Heap size的值，其初始空间(即-Xms)是物理内存的1/64，最大空间(-Xmx)是物理内存的1/4。可以利用JVM提供的-Xmn -Xms -Xmx等选项可进行设置。Heap size 的大小是Young Generation 和Tenured Generaion 之和。 <br />
提示：在JVM中如果98％的时间是用于GC且可用的Heap size 不足2％的时候将抛出此异常信息。 <br />
提示：Heap Size 最大不要超过可用物理内存的80％，一般的要将-Xms和-Xmx选项设置为相同，而-Xmn为1/4的-Xmx值。 <br />
<br />
解决方法： <br />
<br />
手动设置Heap size <br />
修改<span clas**e1?>TOMCAT</span>_HOME/bin/catalina.bat，在&#8220;echo "Using CATALINA_BASE: $CATALINA_BASE"&#8221;上面加入以下行： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码&nbsp;</div>
</div>
<ol class="dp-j">
    <li><span><span>set&nbsp;JAVA_OPTS=%JAVA_OPTS%&nbsp;-server&nbsp;-Xms800m&nbsp;-Xmx800m&nbsp;-<span clas**e2?>XX:MaxNewSize</span>=256m&nbsp;&nbsp;&nbsp;</span></span> </li>
</ol>
</div>
<pre class="java" style="display: none" name="code">set JAVA_OPTS=%JAVA_OPTS% -server -Xms800m -Xmx800m -<span clas**e2?>XX:MaxNewSize</span>=256m </pre>
<br />
<br />
或修改catalina.sh <br />
在&#8220;echo "Using CATALINA_BASE: $CATALINA_BASE"&#8221;上面加入以下行： <br />
JAVA_OPTS="$JAVA_OPTS -server -Xms800m -Xmx800m -<span clas**e2?>XX:MaxNewSize</span>=256m" <br />
<br />
2、其次是：java.lang.OutOfMemoryError: PermGen space <br />
<br />
原因： <br />
<br />
PermGen space的全称是Permanent Generation space,是指内存的永久保存区域，这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被放到PermGen space中，它和存放类实例(Instance)的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理，所以如果你的应用中有很CLASS的话,就很可能出现PermGen space错误，这种错误常见在web服务器对JSP进行pre compile的时候。如果你的WEB APP下都用了大量的第三方jar, 其大小超过了jvm默认的大小(4M)那么就会产生此错误信息了。 <br />
<br />
解决方法： <br />
<br />
1. 手动设置MaxPermSize大小 <br />
修改<span clas**e1?>TOMCAT</span>_HOME/bin/catalina.bat（Linux下为catalina.sh），在
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码&nbsp;</div>
</div>
<ol class="dp-j">
    <li><span><span>&#8220;echo&nbsp;</span><span class="string">"Using&nbsp;CATALINA_BASE:&nbsp;$CATALINA_BASE"</span><span>&#8221;上面加入以下行：&nbsp;&nbsp;&nbsp;</span></span>
    <li><span>set&nbsp;JAVA_OPTS=%JAVA_OPTS%&nbsp;-server&nbsp;-XX:PermSize=128M&nbsp;-XX:MaxPermSize=512m&nbsp;&nbsp;&nbsp;</span> </li>
</ol>
</div>
<pre class="java" style="display: none" name="code">&#8220;echo "Using CATALINA_BASE: $CATALINA_BASE"&#8221;上面加入以下行：
set JAVA_OPTS=%JAVA_OPTS% -server -XX:PermSize=128M -XX:MaxPermSize=512m </pre>
<br />
<br />
catalina.sh下为： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码&nbsp;</div>
</div>
<ol class="dp-j">
    <li><span><span>JAVA_OPTS=</span><span class="string">"$JAVA_OPTS&nbsp;-server&nbsp;-XX:PermSize=128M&nbsp;-XX:MaxPermSize=512m"</span><span>&nbsp;&nbsp;</span></span> </li>
</ol>
</div>
<pre class="java" style="display: none" name="code">JAVA_OPTS="$JAVA_OPTS -server -XX:PermSize=128M -XX:MaxPermSize=512m"</pre>
<br />
<br />
<br />
另外看到了另外一个帖子，觉得挺好，摘抄如下： <br />
分析java.lang.OutOfMemoryError: PermGen space <br />
<br />
发现很多人把问题归因于： spring,hibernate,<span clas**e1?>tomcat</span>，因为他们动态产生类,导致JVM中的permanent heap溢出 。然后解决方法众说纷纭，有人说升级 <span clas**e1?>tomcat</span>版本到最新甚至干脆不用<span clas**e1?>tomcat</span>。还有人怀疑spring的问题，在spring论坛上讨论很激烈，因为spring在AOP时使用CBLIB会动态产生很多类。 <br />
<br />
但问题是为什么这些王牌的开源会出现同一个问题呢，那么是不是更基础的原因呢？<span clas**e1?>tomcat</span>在Q&amp;A很隐晦的回答了这一点，我们知道这个问题，但这个问题是由一个更基础的问题产生。 <br />
<br />
于是有人对更基础的JVM做了检查，发现了问题的关键。原来SUN 的JVM把内存分了不同的区，其中一个就是permenter区用来存放用得非常多的类和类描述。本来SUN设计的时候认为这个区域在JVM启动的时候就固定了，但他没有想到现在动态会用得这么广泛。而且这个区域有特殊的垃圾收回机制，现在的问题是动态加载类到这个区域后，gc根本没办法回收！ <br />
<br />
<br />
对于以上两个问题，我的处理是： <br />
<br />
在catalina.bat的第一行增加： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码&nbsp;</div>
</div>
<ol class="dp-j">
    <li><span><span>set&nbsp;JAVA_OPTS=-Xms64m&nbsp;-Xmx256m&nbsp;-XX:PermSize=128M&nbsp;-<span clas**e2?>XX:MaxNewSize</span>=256m&nbsp;-XX:MaxPermSize=256m&nbsp;&nbsp;&nbsp;</span></span> </li>
</ol>
</div>
<pre class="java" style="display: none" name="code">set JAVA_OPTS=-Xms64m -Xmx256m -XX:PermSize=128M -<span clas**e2?>XX:MaxNewSize</span>=256m -XX:MaxPermSize=256m </pre>
<br />
<br />
在catalina.sh的第一行增加： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码&nbsp;</div>
</div>
<ol class="dp-j">
    <li><span><span>JAVA_OPTS=-Xms64m&nbsp;-Xmx256m&nbsp;-XX:PermSize=128M&nbsp;-<span clas**e2?>XX:MaxNewSize</span>=256m&nbsp;-XX:MaxPermSize=256m&nbsp;&nbsp; </span></span></li>
</ol>
</div>
<img src ="http://www.blogjava.net/yifeng/aggbug/246734.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yifeng/" target="_blank">忆风</a> 2008-12-16 21:42 <a href="http://www.blogjava.net/yifeng/archive/2008/12/16/246734.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts 2 + Spring 2 + JPA + AJAX</title><link>http://www.blogjava.net/yifeng/archive/2008/12/11/245592.html</link><dc:creator>忆风</dc:creator><author>忆风</author><pubDate>Wed, 10 Dec 2008 16:55:00 GMT</pubDate><guid>http://www.blogjava.net/yifeng/archive/2008/12/11/245592.html</guid><wfw:comment>http://www.blogjava.net/yifeng/comments/245592.html</wfw:comment><comments>http://www.blogjava.net/yifeng/archive/2008/12/11/245592.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yifeng/comments/commentRss/245592.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yifeng/services/trackbacks/245592.html</trackback:ping><description><![CDATA[<h3><a name="Struts2%2BSpring2%2BJPA%2BAJAX-Showmethecode" style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>Show me the
code</h3>
<p>You can just download the <span class="nobr"><a title="Visit page outside Confluence" href="http://cwiki.apache.org/S2WIKI/struts-2-spring-2-jpa-ajax.data/quickstart.zip" rel="nofollow">zipped
Eclipse project<sup><img class="rendericon" border="0" alt="" align="absMiddle" src="http://cwiki.apache.org/confluence/images/icons/linkext7.gif" width="7" height="7" /></sup></a></span>, add the required dependencies to the lib folder
under the /WebContent/WEB-INF/lib folder (relative to project's root folder) and
import it into Eclipse.</p>
<h3><a name="Struts2%2BSpring2%2BJPA%2BAJAX-Prerequisites" style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>Prerequisites</h3>
<ul>
    <li><span class="nobr"><a title="Visit page outside Confluence" href="http://struts.apache.org/2.x/" rel="nofollow">Struts 2<sup><img class="rendericon" border="0" alt="" align="absMiddle" src="http://cwiki.apache.org/confluence/images/icons/linkext7.gif" width="7" height="7" /></sup></a></span>
    </li>
    <li><span class="nobr"><a title="Visit page outside Confluence" href="http://tomcat.apache.org/download-55.cgi" rel="nofollow">Tomcat 5.5<sup><img class="rendericon" border="0" alt="" align="absMiddle" src="http://cwiki.apache.org/confluence/images/icons/linkext7.gif" width="7" height="7" /></sup></a></span>
    </li>
    <li><span class="nobr"><a title="Visit page outside Confluence" href="http://www.eclipse.org/" rel="nofollow">Eclipse<sup><img class="rendericon" border="0" alt="" align="absMiddle" src="http://cwiki.apache.org/confluence/images/icons/linkext7.gif" width="7" height="7" /></sup></a></span>
    </li>
    <li><span class="nobr"><a title="Visit page outside Confluence" href="http://www.eclipse.org/webtools/" rel="nofollow">Eclipse WTP<sup><img class="rendericon" border="0" alt="" align="absMiddle" src="http://cwiki.apache.org/confluence/images/icons/linkext7.gif" width="7" height="7" /></sup></a></span>
    </li>
    <li><span class="nobr"><a title="Visit page outside Confluence" href="http://www.hibernate.org/" rel="nofollow">Hibernate Core<sup><img class="rendericon" border="0" alt="" align="absMiddle" src="http://cwiki.apache.org/confluence/images/icons/linkext7.gif" width="7" height="7" /></sup></a></span>
    </li>
    <li><span class="nobr"><a title="Visit page outside Confluence" href="http://www.hibernate.org/" rel="nofollow">Hibernate Annotations<sup><img class="rendericon" border="0" alt="" align="absMiddle" src="http://cwiki.apache.org/confluence/images/icons/linkext7.gif" width="7" height="7" /></sup></a></span>
    </li>
    <li><span class="nobr"><a title="Visit page outside Confluence" href="http://www.hibernate.org/" rel="nofollow">Hibernate Entity Manager<sup><img class="rendericon" border="0" alt="" align="absMiddle" src="http://cwiki.apache.org/confluence/images/icons/linkext7.gif" width="7" height="7" /></sup></a></span>
    </li>
    <li><span class="nobr"><a title="Visit page outside Confluence" href="http://dev.mysql.com/downloads/mysql/5.0.html" rel="nofollow">MySql
    Server<sup><img class="rendericon" border="0" alt="" align="absMiddle" src="http://cwiki.apache.org/confluence/images/icons/linkext7.gif" width="7" height="7" /></sup></a></span>
    </li>
    <li><span class="nobr"><a title="Visit page outside Confluence" href="http://dev.mysql.com/downloads/connector/j/5.0.html" rel="nofollow">Mysql
    JDBC Driver<sup><img class="rendericon" border="0" alt="" align="absMiddle" src="http://cwiki.apache.org/confluence/images/icons/linkext7.gif" width="7" height="7" /></sup></a></span>
    </li>
    <li><span class="nobr"><a title="Visit page outside Confluence" href="http://www.springframework.org/download" rel="nofollow">Spring 2.0<sup><img class="rendericon" border="0" alt="" align="absMiddle" src="http://cwiki.apache.org/confluence/images/icons/linkext7.gif" width="7" height="7" /></sup></a></span> </li>
</ul>
<h3><a name="Struts2%2BSpring2%2BJPA%2BAJAX-Tomcat" style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>Tomcat</h3>
<p>Install Tomcat before going forward. See Tomcat's installation guide if you
have any problem installing it. </p>
<h3><a name="Struts2%2BSpring2%2BJPA%2BAJAX-MySql" style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>MySql</h3>
<p>Install and configure MySql. Create a database named "quickstart" and run the
script below to create the "Person" table. Later, on applicationContext.xml,
we'll use 'root' as the user name and password for the database, remember to
replace those values with the right ones for your database. </p>
<div class="code">
<div class="codeContent">
<pre class="code-sql">CREATE TABLE 'quickstart'.'Person' (
'id' INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
'firstName' <span class="code-object">VARCHAR</span>(45) NOT NULL,
'lastName' <span class="code-object">VARCHAR</span>(45) NOT NULL,
PRIMARY KEY('id')
)
ENGINE = InnoDB;</pre>
</div>
</div>
<h3><a name="Struts2%2BSpring2%2BJPA%2BAJAX-CreateEclipseproject" style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>Create
Eclipse project</h3>
<ol>
    <li>Open Eclipse. Seriously, you need to open Eclipse.
    </li>
    <li>Click File -> New -> Project. Under the "Web" folder, select "Dynamic
    Web Project" and click "Next".
    </li>
    <li>Enter the project name, "quickstart" from here on. The project will be
    running inside Tomcat, so we need to create a server configuration for it.
    <ol>
        <li>Under "Target Runtime", click "New", select "Apache Tomcat 5.5" and click
        next.
        </li>
        <li>Enter Tomcat's installation directory and select an installed JRE (1.5 is
        required) </li>
    </ol>
    </li>
    <li>Now you should be back to the project creation wizard, with Tomcat as your
    Target Runtime. Click "Next". Select "Dynamic Web Module" and "Java" facets, and
    click "Finish". </li>
</ol>
<h3><a name="Struts2%2BSpring2%2BJPA%2BAJAX-Dependencies" style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>Dependencies</h3>
<p>Your project should contain the folders "src", "build" and "WebContent". We
are going to put all the required jars under "/WebContent/WEB-INF/lib". To add
files to the "lib" folder, just copy them to
${workspace}\quickstart\WebContent\WEB-INF\lib, where ${workspace} is the
location of your Eclipse workspace folder. The version has been removed from the
jar files.</p>
<table class="confluenceTable">
    <tbody>
        <tr>
            <th class="confluenceTh">Jar</th>
            <th class="confluenceTh">From</th>
        </tr>
        <tr>
            <td class="confluenceTd">xwork.jar</td>
            <td class="confluenceTd">Struts 2</td>
        </tr>
        <tr>
            <td class="confluenceTd">struts2-api.jar</td>
            <td class="confluenceTd">Struts 2</td>
        </tr>
        <tr>
            <td class="confluenceTd">struts2-core.jar</td>
            <td class="confluenceTd">Struts 2</td>
        </tr>
        <tr>
            <td class="confluenceTd">struts2-Spring-plugin.jar</td>
            <td class="confluenceTd">Struts 2</td>
        </tr>
        <tr>
            <td class="confluenceTd">ognl.jar</td>
            <td class="confluenceTd">Struts 2</td>
        </tr>
        <tr>
            <td class="confluenceTd">freemarker-2.3.4.jar</td>
            <td class="confluenceTd">Struts 2</td>
        </tr>
        <tr>
            <td class="confluenceTd">mysql-connector-java.jar</td>
            <td class="confluenceTd">MySql JDBC Driver</td>
        </tr>
        <tr>
            <td class="confluenceTd">spring.jar</td>
            <td class="confluenceTd">Sping 2.0</td>
        </tr>
        <tr>
            <td class="confluenceTd">antlr.jar</td>
            <td class="confluenceTd">Hibernate Core</td>
        </tr>
        <tr>
            <td class="confluenceTd">asm.jar</td>
            <td class="confluenceTd">Hibernate Core</td>
        </tr>
        <tr>
            <td class="confluenceTd">asm-attrs.jar</td>
            <td class="confluenceTd">Hibernate Core</td>
        </tr>
        <tr>
            <td class="confluenceTd">cglib.jar</td>
            <td class="confluenceTd">Hibernate Core</td>
        </tr>
        <tr>
            <td class="confluenceTd">dom4j.jar</td>
            <td class="confluenceTd">Hibernate Core</td>
        </tr>
        <tr>
            <td class="confluenceTd">jdbc2_0-stdext.jar</td>
            <td class="confluenceTd">Hibernate Core</td>
        </tr>
        <tr>
            <td class="confluenceTd">ehcache.jar</td>
            <td class="confluenceTd">Hibernate Core</td>
        </tr>
        <tr>
            <td class="confluenceTd">hibernate3.jar</td>
            <td class="confluenceTd">Hibernate Core</td>
        </tr>
        <tr>
            <td class="confluenceTd">xml-apis.jar</td>
            <td class="confluenceTd">Hibernate Core</td>
        </tr>
        <tr>
            <td class="confluenceTd">commons-collections.jar</td>
            <td class="confluenceTd">Hibernate Core</td>
        </tr>
        <tr>
            <td class="confluenceTd">ejb3-persistence.jar</td>
            <td class="confluenceTd">Hibernate Annotations</td>
        </tr>
        <tr>
            <td class="confluenceTd">jta.jar</td>
            <td class="confluenceTd">Hibernate Annotations</td>
        </tr>
        <tr>
            <td class="confluenceTd">hibernate-annotations.jar</td>
            <td class="confluenceTd">Hibernate Annotations</td>
        </tr>
        <tr>
            <td class="confluenceTd">hibernate-entitymanager.jar</td>
            <td class="confluenceTd">Hibernate Entity Manager</td>
        </tr>
        <tr>
            <td class="confluenceTd">javassist.jar</td>
            <td class="confluenceTd">Hibernate Entity Manager</td>
        </tr>
        <tr>
            <td class="confluenceTd">jboss-archive-browsing.jar</td>
            <td class="confluenceTd">Hibernate Entity Manager</td>
        </tr>
    </tbody>
</table>
<p>Right click on the project and select "Refresh" (to notify Eclipse of the
jars that we just added).</p>
<h3><a name="Struts2%2BSpring2%2BJPA%2BAJAX-Domain" style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>Domain</h3>
<p>Our domain model will consist of just a simple "Person" class with a couple
of fields. </p>
<ol>
    <li>Create a new class named "Person" (File -> New -> Class), and enter
    "quickstart.model" for the package name.
    </li>
    <li>Add the fields "id" (int), "firstName" (String), and lastName ("String")
    with their setter/getter methods.
    </li>
    <li>Mark your class with the "@Entity" annotation, and the "id" field with the
    annotations "@Id" and "@GeneratedValue". </li>
</ol>
<p>your class will look like:</p>
<div class="code">
<div class="codeHeader"><strong>Person.java</strong></div>
<div class="codeContent">
<pre class="code-java"><span class="code-keyword">package</span> quickstart.model;
<span class="code-keyword">import</span> javax.persistence.Entity;
<span class="code-keyword">import</span> javax.persistence.GeneratedValue;
<span class="code-keyword">import</span> javax.persistence.Id;
@Entity
<span class="code-keyword">public</span> class Person {
@Id
@GeneratedValue
<span class="code-keyword">private</span> <span class="code-object">Integer</span> id;
<span class="code-keyword">private</span> <span class="code-object">String</span> lastName;
<span class="code-keyword">private</span> <span class="code-object">String</span> firstName;
<span class="code-keyword">public</span> <span class="code-object">String</span> getFirstName() {
<span class="code-keyword">return</span> firstName;
}
<span class="code-keyword">public</span> void setFirstName(<span class="code-object">String</span> firstName) {
<span class="code-keyword">this</span>.firstName = firstName;
}
<span class="code-keyword">public</span> <span class="code-object">String</span> getLastName() {
<span class="code-keyword">return</span> lastName;
}
<span class="code-keyword">public</span> void setLastName(<span class="code-object">String</span> lastName) {
<span class="code-keyword">this</span>.lastName = lastName;
}
<span class="code-keyword">public</span> <span class="code-object">Integer</span> getId() {
<span class="code-keyword">return</span> id;
}
<span class="code-keyword">public</span> void setId(<span class="code-object">Integer</span> id) {
<span class="code-keyword">this</span>.id = id;
}
}</pre>
</div>
</div>
<p>@Entity will let the provider know that this class can be persisted. @Id
marks the "id" field as the primary key for this class. @GeneratedValue will
cause the id field to be generated by the provider (Hibernate). Classes and
fields are by default mapped to tables and columns with the same name, see JPA's
documentation for more details. </p>
<h3><a name="Struts2%2BSpring2%2BJPA%2BAJAX-Personservice." style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>Person
service.</h3>
<p>We will now write the class that will take care of CRUD operations on
"Person" objects.</p>
<ol>
    <li>Create a new interface (File -> New -> Interface), enter
    "PersonService" for the name, and "quickstart.service" for the namespace. Set
    its content to: </li>
</ol>
<div class="code">
<div class="codeHeader"><strong>PersonService.java</strong></div>
<div class="codeContent">
<pre class="code-java"><span class="code-keyword">package</span> quickstart.service;
<span class="code-keyword">import</span> java.util.List;
<span class="code-keyword">import</span> quickstart.model.Person;
<span class="code-keyword">public</span> <span class="code-keyword">interface</span> PersonService {
<span class="code-keyword">public</span> List&lt;Person> findAll();
<span class="code-keyword">public</span> void save(Person person);
<span class="code-keyword">public</span> void remove(<span class="code-object">int</span> id);
<span class="code-keyword">public</span> Person find(<span class="code-object">int</span> id);
}</pre>
</div>
</div>
<ol>
    <li>Create a new class (File -> New -> Class), enter "PersonServiceImpl"
    for the name and "quickstart.service" for the namespace. Set its content to:
    </li>
</ol>
<div class="code">
<div class="codeHeader"><strong>PersonServiceImpl.java</strong></div>
<div class="codeContent">
<pre class="code-java"><span class="code-keyword">package</span> quickstart.service;
<span class="code-keyword">import</span> java.util.List;
<span class="code-keyword">import</span> javax.persistence.EntityManager;
<span class="code-keyword">import</span> javax.persistence.PersistenceContext;
<span class="code-keyword">import</span> javax.persistence.Query;
<span class="code-keyword">import</span> org.springframework.transaction.annotation.Transactional;
<span class="code-keyword">import</span> quickstart.model.Person;
@Transactional
<span class="code-keyword">public</span> class PersonServiceImpl <span class="code-keyword">implements</span> PersonService {
<span class="code-keyword">private</span> EntityManager em;
@PersistenceContext
<span class="code-keyword">public</span> void setEntityManager(EntityManager em) {
<span class="code-keyword">this</span>.em = em;
}
@SuppressWarnings(<span class="code-quote">"unchecked"</span>)
<span class="code-keyword">public</span> List&lt;Person> findAll() {
Query query = getEntityManager().createQuery(<span class="code-quote">"select p FROM Person p"</span>);
<span class="code-keyword">return</span> query.getResultList();
}
<span class="code-keyword">public</span> void save(Person person) {
<span class="code-keyword">if</span> (person.getId() == <span class="code-keyword">null</span>) {
<span class="code-comment">// <span class="code-keyword">new</span>
</span>            em.persist(person);
} <span class="code-keyword">else</span> {
<span class="code-comment">// update
</span>            em.merge(person);
}
}
<span class="code-keyword">public</span> void remove(<span class="code-object">int</span> id) {
Person person = find(id);
<span class="code-keyword">if</span> (person != <span class="code-keyword">null</span>) {
em.remove(person);
}
}
<span class="code-keyword">private</span> EntityManager getEntityManager() {
<span class="code-keyword">return</span> em;
}
<span class="code-keyword">public</span> Person find(<span class="code-object">int</span> id) {
<span class="code-keyword">return</span> em.find(Person.class, id);
}
}</pre>
</div>
</div>
<p>@PersistenceContext will make Spring inject an EntityManager into the service
when it is instantiated. The @PersistenceContext annotation can be placed on the
field, or on the setter method. If the class is annotated as @Transactional,
Spring will make sure that its methods run inside a transaction.</p>
<h3><a name="Struts2%2BSpring2%2BJPA%2BAJAX-JPAconfiguration" style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>JPA
configuration </h3>
<ol>
    <li>Create a folder named "META-INF" under the "src" folder.
    </li>
    <li>Create a file named "persistence.xml" under the "META-INF" folder and set
    its content to: </li>
</ol>
<div class="code">
<div class="codeHeader"><strong>persistence.xml</strong></div>
<div class="codeContent">
<pre class="code-xml">&lt;persistence xmlns=<span class="code-quote">"http://java.sun.com/xml/ns/persistence"</span>
<span class="code-keyword">xmlns:xsi</span>=<span class="code-quote">"http://www.w3.org/2001/XMLSchema-instance"</span>
xsi:schemaLocation=<span class="code-quote">"http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"</span>
version=<span class="code-quote">"1.0"</span>>
<span class="code-tag">&lt;persistence-unit name=<span class="code-quote">"punit"</span>></span>
<span class="code-tag">&lt;/persistence-unit></span>
<span class="code-tag">&lt;/persistence></span></pre>
</div>
</div>
<p>JPA configuration can be set on this file. On this example it will be empty
because the datasource configuration will be on the Spring configuration file.
</p>
<h3><a name="Struts2%2BSpring2%2BJPA%2BAJAX-Spring" style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>Spring</h3>
<ol>
    <li>Update the content of web.xml under /WebContent/WEB-INF/web.xml to:
    </li>
</ol>
<div class="code">
<div class="codeHeader"><strong>web.xml</strong></div>
<div class="codeContent">
<pre class="code-xml"><span class="code-tag">&lt;?xml version=<span class="code-quote">"1.0"</span> encoding=<span class="code-quote">"UTF-8"</span>?></span>
&lt;web-app id=<span class="code-quote">"person"</span> version=<span class="code-quote">"2.4"</span> xmlns=<span class="code-quote">"http://java.sun.com/xml/ns/j2ee"</span>
<span class="code-keyword">xmlns:xsi</span>=<span class="code-quote">"http://www.w3.org/2001/XMLSchema-instance"</span>
xsi:schemaLocation=<span class="code-quote">"http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"</span>>
<span class="code-tag">&lt;display-name></span>person<span class="code-tag">&lt;/display-name></span>
<span class="code-tag">&lt;filter></span>
<span class="code-tag">&lt;filter-name></span>struts2<span class="code-tag">&lt;/filter-name></span>
<span class="code-tag">&lt;filter-class></span>
org.apache.struts2.dispatcher.FilterDispatcher
<span class="code-tag">&lt;/filter-class></span>
<span class="code-tag">&lt;/filter></span>
<span class="code-tag">&lt;filter-mapping></span>
<span class="code-tag">&lt;filter-name></span>struts2<span class="code-tag">&lt;/filter-name></span>
<span class="code-tag">&lt;url-pattern></span>/*<span class="code-tag">&lt;/url-pattern></span>
<span class="code-tag">&lt;/filter-mapping></span>
<span class="code-tag">&lt;welcome-file-list></span>
<span class="code-tag">&lt;welcome-file></span>index.jsp<span class="code-tag">&lt;/welcome-file></span>
<span class="code-tag">&lt;/welcome-file-list></span>
<span class="code-tag">&lt;listener></span>
<span class="code-tag">&lt;listener-class></span>
org.springframework.web.context.ContextLoaderListener
<span class="code-tag">&lt;/listener-class></span>
<span class="code-tag">&lt;/listener></span>
<span class="code-tag">&lt;/web-app></span></pre>
</div>
</div>
<p>This will make the container redirect all requests to Struts
"FilterDispatcher" class. "index.jsp" is set as the home page, and Spring's
"ContextLoaderListener" is configured as a listener.</p>
<ol>
    <li>Create a file named "applicationContext.xml" under /WebContent/WEB-INF, and
    set its content to: </li>
</ol>
<div class="code">
<div class="codeHeader"><strong>applicationContext.xml</strong></div>
<div class="codeContent">
<pre class="code-xml"><span class="code-tag">&lt;?xml version=<span class="code-quote">"1.0"</span> encoding=<span class="code-quote">"UTF-8"</span>?></span>
&lt;beans xmlns=<span class="code-quote">"http://www.springframework.org/schema/beans"</span>
<span class="code-keyword">xmlns:xsi</span>=<span class="code-quote">"http://www.w3.org/2001/XMLSchema-instance"</span>
<span class="code-keyword">xmlns:aop</span>=<span class="code-quote">"http://www.springframework.org/schema/aop"</span>
<span class="code-keyword">xmlns:tx</span>=<span class="code-quote">"http://www.springframework.org/schema/tx"</span>
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
&lt;bean
class=<span class="code-quote">"org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"</span> />
<span class="code-tag">&lt;bean id=<span class="code-quote">"personService"</span> class=<span class="code-quote">"quickstart.service.PersonServiceImpl"</span> /></span>
&lt;bean id=<span class="code-quote">"entityManagerFactory"</span>
class=<span class="code-quote">"org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"</span>>
<span class="code-tag">&lt;property name=<span class="code-quote">"dataSource"</span> ref=<span class="code-quote">"dataSource"</span> /></span>
<span class="code-tag">&lt;property name=<span class="code-quote">"jpaVendorAdapter"</span>></span>
&lt;bean
class=<span class="code-quote">"org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"</span>>
<span class="code-tag">&lt;property name=<span class="code-quote">"database"</span> value=<span class="code-quote">"MYSQL"</span> /></span>
<span class="code-tag">&lt;property name=<span class="code-quote">"showSql"</span> value=<span class="code-quote">"true"</span> /></span>
<span class="code-tag">&lt;/bean></span>
<span class="code-tag">&lt;/property></span>
<span class="code-tag">&lt;/bean></span>
&lt;bean id=<span class="code-quote">"dataSource"</span>
class=<span class="code-quote">"org.springframework.jdbc.datasource.DriverManagerDataSource"</span>>
<span class="code-tag">&lt;property name=<span class="code-quote">"driverClassName"</span> value=<span class="code-quote">"com.mysql.jdbc.Driver"</span> /></span>
<span class="code-tag">&lt;property name=<span class="code-quote">"url"</span> value=<span class="code-quote">"jdbc:mysql://localhost/test"</span> /></span>
<span class="code-tag">&lt;property name=<span class="code-quote">"username"</span> value=<span class="code-quote">"root"</span> /></span>
<span class="code-tag">&lt;property name=<span class="code-quote">"password"</span> value=<span class="code-quote">"root"</span> /></span>
<span class="code-tag">&lt;/bean></span>
&lt;bean id=<span class="code-quote">"transactionManager"</span>
class=<span class="code-quote">"org.springframework.orm.jpa.JpaTransactionManager"</span>>
<span class="code-tag">&lt;property name=<span class="code-quote">"entityManagerFactory"</span> ref=<span class="code-quote">"entityManagerFactory"</span> /></span>
<span class="code-tag">&lt;/bean></span>
<span class="code-tag">&lt;tx:annotation-driven transaction-manager=<span class="code-quote">"transactionManager"</span> /></span>
&lt;bean id=<span class="code-quote">"personAction"</span> scope=<span class="code-quote">"prototype"</span>
class=<span class="code-quote">"quickstart.action.PersonAction"</span>>
<span class="code-tag">&lt;constructor-arg ref=<span class="code-quote">"personService"</span> /></span>
<span class="code-tag">&lt;/bean></span>
<span class="code-tag">&lt;/beans></span></pre>
</div>
</div>
<p>Note that the "class" attribute of the bean "personAction" is set to the name
of the action class, and the "personService" bean will be passed as a parameter
to the action constructor. Change the "url", "username" and "password" in the
"dataSource" bean to the appropiate values for your database. For more details
on the rest of the beans on this file, see Spring's documentation. The "scope"
attribute is new in Spring 2, and it means that Spring will create a new
PersonAction object every time an object of that type is requested. In Struts 2
a new action object is created to serve each request, that's why we need
scope="prototype".</p>
<h3><a name="Struts2%2BSpring2%2BJPA%2BAJAX-Struts" style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>Struts</h3>
<p>We will now create a simple Struts action that wraps PersonServices methods,
and we will configure Struts to use Spring as the object factory. </p>
<ol>
    <li>Open the new class dialog (File -> New -> Class) and enter
    "PersonAction" for the classname, and "quickstart.action" for the namespace. Set
    its content to: </li>
</ol>
<div class="code">
<div class="codeHeader"><strong>PersonAction.java</strong></div>
<div class="codeContent">
<pre class="code-java"><span class="code-keyword">package</span> quickstart.action;
<span class="code-keyword">import</span> java.util.List;
<span class="code-keyword">import</span> quickstart.model.Person;
<span class="code-keyword">import</span> quickstart.service.PersonService;
<span class="code-keyword">import</span> com.opensymphony.xwork2.Action;
<span class="code-keyword">import</span> com.opensymphony.xwork2.Preparable;
<span class="code-keyword">public</span> class PersonAction <span class="code-keyword">implements</span> Preparable {
<span class="code-keyword">private</span> PersonService service;
<span class="code-keyword">private</span> List&lt;Person> persons;
<span class="code-keyword">private</span> Person person;
<span class="code-keyword">private</span> <span class="code-object">Integer</span> id;
<span class="code-keyword">public</span> PersonAction(PersonService service) {
<span class="code-keyword">this</span>.service = service;
}
<span class="code-keyword">public</span> <span class="code-object">String</span> execute() {
<span class="code-keyword">this</span>.persons = service.findAll();
<span class="code-keyword">return</span> Action.SUCCESS;
}
<span class="code-keyword">public</span> <span class="code-object">String</span> save() {
<span class="code-keyword">this</span>.service.save(person);
<span class="code-keyword">this</span>.person = <span class="code-keyword">new</span> Person();
<span class="code-keyword">return</span> execute();
}
<span class="code-keyword">public</span> <span class="code-object">String</span> remove() {
service.remove(id);
<span class="code-keyword">return</span> execute();
}
<span class="code-keyword">public</span> List&lt;Person> getPersons() {
<span class="code-keyword">return</span> persons;
}
<span class="code-keyword">public</span> <span class="code-object">Integer</span> getId() {
<span class="code-keyword">return</span> id;
}
<span class="code-keyword">public</span> void setId(<span class="code-object">Integer</span> id) {
<span class="code-keyword">this</span>.id = id;
}
<span class="code-keyword">public</span> void prepare() <span class="code-keyword">throws</span> Exception {
<span class="code-keyword">if</span> (id != <span class="code-keyword">null</span>)
person = service.find(id);
}
<span class="code-keyword">public</span> Person getPerson() {
<span class="code-keyword">return</span> person;
}
<span class="code-keyword">public</span> void setPerson(Person person) {
<span class="code-keyword">this</span>.person = person;
}
}</pre>
</div>
</div>
<p>Look mom my action is a simple POJO!<br />
The "Preparable" interface instructs
Struts to call the "prepare" method if the "PrepareInterceptor" is applied to
the action (by default, it is). The constructor of the action takes a
"PersonService" as a parameter, which Spring will take care of passing when the
action is instatiated.</p>
<ol>
    <li>Create a new file named "struts.xml" under the "src" folder. And set its
    content to: </li>
</ol>
<div class="code">
<div class="codeHeader"><strong>struts.xml</strong></div>
<div class="codeContent">
<pre class="code-xml"><span class="code-tag">&lt;?xml version=<span class="code-quote">"1.0"</span> encoding=<span class="code-quote">"UTF-8"</span> ?></span>
&lt;!DOCTYPE struts PUBLIC
<span class="code-quote">"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"</span>
<span class="code-quote">"http://struts.apache.org/dtds/struts-2.0.dtd"</span>>
<span class="code-tag">&lt;struts></span>
<span class="code-tag">&lt;constant name=<span class="code-quote">"struts.objectFactory"</span> value=<span class="code-quote">"spring"</span> /></span>
<span class="code-tag">&lt;constant name=<span class="code-quote">"struts.devMode"</span> value=<span class="code-quote">"true"</span> /></span>
<span class="code-tag">&lt;package name=<span class="code-quote">"person"</span> extends=<span class="code-quote">"struts-default"</span>></span>
<span class="code-tag">&lt;action name=<span class="code-quote">"list"</span> method=<span class="code-quote">"execute"</span> class=<span class="code-quote">"personAction"</span>></span>
<span class="code-tag">&lt;result></span>pages/list.jsp<span class="code-tag">&lt;/result></span>
<span class="code-tag">&lt;result name=<span class="code-quote">"input"</span>></span>pages/list.jsp<span class="code-tag">&lt;/result></span>
<span class="code-tag">&lt;/action></span>
<span class="code-tag">&lt;action name=<span class="code-quote">"remove"</span> class=<span class="code-quote">"personAction"</span> method=<span class="code-quote">"remove"</span>></span>
<span class="code-tag">&lt;result></span>pages/list.jsp<span class="code-tag">&lt;/result></span>
<span class="code-tag">&lt;result name=<span class="code-quote">"input"</span>></span>pages/list.jsp<span class="code-tag">&lt;/result></span>
<span class="code-tag">&lt;/action></span>
<span class="code-tag">&lt;action name=<span class="code-quote">"save"</span> class=<span class="code-quote">"personAction"</span> method=<span class="code-quote">"save"</span>></span>
<span class="code-tag">&lt;result></span>pages/list.jsp<span class="code-tag">&lt;/result></span>
<span class="code-tag">&lt;result name=<span class="code-quote">"input"</span>></span>pages/list.jsp<span class="code-tag">&lt;/result></span>
<span class="code-tag">&lt;/action></span>
<span class="code-tag">&lt;/package></span>
<span class="code-tag">&lt;/struts></span></pre>
</div>
</div>
<p>Setting "struts.objectFactory" to "spring" will force Struts to instantiate
the actions using Spring, injecting all the defined dependencies on
applicationContext.xml. The "class" attribute for each action alias is set to
"personAction", which is the bean id that we defined on applicationContext.xml
for the PersonAction class. This is all that is needed to make Struts work with
Spring. </p>
<h3><a name="Struts2%2BSpring2%2BJPA%2BAJAX-Thepages" style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>The pages</h3>
<p>We only have two pages, "index.jsp" and "list.jsp". "list.jsp" returns a
table with a list of the persons on the database.We have this list on a
different page because we are going to add some AJAX to spicy it up. </p>
<ol>
    <li>Create a new file named "list.jsp" under /WebContent/pages/ and set its
    content to: </li>
</ol>
<div class="code">
<div class="codeHeader"><strong>list.jsp</strong></div>
<div class="codeContent">
<pre class="code-html"><span class="code-tag">&lt;%@ taglib prefix=<span class="code-quote">"s"</span> uri=<span class="code-quote">"/struts-tags"</span>%></span>
<span class="code-tag">&lt;p></span>Persons<span class="code-tag">&lt;/p></span>
<span class="code-tag">&lt;s:if test=<span class="code-quote">"persons.size ></span> 0"</span>>
<span class="code-tag">&lt;table></span>
<span class="code-tag">&lt;s:iterator value=<span class="code-quote">"persons"</span>></span>
<span class="code-tag">&lt;tr id=<span class="code-quote">"row_&lt;s:property value="</span>id<span class="code-quote">"/></span>"</span>>
<span class="code-tag">&lt;td></span>
<span class="code-tag">&lt;s:property value=<span class="code-quote">"firstName"</span> /></span>
<span class="code-tag">&lt;/td></span>
<span class="code-tag">&lt;td></span>
<span class="code-tag">&lt;s:property value=<span class="code-quote">"lastName"</span> /></span>
<span class="code-tag">&lt;/td></span>
<span class="code-tag">&lt;td></span>
<span class="code-tag">&lt;s:url id=<span class="code-quote">"removeUrl"</span> action=<span class="code-quote">"remove"</span>></span>
<span class="code-tag">&lt;s:param name=<span class="code-quote">"id"</span> value=<span class="code-quote">"id"</span> /></span>
<span class="code-tag">&lt;/s:url></span>
<span class="code-tag">&lt;s:a href=<span class="code-quote">"%{removeUrl}"</span> theme=<span class="code-quote">"ajax"</span> targets=<span class="code-quote">"persons"</span>></span>Remove<span class="code-tag">&lt;/s:a></span>
<span class="code-tag">&lt;s:a id=<span class="code-quote">"a_%{id}"</span> theme=<span class="code-quote">"ajax"</span> notifyTopics=<span class="code-quote">"/edit"</span>></span>Edit<span class="code-tag">&lt;/s:a></span>
<span class="code-tag">&lt;/td></span>
<span class="code-tag">&lt;/tr></span>
<span class="code-tag">&lt;/s:iterator></span>
<span class="code-tag">&lt;/table></span>
<span class="code-tag">&lt;/s:if></span></pre>
</div>
</div>
<p>This is going to render a table with each row showing the first and last name
of the person, a link to remove the person, and a link to edit. The remove link
has the attribute "targets", set to "persons", which means that when the user
clicks on it, an asynchronous request will be made to the "remove" action (as
configured on struts.xml, "remove" points to the "remove" method in
PersonAction), passing the person id as parameter.</p>
<p>When the edit link is clicked on, it will publish the "/edit" topic, which
will trigger a javascript function to populate the fields.</p>
<ol>
    <li>Create a new file named "index.jsp" under /WebContent and set its content
    to: </li>
</ol>
<div class="code">
<div class="codeHeader"><strong>index.jsp</strong></div>
<div class="codeContent">
<pre class="code-html"><span class="code-tag">&lt;%@ taglib prefix=<span class="code-quote">"s"</span> uri=<span class="code-quote">"/struts-tags"</span>%></span>
<span class="code-tag">&lt;html></span>
<span class="code-tag">&lt;head></span>
<span class="code-tag">&lt;s:head theme=<span class="code-quote">"ajax"</span> debug=<span class="code-quote">"true"</span>/></span>
<span class="code-tag">&lt;script type=<span class="code-quote">"text/javascript"</span>></span>
dojo.event.topic.subscribe(<span class="code-quote">"/save"</span>, function(data, type, request) {
if(type == <span class="code-quote">"load"</span>) {
dojo.byId(<span class="code-quote">"id"</span>).value = "";
dojo.byId(<span class="code-quote">"firstName"</span>).value = "";
dojo.byId(<span class="code-quote">"lastName"</span>).value = "";
}
});
dojo.event.topic.subscribe(<span class="code-quote">"/edit"</span>, function(data, type, request) {
if(type == <span class="code-quote">"before"</span>) {
var id = data.split(<span class="code-quote">"_"</span>)[1];
var tr = dojo.byId(<span class="code-quote">"row_"</span>+id);
var tds = tr.getElementsByTagName(<span class="code-quote">"td"</span>);
dojo.byId(<span class="code-quote">"id"</span>).value = id;
dojo.byId(<span class="code-quote">"firstName"</span>).value = dojo.string.trim(dojo.dom.textContent(tds[0]));
dojo.byId(<span class="code-quote">"lastName"</span>).value = dojo.string.trim(dojo.dom.textContent(tds[1]));
}
});
<span class="code-tag">&lt;/script></span>
<span class="code-tag">&lt;/head></span>
<span class="code-tag">&lt;body></span>
<span class="code-tag">&lt;s:url action=<span class="code-quote">"list"</span> id=<span class="code-quote">"descrsUrl"</span>/></span>
<span class="code-tag">&lt;div style=<span class="code-quote">"width: 300px;border-style: solid"</span>></span>
<span class="code-tag">&lt;div style=<span class="code-quote">"text-align: right;"</span>></span>
<span class="code-tag">&lt;s:a theme=<span class="code-quote">"ajax"</span> notifyTopics=<span class="code-quote">"/refresh"</span>></span>Refresh<span class="code-tag">&lt;/s:a></span>
<span class="code-tag">&lt;/div></span>
<span class="code-tag">&lt;s:div id=<span class="code-quote">"persons"</span> theme=<span class="code-quote">"ajax"</span> href=<span class="code-quote">"%{descrsUrl}"</span> loadingText=<span class="code-quote">"Loading..."</span> listenTopics=<span class="code-quote">"/refresh"</span>/></span>
<span class="code-tag">&lt;/div></span>
<span class="code-tag">&lt;br/></span>
<span class="code-tag">&lt;div style=<span class="code-quote">"width: 300px;border-style: solid"</span>></span>
<span class="code-tag">&lt;p></span>Person Data<span class="code-tag">&lt;/p></span>
<span class="code-tag">&lt;s:form action=<span class="code-quote">"save"</span> validate=<span class="code-quote">"true"</span>></span>
<span class="code-tag">&lt;s:textfield id=<span class="code-quote">"id"</span> name=<span class="code-quote">"person.id"</span> cssStyle=<span class="code-quote">"display:none"</span>/></span>
<span class="code-tag">&lt;s:textfield id=<span class="code-quote">"firstName"</span> label=<span class="code-quote">"First Name"</span> name=<span class="code-quote">"person.firstName"</span>/></span>
<span class="code-tag">&lt;s:textfield id=<span class="code-quote">"lastName"</span> label=<span class="code-quote">"Last Name"</span> name=<span class="code-quote">"person.lastName"</span>/></span>
<span class="code-tag">&lt;s:submit theme=<span class="code-quote">"ajax"</span> targets=<span class="code-quote">"persons"</span> notifyTopics=<span class="code-quote">"/save"</span>/></span>
<span class="code-tag">&lt;/s:form></span>
<span class="code-tag">&lt;/div></span>
<span class="code-tag">&lt;/body></span>
<span class="code-tag">&lt;/html></span></pre>
</div>
</div>
<p>Look mom no page refresh!<br />
The div "persons" will load its content
asynchronously, and will show "Loading..." while while the request is on
progress (you can use the "indicator" attribute for better progress feedback),
you can force it to refresh clicking on the "Refresh" link. The "submit" button,
will make an asynchronous request to the action "save" ("save" method on
PersonAction), and will publish the topic "/save" to which we subscribed to,
using "dojo.event.topic.subscribe", to clear the input fields.</p>
<h3><a name="Struts2%2BSpring2%2BJPA%2BAJAX-Validation" style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); "></a>Validation</h3>
<p>Because we don't want any John Doe on our database, we will add some basic
client side validation to our form. In Struts 2, validation can be placed on xml
files with the name pattern ActionName-validation.xml, located on the same
package as the action. To add validation to an specific alias of an action (like
a method), the validation file name follows the pattern
ActionName-alias-validation.xml, where "alias" is the action alias name (in this
case a method name, "save"). Add a file named "PersonAction-save-validation.xml"
under /src/quickstart/action, and set its content to:</p>
<div class="code">
<div class="codeContent">
<pre class="code-xml">&lt;!DOCTYPE validators PUBLIC
<span class="code-quote">"-//OpenSymphony Group//XWork Validator 1.0//EN"</span>
<span class="code-quote">"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"</span>>
<span class="code-tag">&lt;validators></span>
<span class="code-tag">&lt;field name=<span class="code-quote">"person.firstName"</span>></span>
<span class="code-tag">&lt;field-validator type=<span class="code-quote">"requiredstring"</span>></span>
<span class="code-tag">&lt;message></span>First name is required!<span class="code-tag">&lt;/message></span>
<span class="code-tag">&lt;/field-validator></span>
<span class="code-tag">&lt;/field></span>
<span class="code-tag">&lt;field name=<span class="code-quote">"person.lastName"</span>></span>
<span class="code-tag">&lt;field-validator type=<span class="code-quote">"requiredstring"</span>></span>
<span class="code-tag">&lt;message></span>Last name is required!<span class="code-tag">&lt;/message></span>
<span class="code-tag">&lt;/field-validator></span>
<span class="code-tag">&lt;/field></span>
<span class="code-tag">&lt;/validators></span></pre>
</div>
</div>
<p>See the Struts documentation for details on existing validators, and how to
write, and plug in, your own validators.</p>
<p>To run the project, Right click on your project and Run As -> Run on
Server. You can debug it on the same way, Right click on the project and Debug
As -> Debug on Server. Download and install Struts 2 Showcase to see more
examples.</p>
<img src ="http://www.blogjava.net/yifeng/aggbug/245592.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yifeng/" target="_blank">忆风</a> 2008-12-11 00:55 <a href="http://www.blogjava.net/yifeng/archive/2008/12/11/245592.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JSTL经常用法</title><link>http://www.blogjava.net/yifeng/archive/2008/11/21/241780.html</link><dc:creator>忆风</dc:creator><author>忆风</author><pubDate>Thu, 20 Nov 2008 17:47:00 GMT</pubDate><guid>http://www.blogjava.net/yifeng/archive/2008/11/21/241780.html</guid><wfw:comment>http://www.blogjava.net/yifeng/comments/241780.html</wfw:comment><comments>http://www.blogjava.net/yifeng/archive/2008/11/21/241780.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yifeng/comments/commentRss/241780.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yifeng/services/trackbacks/241780.html</trackback:ping><description><![CDATA[<div class="postDetail" id="detail8a8181871d9741c3011db2c3be0071b4">
<div class="font5" id="upfile8a8181871d9741c3011db2c3be0071b4" style="display: none"></div>
<p>JavaServer Pages Standard Tag Libray(1.1),其中文名字为JSP标准标签函数库。JSTL是一个标准的已<br />
制定好的标签库，可以应用于各种领域，如:基本输入输出，流程控制，循环，XML文件剖析，数据库查<br />
询以及国际化和文字格式标准化的应用等。JSTL所提供的标签库分为以下五大类:<br />
核心标签库(Core tag Liabry)主要有:基本输入输出，流程控制，迭代操作和URL操作。<br />
在JSP中使用JSTL中的标签库时，必须使用&lt;<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#37;&#64;&#116;&#97;&#103;&#108;&#105;&#98;&#37;">%@taglib%</a>&gt;指令，并且设定prefix和uri的值得，通常设定:<br />
&lt;<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#37;&#64;&#116;&#97;&#103;&#108;&#105;&#98;">%@taglib</a> prefix="c" uri="<a href='http://java.sun.com/jsp/jstl/core"%' href_cetemp='http://java.sun.com/jsp/jstl/core"%'>http://java.sun.com/jsp/jstl/core"%</a>&gt;<br />
这样就可以使用核心标签库了。</p>
<p>.表达式操作<br />
表达式操作分类中包含四个标签: &lt;c:out&gt;,&lt;c:set&gt;,&lt;c:remove&gt;和&lt;c:catch&gt;<br />
&lt;c:out&gt;：重要用来显示数据的内容，类似与&lt;%=s.c.r.i.p.ting-language%&gt;。它的语法如下:<br />
语法1: 没有body内容<br />
&lt;c:out value="value" [escapeXml="{true|false}"] [default="defaultValue"]/&gt;</p>
<p>语法2: 有body内容<br />
&lt;c:out value="value"&nbsp;&nbsp; [escapeXml="{true|false}"]&gt;<br />
&nbsp;&nbsp; default value<br />
&lt;/c:out&gt;</p>
<p>Attribute<br />
-----------------------------------------------------------------------------------------------------------------------<br />
名称&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 说明&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类型&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 必须&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 默认值<br />
value&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 需要显示的值&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object&nbsp;&nbsp;&nbsp;&nbsp; 是&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 无<br />
default&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果value值为null,则显示default的值&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object&nbsp;&nbsp;&nbsp;&nbsp; 否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 无<br />
escapeXml&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 是否转换特殊字符，如: &lt;转换为&amp;It&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object&nbsp;&nbsp;&nbsp;&nbsp; 否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; true<br />
----------------------------------------------------------------------------------------------------------------------<br />
Null和错误说明<br />
假若value为null,会显示default的值；假若没有设定default的值，则会显示一个空的字符串。</p>
<p>&lt;c:set&gt;:主要用来把变量存储至JSP范围或是JavaBean的属性中。<br />
语法1: 没有body<br />
将value的值存储至范围为scope的varName变量之中<br />
&lt;c:set value="value" var="varName" [scope="{page|request|session|application}"]/&gt;</p>
<p>语法2: 有body<br />
将body内容存储至范围为scope的varName变量之中<br />
&lt;c:set value="value" [scope="{page|request|session|application}"]&gt;<br />
&nbsp;&nbsp; body.....<br />
&lt;/c:set&gt;</p>
<p>语法3: 将value的值存储至target对象属性中<br />
&lt;c:set value="value" target="target" property="propertyNmae"/&gt;</p>
<p>语法4: 将body内容的数据存储至target对象属性中<br />
&lt;c:set target="target" property="propertyNmae"&gt;<br />
body....<br />
&lt;/c:set&gt;</p>
<p>Attribute<br />
----------------------------------------------------------------------------------------<br />
名称&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 说明&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类型&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 必须&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 默认值<br />
value&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 要被存储的值&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 无<br />
var&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 欲存入的变量名&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; N&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 无<br />
scope&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var变量的JSP范围&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; N&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; page<br />
target&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 为一JavaBean或java.util.Map对象&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 无<br />
property&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 指定target对象属性&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 无<br />
------------------------------------------------------------------------------------------<br />
Null 和 错误处理:<br />
语法3和语法4会产生异常错误,有以下两种情况:<br />
.target 为null<br />
.target 不是java.util.Map或JavaBean对象<br />
假若value为null时:将由存储变量改为移除变量<br />
.语法1: 由var和scope所定义的变量，将被移除<br />
&nbsp;&nbsp;&nbsp;&nbsp; .若scope已指定时，则PageContext.removeAttribute(varName,scope);<br />
&nbsp;&nbsp;&nbsp;&nbsp; .若scope未指定时，则PageContext.removeAttribute(varName);<br />
.语法3: <br />
&nbsp;&nbsp;&nbsp;&nbsp; .假若target为Map时，则Map.remove(property);<br />
&nbsp;&nbsp;&nbsp;&nbsp; .假若target为JavaBean时，propertye指定的属性为null<br />
注意: var和scope这两个属性不能使用表达式来表示，我们不能写成 scope="${ourScope}"或var="${a}"</p>
<p>&lt;c:remove&gt;:主要用来移除变量。<br />
语法:<br />
&lt;c:remove var="varName" [scope="{page|request|session|application}"]/&gt;</p>
<p>Attribute<br />
----------------------------------------------------------------------------------------<br />
名称&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 说明&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类型&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 必须&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 默认值<br />
var&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 欲移除变量的名称&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; N&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 是&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 无<br />
scope&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var变量的JSP范围&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; N&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; page<br />
----------------------------------------------------------------------------------------<br />
说明:<br />
&lt;c:remove&gt;必须要有var属性，即要被移除的属性名称，scope则可有可无，如:<br />
&lt;c:remove var="username" scope="session"/&gt;<br />
将username变量从session范围移除。若我们不设定scope，则&lt;c:remove&gt;会移除所有范围名称为username<br />
的数据。</p>
<p>&lt;c:catch&gt;:主要用来处理产生错误的异常情况，并且将信息保存起来。<br />
语法:<br />
&lt;c:catch [var="varName"]&gt;<br />
...欲抓取错误的部分...<br />
&lt;/c:catch&gt;</p>
<p>Attribute<br />
----------------------------------------------------------------------------------------<br />
名称&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 说明&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类型&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 必须&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 默认值<br />
var&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用来存储错误信息的变量&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; N&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 无<br />
-----------------------------------------------------------------------------------------<br />
说明:<br />
&lt;c:catch&gt;主要将可能发生错误的部分放在&lt;c:catch&gt;和&lt;/c:catch&gt;之间。如果真的发生错误，可将错误<br />
信息保存至变量varName标量中，如:<br />
&lt;c:catch var="message"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; //可能发生错误的部分<br />
&lt;/catch&gt;<br />
另外，当错误发生&lt;c:catch&gt;和&lt;/c:catch&gt;之间时，只有&lt;c:catch&gt;和&lt;/c:catch&gt;之间的程序会被中止忽<br />
略，但整个网页不会被中止。</p>
<p>流程控制<br />
流程控制分类中包含四个标签:&lt;c:if&gt;,&lt;c:choose&gt;,&lt;c:when&gt;和&lt;c:otherwise&gt;。</p>
<p>&lt;c:if&gt;:的用途和我们在一般程序中写的if一样。<br />
语法:<br />
语法1：没有body<br />
&lt;c:if test="testCondition" var="varName" [scope="{page|request|session|application}"]/&gt;</p>
<p>语法2: 有body<br />
&lt;c:if test="testCondition" [var="varName"] [scope="{page|request|session|appliation}"]&gt;<br />
&nbsp;&nbsp; ...body....<br />
&lt;/c:if&gt;</p>
<p>Attribute<br />
------------------------------------------------------------------------------------------------------------------------<br />
名称&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 说明&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类型&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 必须&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 默认值<br />
test&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果表达式的结果为true则执行body,false则相反&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boolean&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 是&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 无<br />
var&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用来存储test运算后的结果，即true或false&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; N&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 无<br />
scope&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var变量的JSP范围&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; N&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; page<br />
------------------------------------------------------------------------------------------------------------------------<br />
说明:<br />
&lt;c:if&gt;标签必须要有test属性，body里除了能是静态文本之外可以是任何JSP代码，标签或HTML代码。</p>
<p>&lt;c:choose&gt;:本身只当作&lt;c:when&gt;和&lt;c:otherwise&gt;的父标签。<br />
语法:<br />
&lt;c:choose&gt;<br />
&nbsp;&nbsp; body(&lt;when&gt;和&lt;otherwise&gt;)<br />
&lt;/c:choose&gt;<br />
限制:<br />
&lt;c:choose&gt;的本地内容只能有:<br />
.空白<br />
.1或多个&lt;c:when&gt;<br />
.0或多个&lt;c:otherwise&gt;<br />
如:<br />
&lt;c:choose&gt;</p>
<p>&lt;c:when test="${condition1}"&gt;<br />
&nbsp;&nbsp;&nbsp; condition1 为 true<br />
&lt;/c:when&gt;</p>
<p>&lt;c:when test="${condition2}"&gt;<br />
&nbsp;&nbsp;&nbsp; condition2 为 true<br />
&lt;/c:when&gt;</p>
<p>&lt;c:otherwise&gt;<br />
&nbsp;&nbsp;&nbsp; condition1和conditon2都为false<br />
&lt;/&lt;c:otherwise &gt;<br />
<br />
&lt;/c:choose&gt;<br />
说明:<br />
在同一个&lt;c:choose&gt;中，假如所有的&lt;c:when&gt;的test都不为true时，则执行&lt;c:otherwise&gt;的本体内容。<br />
在同一个&lt;c:choose&gt;中，假若有好几个&lt;c:when&gt;都会true时，只能有一个&lt;c:when&gt;成立。</p>
<p>迭代操作<br />
迭代(Iterator)操作主要包含两个标签: &lt;c:forEach&gt;和&lt;c:forTokens&gt;。</p>
<p>&lt;c:forEach&gt;为循环控制，它可以将集合(Collection)中的成员循序浏览一遍。运做方式为当条件符合<br />
时，就会持续重复执行&lt;c:forEach&gt;的body内容。<br />
语法:<br />
语法1: 迭代一集合对象之所有成员<br />
&lt;c:forEach [var="varName"] items="collection" [varStatus="varStatusName"]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [begin="begin"] [end="end"] [step="step"]&gt;<br />
...body内容.....<br />
&lt;c:forEach&gt;</p>
<p>语法2: 迭代指定的次数<br />
&lt;c:forEach [var="varName"] [varStatus="varStatusName"]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; begin="begin" end="end" [step="step"]&gt;<br />
...body内容.....<br />
&lt;c:forEach&gt;</p>
<p>Attribute<br />
--------------------------------------------------------------------------------------------------------------------------<br />
名称&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 说明&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类型&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 必须&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 默认值<br />
var&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用来存放现在指到的成员&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; N&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 无</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Arrays<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Collection<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Iterator&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 无<br />
items&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 被迭代的集合对象&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Enumeration&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Map<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String</p>
<p>varStatus&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用来存放到指到的相关成员信息&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; N&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 无<br />
begin&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 开始的位置&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0<br />
end&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 结束的位置&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最后一个成员<br />
setp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 每次迭代的间隔数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<br />
-------------------------------------------------------------------------------------------------------------------------<br />
Null 和 错误处理<br />
.假若items为null时，则表示为一空的集合对象<br />
.假若begin大于或等于items时，则迭代不运算<br />
注意:<br />
varName的范围只存在&lt;c:forEach&gt;的本体中，如果超出了本题，则不能取得varName的值。如:<br />
&lt;c:forEach items="${atts}" var="item"&gt;<br />
&lt;/c:forEach&gt;<br />
${item}&lt;/br&gt;<br />
${item}则不会显示item的内容。&lt;c:forEach&gt;除了支持数组之外，还有标准的J2SE的结合类型，例如:<br />
ArrayList,List,LinkedList,Vector,Stack和Set等等；另外包括java.util.Map类的对象，例如:<br />
HashMap,Hashtable,Properties,Provider和Attributes。</p>
<p>另外&lt;c:forEach&gt;还提供了varStatus属性，主要用来存放现在指到成员的相关信息。例如：我们写成<br />
varStatus="s",那么就会把信息存放到名称为s的属性当中。varStatus属性还提供另外四个属性:index,<br />
count,fist和last，它们个自的意义如下:<br />
------------------------------------------------------------------------------------------<br />
&nbsp;&nbsp;&nbsp; 属性&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类型&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 意义<br />
&nbsp;&nbsp;&nbsp; index&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; number&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 现在指到成员的索引<br />
&nbsp;&nbsp;&nbsp; count&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; number&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 总共指到成员的总和<br />
&nbsp;&nbsp;&nbsp; first&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boolean&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 现在指到成员是否为第一个<br />
&nbsp;&nbsp;&nbsp; last&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boolean&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 现在指到成员是否为最后一个<br />
-------------------------------------------------------------------------------------------<br />
如下例子:<br />
&lt;<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#37;&#64;&#112;&#97;&#103;&#101;">%@page</a> contentType="text/html;charset=gb2312"%&gt;<br />
&lt;<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#37;&#64;&#116;&#97;&#103;&#108;&#105;&#98;">%@taglib</a> prefix="c" uri="<a href='http://java.sun.com/jsp/jstl/core"%' href_cetemp='http://java.sun.com/jsp/jstl/core"%'>http://java.sun.com/jsp/jstl/core"%</a>&gt;<br />
&lt;%<br />
String atts[] = new String[5];<br />
atts[0]="hello";<br />
atts[1]="this";<br />
atts[2]="is";<br />
atts[3]="a";<br />
atts[4]="girl";<br />
request.setAttritue("atts",atts);<br />
%&gt;<br />
&lt;c:forEach items="${atts}" var="item" varStatus="s"&gt;<br />
&lt;h2&gt;&lt;c:out value="${item}"/&gt;的四种属性&gt;&lt;/h2&gt;<br />
index: ${s.index}&lt;/br&gt;<br />
count: ${s.count}&lt;/br&gt;<br />
first: ${s.first}&lt;/br&gt;<br />
last:&nbsp;&nbsp; ${s.last}&lt;/br&gt; <br />
&lt;/c:forEach&gt;</p>
<p>&lt;c:forTokens&gt;<br />
&lt;c:forTokens&gt;:用来浏览一字符串中所有的成员，起成员是由定义符号(delimiters)所分隔的。<br />
语法:<br />
&lt;c:forTokens items="stringFoTokens" delims="delimmmmiters" [var="varName"]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [varStatus="varStatusName"] [begin="begin"] [end="end"] [step="step"]&gt;<br />
...body内容....<br />
&lt;/c:forTokens&gt;</p>
<p>Attribute<br />
--------------------------------------------------------------------------------------------------------------------<br />
名称&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 说明&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类型&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 必须&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 默认值<br />
var&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用来存放现在指到的成员&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 无<br />
items&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 被迭代的字符串&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 是&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 无<br />
delims&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 定义用来分割字符串的字符&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; N&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 是&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 无<br />
varStatus&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用来存放现在指到的相关成员信息&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; N&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 无<br />
begin&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 开始的位置&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0<br />
end&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 结束的位置&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最后一个成员<br />
step&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 每次迭代间隔数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<br />
---------------------------------------------------------------------------------------------------------------------<br />
限制:<br />
.假若有begin属性时，begin必须大于等于0<br />
.假若有end属性时，必须大于begin<br />
.假若有step属性时，step必须大于等于1</p>
<p>Null 和 错误处理<br />
.假如itmes为null时,则表示为有空的集合对象<br />
.假若begin大于等于items的大小时，则迭代不运算</p>
<p>例子:<br />
&lt;c:forToken items="A,B,C,D,E,F,G" delims="," var="item&gt;<br />
${item}<br />
&lt;/c:forToken&gt;<br />
items属性也可以用EL，例如:<br />
&lt;%<br />
String phonenumber="123-456-7899";<br />
request.setAttribute("userPhone",phonenumber);<br />
%&gt;<br />
&lt;c:forTokens items="${userPhone}" delims="-" var="item"&gt;<br />
${item}<br />
&lt;/c:forTokens&gt;</p>
<p>URL操作<br />
JSTL包含三个URL操作有关的标签,分别是: &lt;c:import&gt;,&lt;c:redirect&gt;和&lt;c:url&gt;。它们的主要功能是：<br />
用来将其他文件的内容包含起来，网页的向导，还有url的产生。</p>
</div>
<img src ="http://www.blogjava.net/yifeng/aggbug/241780.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yifeng/" target="_blank">忆风</a> 2008-11-21 01:47 <a href="http://www.blogjava.net/yifeng/archive/2008/11/21/241780.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Web在线编辑器</title><link>http://www.blogjava.net/yifeng/archive/2008/11/20/241520.html</link><dc:creator>忆风</dc:creator><author>忆风</author><pubDate>Wed, 19 Nov 2008 16:32:00 GMT</pubDate><guid>http://www.blogjava.net/yifeng/archive/2008/11/20/241520.html</guid><wfw:comment>http://www.blogjava.net/yifeng/comments/241520.html</wfw:comment><comments>http://www.blogjava.net/yifeng/archive/2008/11/20/241520.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yifeng/comments/commentRss/241520.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yifeng/services/trackbacks/241520.html</trackback:ping><description><![CDATA[<h1>一、网易编辑器用法演示</h1>
<h1><img height="334" alt="" src="http://www.blogjava.net/images/blogjava_net/yifeng/other/163HtmlEditor.JPG" width="723" border="0" /><br />
下载地址：<a title="163HtmlEditor.rar" href="/Files/yifeng/Repository/163HtmlEditor.rar">163HtmlEditor.rar</a><br />
<br />
二、新浪博客HtmlEditor在线编辑器<br />
<img height="465" alt="" src="http://www.blogjava.net/images/blogjava_net/yifeng/other/SinaEditor.JPG" width="635" border="0" /></h1>
<p>&nbsp;</p>
<p><font color="#ff6600"><strong><span style="color: #000000">调用： </span></strong></p>
<p><span style="color: #000000"><strong>&lt;input type="hidden" name="content" id="content"&gt;<br />
&lt;iframe src="Edit/editor.htm?id=content&amp;ReadCookie=0" frameBorder="0" marginHeight="0" marginWidth="0" scrolling="No" width="700" height="460"&gt;&lt;/iframe&gt;</strong></span></p>
<p><strong><span style="color: #000000">注意：id为调用参数(小写)，即隐藏的内容表单项id， ReadCookie设置是否读取上次未提交的数据，1为开启，0为关闭（注意大小写）。</span></strong></p>
<p><strong><span style="color: #000000">在上次修复的基础上增加了一个附件上传功能，但还是有几个不理想的地方。<br />
<br />
缺陷：<br />
1缺乏安全判断（上一版也有这个问题）<br />
2附件上传后，插入编辑器的样式很难看。<br />
3缺清除格式功能</span></strong></p>
<p><br />
</font>&nbsp;</p>
<p>下载地址：<a title="SinaEditor.rar" href="/Files/yifeng/Repository/SinaEditor.rar">SinaEditor.rar</a><br />
</p>
<h1><br />
三、FCKeditor<br />
<img height="249" alt="" src="http://www.blogjava.net/images/blogjava_net/yifeng/other/FCKeditor.JPG" width="898" border="0" /></h1>
<p>&nbsp;<strong>FCK的使用，参见地址：http://blog.csdn.net/qjyong/archive/2007/06/20/1658940.aspx</strong></p>
<img src ="http://www.blogjava.net/yifeng/aggbug/241520.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yifeng/" target="_blank">忆风</a> 2008-11-20 00:32 <a href="http://www.blogjava.net/yifeng/archive/2008/11/20/241520.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>中材技术数字信息管理系统界面</title><link>http://www.blogjava.net/yifeng/archive/2008/10/24/236290.html</link><dc:creator>忆风</dc:creator><author>忆风</author><pubDate>Thu, 23 Oct 2008 19:58:00 GMT</pubDate><guid>http://www.blogjava.net/yifeng/archive/2008/10/24/236290.html</guid><wfw:comment>http://www.blogjava.net/yifeng/comments/236290.html</wfw:comment><comments>http://www.blogjava.net/yifeng/archive/2008/10/24/236290.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/yifeng/comments/commentRss/236290.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yifeng/services/trackbacks/236290.html</trackback:ping><description><![CDATA[<img alt="" src="http://www.blogjava.net/images/blogjava_net/yifeng/projects/zcjslogin.PNG" border="0" /><br />
<br />
<br />
<img height="847" alt="" src="http://www.blogjava.net/images/blogjava_net/yifeng/projects/zcjs01.png" width="1013" border="0" /><br />
<br />
<br />
<br />
<img height="775" alt="" src="http://www.blogjava.net/images/blogjava_net/yifeng/projects/zcjs02.PNG" width="1190" border="0" />
<img src ="http://www.blogjava.net/yifeng/aggbug/236290.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yifeng/" target="_blank">忆风</a> 2008-10-24 03:58 <a href="http://www.blogjava.net/yifeng/archive/2008/10/24/236290.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>1亿动态pv/天的超级数据库缓存解决方案，开源了，还有测试代码。</title><link>http://www.blogjava.net/yifeng/archive/2008/10/12/233820.html</link><dc:creator>忆风</dc:creator><author>忆风</author><pubDate>Sat, 11 Oct 2008 18:57:00 GMT</pubDate><guid>http://www.blogjava.net/yifeng/archive/2008/10/12/233820.html</guid><wfw:comment>http://www.blogjava.net/yifeng/comments/233820.html</wfw:comment><comments>http://www.blogjava.net/yifeng/archive/2008/10/12/233820.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.blogjava.net/yifeng/comments/commentRss/233820.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yifeng/services/trackbacks/233820.html</trackback:ping><description><![CDATA[说是支持1亿pv/天，也许有点夸张，也是为了吸引您能点进来，如果您能认真看完相信也不会让您失望，当然，肯定有很多&#8220;高手&#8221;会对此会嗤之以鼻，没关系，有很多眼高手低的人总喜欢评论别人却从不会看清自己。 <br />
<br />
如果大家真想支持我、支持中国人开源项目，请把该文贴到自己的博客中或者收藏本文，记得包含文档的下载地址！！！！！！！谢谢。 <br />
<br />
我说的系统主要是构建在hibernate之上的高效数据库缓存系统，其中包含了分布式解决方案，该系统已经应用在舍得网上了，没有发现大问题，本人也相信该系统已经足够强大，应付数百万IP/天的应用都不是问题，我这么说肯定有人会对此表示怀疑，其实系统到底能撑多少IP/天不在于系统本身而是在于使用该系统的人。 <br />
<br />
代码看上去很简单，其实却是两年经验的总结，整过过程也遇到了很多难点，最后一一解决了，所以也请各位珍惜他人的劳动成果。本系统非常简洁易用，主程序BaseManager.java不到1000行代码，用&#8220;精悍&#8221;来形容绝对不为过，1000行代码却包含了数据库对象的缓存、列表和长度的缓存、按字段散列缓存、update延时更新、自动清除列表缓存等功能，用它来实现像论坛、博客、校友录、交友社区等绝大部分应用网站都足够了。 <br />
<br />
我在理想状态下做了压力测试，在没有数据库操作的jsp页面(舍得网新首页)里可以完成2000多requests每秒（正常情况可能有1/1000的request有数据库查询，其余999/1000都是直接从缓存里读取），物品详情页每秒可完成3000多requests，纯静态html页面也只能完成7000多requests/秒，我对首页进行了三个小时的压力测试，完成了24850800个requests，java一点事都没有，内存没有上涨。按照2000个requests/秒算，一天按15小时计算，那么每天能完成3600*15*2000=1亿零8百万requests，当然这是理想状态，实际状态就算打一折，还能完成1000万pv/天，要知道，这只是一个普通1万3千块钱买的服务器，内存4G，CPU2个，LinuxAS4系统，apache2.0.63/resin2.1.17/jdk6.0的环境。 <br />
<br />
现在进入正题。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 <br />
<br />
为什么要用缓存？如果问这个问题说明你还是新手，数据库吞吐量毕竟有限，每秒读写5000次了不起了，如果不用缓存，假设一个页面有100个数据库操作，50个用户并发数据库就歇菜，这样最多能支撑的pv也就50*3600*15=270万，而且数据库服务器累得半死，搞不好什么时候就累死了。我的这套缓存系统比单独用memcached做缓存还要强大，相当于在memcached上再做了两级缓存，大家都知道memcached很强了，但是吞吐量还是有限，每秒20000次get和put当遇到超大规模的应用时还是会歇菜，本地HashMap每秒可执行上百万次put和get，在这上面损耗的性能几乎可以忽略不记了。温馨提示：能不用分布式的时候就不要用分布式，非用分布式的时候再考虑用memcached，我的缓存系统在这方面都已经实现了，改个配置就可以了，有兴趣的可以仔细测试测试！ <br />
<br />
一般数据库缓存在我看来包含四种。第一种：单个对象的缓存（一个对象就是数据库一行记录），对于单个对象的缓存，用HashMap就可以了，稍微复杂一点用LRU算法包装一个HashMap，再复杂一点的分布式用memcached即可，没什么太难的；第二种：列表缓存，就像论坛里帖子的列表；第三种：长度的缓存，比如一个论坛板块里有多少个帖子，这样才方便实现分页。第四种：复杂一点的group，sum，count查询，比如一个论坛里按点击数排名的最HOT的帖子列表。第一种比较好实现，后面三种比较困难，似乎没有通用的解决办法，我暂时以列表缓存（第二种）为例分析。 <br />
<br />
mysql和hibernate的底层在做通用的列表缓存时都是根据查询条件把列表结果缓存起来，但是只要该表的记录有任何变化（增加/删除/修改），列表缓存要全部清除，这样只要一个表的记录经常变化（通常情况都会这样），列表缓存几乎失效，命中率太低了。 <br />
<br />
本人想了一个办法改善了列表缓存，当表的记录有改变时，遍历所有列表缓存，只有那些被影响到的列表缓存才会被删除，而不是直接清除所有列表缓存，比如在一个论坛版（id=1）里增加了一个帖子，那么只要清除id=1这个版对应的列表缓存就可以了，版id=2就不用清除了。这样处理有个好处，可以缓存各种查询条件（如等于、大于、不等于、小于）的列表缓存，但也有个潜在的性能问题，由于需要遍历，CPU符合比较大，如果列表缓存最大长度设置成10000，两个4核的CPU每秒也只能遍历完300多次，这样如果每秒有超过300个insert/update/delete，系统就吃不消了。 <br />
<br />
在前面两种解决办法都不完美的情况下，本人和同事经过几个星期的思索，总算得出了根据表的某几个字段做散列的缓存办法，这种办法无需大规模遍历，所以CPU符合非常小，由于这种列表缓存按照字段做了散列，所以命中率极高。思路如下：每个表有3个缓存Map（key=value键值对），第一个Map是对象缓存A，在A中，key是数据库的id，Value是数据库对象（也就是一行数据）；第二个Map是通用列表缓存B，B的最大长度一般1000左右，在B中，key是查询条件拼出来的String（如start=0,length=15#active=0#state=0），Value是该条件查询下的所有id组成的List；第三个Map是散列缓存C，在C中，key是散列的字段（如根据userId散列的话，其中某个key就是userId=109这样的String）组成的String，value是一个和B类似的HashMap。其中只有B这个Map是需要遍历的，不知道说明白了没有，看完小面这个例子应该就明白了，就用论坛的回复表作说明，假设回复表T中假设有字段id，topicId，postUserId等字段（topicId就是帖子的id，postUserId是发布者id）。 <br />
<br />
第一种情况，也是最常用的情况，就是获取一个帖子对应的回复，sql语句应该是象 <br />
select id from T where topicId=2008 order by createTime desc limit 0,5 <br />
select id from T where topicId=2008 order by createTime desc limit 5,5 <br />
select id from T where topicId=2008 order by createTime desc limit 10,5 <br />
的样子，那么这种列表很显然用topicId做散列是最好的，把上面三个列表缓存（可以是N个）都散列到key是topicId=2008这一个Map中，当id是2008的帖子有新的回复时，系统自动把key是topicId=2008的散列Map清除即可。由于这种散列不需要遍历，因此可以设置成很大，例如100000，这样10万个帖子对应的所有回复列表都可以缓存起来，当有一个帖子有新的回复时，其余99999个帖子对应的回复列表都不会动，缓存的命中率极高。 <br />
<br />
第二种情况，就是后台需要显示最新的回复，sql语句应该是象 <br />
select id from T order by createTime desc limit 0,50 <br />
的样子，这种情况不需要散列，因为后台不可能有太多人访问，常用列表也不会太多，所以直接放到通用列表缓存B中即可。 <br />
<br />
第三种情况，获取一个用户的回复，sql语句象 <br />
select id from T where userId=2046 order by createTime desc limit 0,15 <br />
select id from T where userId=2046 order by createTime desc limit 15,15 <br />
select id from T where userId=2046 order by createTime desc limit 30,15 <br />
的样子，那么这种列表和第一种情况类似，用userId做散列即可。 <br />
<br />
第四种情况，获取一个用户对某个帖子的回复，sql语句象 <br />
select id from T where topicId=2008 and userId=2046 order by createTime desc limit 0,15 <br />
select id from T where topicId=2008 and userId=2046 order by createTime desc limit 15,15 <br />
的样子，这种情况比较少见，一般以topicId=2008为准，也放到key是topicId=2008这个散列Map里即可。 <br />
<br />
总结：这种缓存思路可以存储大规模的列表，缓存命中率极高，因此可以承受超大规模的应用，但是需要技术人员根据自身业务逻辑来配置需要做散列的字段，一般用一个表的索引键做散列（注意顺序，最散的字段放前面），假设以userId为例，可以存储N个用户的M种列表，如果某个用户的相关数据发生变化，其余N-1个用户的列表缓存纹丝不动。以上说明的都是如何缓存列表，缓存长度和缓存列表思路完全一样，如缓存象select count(*) from T where topicId=2008这样的长度，也是放到topicId=2008这个散列Map中。如果再配合好使用mysql的内存表和memcached，加上F5设备做分布式负载均衡，该系统对付像1000万IP/天这种规模级的应用都足够了，除搜索引擎外一般的应用网站到不了这种规模。 <br />
<br />
<span style="color: #000000"><strong>再次申明：系统到底是不是强大不在系统本身而在于使用该系统的人！！！</strong></span> <br />
<br />
这个缓存系统是我和同事几年经验的总结，看似简单，其实也没那么简单，把它作为开源有下面几个目的：第一，真的希望有很多人能用它；第二：希望更多的人能够完善和改进它；第三：希望大家能聚到一起为通用高效数据库缓存构架作出贡献，毕竟，数据库操作是各种应用最常用的操作，也是最容易产生性能瓶颈的地方。 <br />
<br />
Zip包中包含了配置方法和测试用的jsp，只要把它配置成一个web应用就可以快速调试并看到缓存的力量了，文档和下载地址是<a href="http://shedewang.com/akaladocs/api/com/akala/dbcache/core/BaseManager.html" target="_blank">http://shedewang.com/akaladocs/api/com/akala/dbcache/core/BaseManager.html</a>。群组的地址是<a href="http://groups.csdn.net/shedewang_db_cache" target="_blank">http://groups.csdn.net/shedewang_db_cache</a> <br />
<br />
配置说明文件在docs/开始配置.txt里有说明。 <br />
<br />
最后啰嗦一句，如果大家真想支持我、支持中国人开源项目，请把该文贴到自己的博客中或者收藏本文，记得包含文档的下载地址！！！！！！！谢谢。thank you and Good luck。 <br />
<br />
QQ群：24561583 <br />
<br />
在CSDN里我就只管理这个帖子和群组里的帖子了，其余的地方就不发了。 <br />
<br />
<br />
出自：http://topic.csdn.net/u/20080724/09/6fe7d368-97ac-4de3-bc9a-ef6989903153.html<br />
 <img src ="http://www.blogjava.net/yifeng/aggbug/233820.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yifeng/" target="_blank">忆风</a> 2008-10-12 02:57 <a href="http://www.blogjava.net/yifeng/archive/2008/10/12/233820.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LDAP基础</title><link>http://www.blogjava.net/yifeng/archive/2008/09/21/230212.html</link><dc:creator>忆风</dc:creator><author>忆风</author><pubDate>Sat, 20 Sep 2008 18:40:00 GMT</pubDate><guid>http://www.blogjava.net/yifeng/archive/2008/09/21/230212.html</guid><wfw:comment>http://www.blogjava.net/yifeng/comments/230212.html</wfw:comment><comments>http://www.blogjava.net/yifeng/archive/2008/09/21/230212.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yifeng/comments/commentRss/230212.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yifeng/services/trackbacks/230212.html</trackback:ping><description><![CDATA[一、Directory&nbsp;<wbr>Services(目录服务)能做什么？<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>我们知道，当局域网的规模变的越来越大时，为了方便主机管理，我们使用DHCP来实现IP地址、以太网地址、主机名和拓扑结构等的集中管理和统一分配。同样，如果一个局域网内有许多的其它资源时，如打印机、共享文件夹等等，为了方便的定位及查找它们，一种集中定位管理的方式或许是较好的选择，DNS和NIS都是用来实现类似管理的方法。<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>对于局域网内的一个用户来讲，工作等其它应用需要，我们必须凭帐号登录主机、用帐号收发E-mail，甚至为了管理需要公司还需要维护一个电子号码簿来存储员工的姓名、地址、电话号码等信息。随着时间的增长，我们会为这些越来越多的帐号和密码弄的头晕脑胀。同时，如果一个员工离开，管理员就不得不翻遍所有的记录帐号信息的文件把离职员工的信息删除。这些将是一个繁琐而效率低下的工作。那么，如果能将此些帐号信息等统一到一个文件中进行管理，无疑会大大提高员工及管理员的工作效率。目录服务（LDAP是其实现的一种）正是基于这些应用实现的。<br />
<br />
二、什么是LDAP？<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>LDAP是Lightweight&nbsp;<wbr>Directory&nbsp;<wbr>Access&nbsp;<wbr>Protocol的缩写，顾名思义，它是指轻量级目录访问协议（这个主要是相对另一目录访问协议X.500而言的；LDAP略去了x.500中许多不太常用的功能，且以TCP/IP协议为基础）。目录服务和数据库很类似，但又有着很大的不同之处。数据库设计为方便读写，但目录服务专门进行了读优化的设计，因此不太适合于经常有写操作的数据存储。同时，LDAP只是一个协议，它没有涉及到如何存储这些信息，因此还需要一个后端数据库组件来实现。这些后端可以是bdb(BerkeleyDB)、ldbm、shell和passwd等。<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>LDAP目录以树状的层次结构来存储数据（这很类同于DNS），最顶层即根部称作&#8220;基准DN&#8221;，形如"dc=mydomain,dc=org"或者"o=mydomain.org"，前一种方式更为灵活也是Windows&nbsp;<wbr>AD中使用的方式。在根目录的下面有很多的文件和目录，为了把这些大量的数据从逻辑上分开，LDAP像其它的目录服务协议一样使用OU（Organization&nbsp;<wbr>Unit），可以用来表示公司内部机构，如部门等，也可以用来表示设备、人员等。同时OU还可以有子OU，用来表示更为细致的分类。<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>LDAP中每一条记录都有一个唯一的区别于其它记录的名字DN（Distinguished&nbsp;<wbr>Name）,其处在&#8220;叶子&#8221;位置的部分称作RDN；如dn:cn=tom,ou=animals,dc=mydomain,dc=org中tom即为RDN；RDN在一个OU中必须是唯一的。<br />
<br />
三、什么是LDIF？<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>LDIF(LDAP&nbsp;<wbr>Interchange&nbsp;<wbr>Format)是指存储LDAP配置信息及目录内容的标准文本文件格式，之所以使用文本文件来格式来存储这些信息是为了方便读取和修改，这也是其它大多数服务配置文件所采取的格式。LDIF文件常用来向目录导入或更改记录信息，这些信息需要按照LDAP中schema的格式进行组织，并会接受schema的检查，如果不符合其要求的格式将会出现报错信息。LDIF文件样例如下：<br />
<br />
#LDIF&nbsp;<wbr>file&nbsp;<wbr>example<br />
dn:&nbsp;<wbr>dc=mydomain,dc=org<br />
objectClass:&nbsp;<wbr>domain<br />
dc:&nbsp;<wbr>mydomain<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>其中，以&#8220;#&#8221;号开头的为注释行；第二行起的行中，冒号左边为属性，右边是属性的值，这类同于编程中的变量及为其所赋的值，但属性可以被重复赋值。<br />
<br />
四、objectClass&nbsp;<wbr><br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>LDAP中，一条记录必须包含一个objectClass属性，且其需要赋予至少一个值。每一个值将用作一条LDAP记录进行数据存储的模板；模板中包含了一条记录中数个必须被赋值的属性和一系列可选的属性。如上述LDIF文件中的记录所示，objectClass的值为domain。<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>objectClass有着严格的等级之分，最顶层的类是top和alias。例如，organizationalPerson这个objectClass隶属于Person,而Person又是top的子类。<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>objectClass大致分为三类：结构型的（如：person和organizationUnit）、辅助型的（如：extensibeObject）和抽象型的（这类不能直接使用）。官方定义的objectClass,如下所示：<br />
<br />
alias&nbsp;<wbr><br />
applicationEntity&nbsp;<wbr><br />
dSA&nbsp;<wbr><br />
applicationProcess&nbsp;<wbr><br />
bootableDevice&nbsp;<wbr><br />
certificationAuthority&nbsp;<wbr><br />
certificationAuthority-V2&nbsp;<wbr><br />
country&nbsp;<wbr><br />
cRLDistributionPoint&nbsp;<wbr><br />
dcObject&nbsp;<wbr><br />
device&nbsp;<wbr><br />
dmd&nbsp;<wbr><br />
domain&nbsp;<wbr><br />
domainNameForm&nbsp;<wbr><br />
extensibleObject&nbsp;<wbr><br />
groupOfNames&nbsp;<wbr><br />
groupOfUniqueNames&nbsp;<wbr><br />
ieee802Device&nbsp;<wbr><br />
ipHost&nbsp;<wbr><br />
ipNetwork&nbsp;<wbr><br />
ipProtocol&nbsp;<wbr><br />
ipService&nbsp;<wbr><br />
locality&nbsp;<wbr><br />
dcLocalityNameForm&nbsp;<wbr><br />
nisMap&nbsp;<wbr><br />
nisNetgroup&nbsp;<wbr><br />
nisObject&nbsp;<wbr><br />
oncRpc&nbsp;<wbr><br />
organization&nbsp;<wbr><br />
dcOrganizationNameForm&nbsp;<wbr><br />
organizationalRole&nbsp;<wbr><br />
organizationalUnit&nbsp;<wbr><br />
dcOrganizationalUnitName<wbr>Form&nbsp;<wbr><br />
person&nbsp;<wbr><br />
organizationalPerson&nbsp;<wbr><br />
inetOrgPerson&nbsp;<wbr><br />
uidOrganizationalPersonN<wbr>ameForm&nbsp;<wbr><br />
residentialPerson&nbsp;<wbr><br />
posixAccount&nbsp;<wbr><br />
posixGroup&nbsp;<wbr><br />
shadowAccount&nbsp;<wbr><br />
strongAuthenticationUser<wbr>&nbsp;<wbr><br />
uidObject&nbsp;<wbr><br />
userSecurityInformation<br />
<br />
五、Attribute介绍<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>如上文所述，Attribute类同于编程语言中的变量，它可以被赋值，就像是可以存放一个单一类型信息的容器。官方声明了许多常用的Attribute,如果其中没有你所需要的，你可以自己定义，但要避免重名。objectClass是一种特殊的Attribute，它包含其它用到的Attribute以及它自身。常见的Attribute如：givenName、l、objectClass、dc、ou、cn、c、mail、telephoneNumber、sn、uid等。分别介绍如下：<br />
<br />
c:国家；<br />
cn:common&nbsp;<wbr>name,指一个对象的名字；如果指人，需要使用其全名；<br />
dc:domain&nbsp;<wbr>Component,经常用来指一个域名的一部分，如：dc=mydomain,dc=org;<br />
givenName：指一个人的名字，不能用来指姓或者middle&nbsp;<wbr>name；<br />
l:指一个地名，如一个城市或者其它地理区域的名字；<br />
mail:电子信箱地址<br />
o:organizationName,指一个组织的名字;<br />
objectClass:一个LDAP&nbsp;<wbr>server要想启用必须能够识别每一个对象的Attribute，objectClass&nbsp;<wbr>Attribute正是用来描述一个对象应该具有的Attribute及可选Attribute。因此，每个objectClass&#8220;模板&#8221;的Attribute中必然含有一条objectClass&nbsp;<wbr>Attribute，我不知道用&#8220;自包含&#8221;称呼这个算不算合适。<br />
ou:organizationalUnitName,指一个组织单元的名字。<br />
sn:surname,指一个人的姓;<br />
telephoneNumber:电话号码，应该带有所在的国家的代码；<br />
uid:userid,通常指一个人的登录名，这个不同于Linux系统中用户的uid；&nbsp;<wbr><br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>如果可以这样类比的话，我想，我们不妨把objectClass理解为关系数据库的表，而attribute则类同为表中的字段。而下面即可介绍的schema或许可以类比作一个数据库，但它的这个类比或许从逻辑上说更合适些。<br />
<br />
六、什么是schema<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>好了，现在可以说说到底什么是schema了。LDAP中，schema用来指定一个目录中所包含的objects的类型（objectClass）以及每一个objectClass中的各个必备（mandatory）和可选（optional）的属性（attribute）。因此，[color=Orange]Schema是一个数据模型，它被用来决定数据怎样被存储，被跟踪的数据的是什么类型，存储在不同的Entry下的数据之间的关系。[/color]schema需要在主配置文件slapd.conf中指定，以用来决定本目录中使用到的objectClass。管理员可以自己设计制定schema，一般包括属性定义（AttributeDefinition）、类定义（ClassDefinition）以及语法定义（SyntaxDefinition）等部分。&nbsp;<wbr>&nbsp;<wbr><br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>LDAP&nbsp;<wbr>V3中在x.500标准的基础上定义了一个包含了网络中大多常见对象的schema，这些对象包括国家、所在地、组织、人员、小组以及设备等。同时，LDAP&nbsp;<wbr>V3中可以很方便的从目录中提取出schema，它正是一条记录中关于属性的声明部分。<br />
<br />
七、对象标识符（Object&nbsp;<wbr>Identifiers）<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>对象标识符（OID）是被LDAP内部数据库引用的数字标识。Attribute的名字是设计为方便人们读取的，但为了方便计算机的处理，通常使用一组数字来标识这些对象，这类同于SNMP中的MIB2。例如，当计算机接收到dc这个Attribute时，它会将这个名字转换为对应的OID：1.3.6.1.4.1.1466.115.121.1.26。<br />
<br />
<br />
八、使用LDAP做身份验正<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>验正主要是用来确定一次会主中客户端用户所具有的权利，即用来确立用户能否登录以及登录具有使用哪些资源以及如何使用资源的权限。验正过程中的修改、查询等操作由认证级别来控制。<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>objectClass中的person可以用来作linux系统中用户登入的身份验正，此时需要指定userPassword属性的值，即指定用户登入时使用的密码。密码可以使用的加密方式有MD5、CRYPT、SHA、SSHA等。在LDAP&nbsp;<wbr>V3中，验正客户端时可以使用的验正机制有匿名验正、简单验正、基于SSL/TLS的验正和基于SASL的验正等四种方式。<br />
<img src ="http://www.blogjava.net/yifeng/aggbug/230212.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yifeng/" target="_blank">忆风</a> 2008-09-21 02:40 <a href="http://www.blogjava.net/yifeng/archive/2008/09/21/230212.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LDAP介绍（转）</title><link>http://www.blogjava.net/yifeng/archive/2008/09/21/230203.html</link><dc:creator>忆风</dc:creator><author>忆风</author><pubDate>Sat, 20 Sep 2008 16:50:00 GMT</pubDate><guid>http://www.blogjava.net/yifeng/archive/2008/09/21/230203.html</guid><wfw:comment>http://www.blogjava.net/yifeng/comments/230203.html</wfw:comment><comments>http://www.blogjava.net/yifeng/archive/2008/09/21/230203.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yifeng/comments/commentRss/230203.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yifeng/services/trackbacks/230203.html</trackback:ping><description><![CDATA[<div>1.&nbsp;<wbr>LDAP介绍&nbsp;<wbr>4<br />
1.1.&nbsp;<wbr>LDAP是什么&nbsp;<wbr>4<br />
1.2.&nbsp;<wbr>LDAP是电话簿&nbsp;<wbr>4<br />
1.3.&nbsp;<wbr>LDAP是不是数据库&nbsp;<wbr>4</div>
<div>2.&nbsp;<wbr>LDAP的特点&nbsp;<wbr>5<br />
2.1.&nbsp;<wbr>LDAP的优势&nbsp;<wbr>5<br />
2.1.1&nbsp;<wbr>跨平台&nbsp;<wbr>5<br />
2.1.2&nbsp;<wbr>费用及维护&nbsp;<wbr>5<br />
2.1.3&nbsp;<wbr>复制技术&nbsp;<wbr>5<br />
2.1.4&nbsp;<wbr>允许使用ACI&nbsp;<wbr>5<br />
2.2.&nbsp;<wbr>LDAP存储什么数据&nbsp;<wbr>6<br />
2.3.&nbsp;<wbr>什么时候该用LDAP存储数据&nbsp;<wbr>6<br />
3.&nbsp;<wbr>LDAP的基本模型&nbsp;<wbr>7<br />
3.1&nbsp;<wbr>信息模型：描述LDAP的信息表示方式&nbsp;<wbr>7<br />
3.2&nbsp;<wbr>命名模型：描述LDAP中的数据如何组织&nbsp;<wbr>7<br />
3.3&nbsp;<wbr>功能模型：描述LDAP中的数据操作访问&nbsp;<wbr>7<br />
3.4&nbsp;<wbr>安全模型：描述LDAP中的安全机制&nbsp;<wbr>8<br />
3.4.1&nbsp;<wbr>身份认证&nbsp;<wbr>8<br />
3.4.2&nbsp;<wbr>通讯安全&nbsp;<wbr>8<br />
3.4.3&nbsp;<wbr>访问控制&nbsp;<wbr>8</div>
<div>4.&nbsp;<wbr>LDAP数据结构&nbsp;<wbr>9<br />
4.1&nbsp;<wbr>树状组织&nbsp;<wbr>9<br />
4.2&nbsp;<wbr>条目和条目认证&nbsp;<wbr>9<br />
4.3&nbsp;<wbr>数据样式（schema）&nbsp;<wbr>9<br />
4.4&nbsp;<wbr>对象类型(objectClass)&nbsp;<wbr>9<br />
4.5&nbsp;<wbr>过滤器和语法&nbsp;<wbr>10<br />
4.6&nbsp;<wbr>树移植&nbsp;<wbr>10<br />
4.7&nbsp;<wbr>LDIF交换文件&nbsp;<wbr>10<br />
4.8&nbsp;<wbr>JAVA或CORBA对象串行化存储&nbsp;<wbr>10<br />
</div>
<p>1.1.&nbsp;<wbr>LDAP是什么<br />
LDAP是轻量目录访问协议，英文全称是Lightweight Directory Access Protocol，一般都简称为LDAP。它是基于X.500标准的，但是简单多了并且可以根据需要定制。与X.500不同，LDAP支持TCP/IP，这对访问Internet是必须的。LDAP的核心规范在RFC中都有定义，所有与LDAP相关的RFC都可以在LDAPman RFC网页中找到。<br />
简单说来，LDAP是一个得到关于人或者资源的集中、静态数据的快速方式。<br />
LDAP是一个用来发布目录信息到许多不同资源的协议。通常它都作为一个集中的地址本使用，不过根据组织者的需要，它可以做得更加强大。<br />
1.2.&nbsp;<wbr>LDAP是电话簿<br />
LDAP其实是一电话簿，类似于我们所使用诸如NIS(Network Information Service)、DNS (Domain Name Service)等网络目录，也类似于你在花园中所看到的树木。<br />
1.3.&nbsp;<wbr>LDAP是不是数据库<br />
不少LDAP开发人员喜欢把LDAP与关系数据库相比，认为是另一种的存贮方式，然后在读性能上进行比较。实际上，这种对比的基础是错误的。LDAP和关系数据库是两种不同层次的概念，后者是存贮方式（同一层次如网格数据库，对象数据库），前者是存贮模式和访问协议。LDAP是一个比关系数据库抽象层次更高的存贮概念，与关系数据库的查询语言SQL属同一级别。LDAP最基本的形式是一个连接数据库的标准方式。该数据库为读查询作了优化。因此它可以很快地得到查询结果，不过在其它方面，例如更新，就慢得多。<br />
从另一个意义上 LDAP是实现了指定的数据结构的存贮，它是一种特殊的数据库。但是LDAP和一般的数据库不同，明白这一点是很重要的。 LDAP对查询进行了优化，与写性能相比LDAP的读性能要优秀很多。<br />
就象Sybase、Oracle、Informix或Microsoft的数据库管理系统（DBMS）是用于处理查询和更新关系型数据库那样，LDAP服务器也是用来处理查询和更新LDAP目录的。换句话来说LDAP目录也是一种类型的数据库，但不是关系型数据库。要特别注意的是，LDAP通常作为一个hierarchal数据库使用，而不是一个关系数据库。因此，它的结构用树来表示比用表格好。正因为这样，就不能用SQL语句了。<br />
2.&nbsp;<wbr>LDAP的特点<br />
2.1.&nbsp;<wbr>LDAP的优势<br />
2.1.1&nbsp;<wbr>跨平台<br />
LDAP最大的优势是：可以在任何计算机平台上，用很容易获得的而且数目不断增加的LDAP的客户端程序访问LDAP目录。而且也很容易定制应用程序为它加上LDAP的支持。<br />
LDAP协议是跨平台的和标准的协议，因此应用程序就不用为LDAP目录放在什么样的服务器上操心了。实际上，LDAP得到了业界的广泛认可，因为它是Internet的标准。产商都很愿意在产品中加入对LDAP的支持，因为他们根本不用考虑另一端（客户端或服务端）是怎么样的。LDAP服务器可以是任何一个开发源代码或商用的LDAP目录服务器（或者还可能是具有LDAP界面的关系型数据库），因为可以用同样的协议、客户端连接软件包和查询命令与LDAP服务器进行交互。与LDAP不同的是，如果软件产商想在软件产品中集成对DBMS的支持，那么通常都要对每一个数据库服务器单独定制。<br />
2.1.2&nbsp;<wbr>费用及维护<br />
不象很多商用的关系型数据库，你不必为LDAP的每一个客户端连接或许可协议付费。<br />
大多数的LDAP服务器安装起来很简单，也容易维护和优化。<br />
2.1.3&nbsp;<wbr>复制技术<br />
LDAP服务器可以用"推"或"拉"的方法复制部分或全部数据，例如：可以把数据"推"到远程的办公室，以增加数据的安全性。复制技术是内置在LDAP服务器中的而且很容易配置。如果要在DBMS中使用相同的复制功能，数据库产商就会要你支付额外的费用，而且也很难管理。<br />
2.1.4&nbsp;<wbr>允许使用ACI<br />
LDAP允许你根据需要使用ACI（一般都称为ACL或者访问控制列表）控制对数据读和写的权限。例如，设备管理员可以有权改变员工的工作地点和办公室号码，但是不允许改变记录中其它的域。ACI可以根据谁访问数据、访问什么数据、数据存在什么地方以及其它对数据进行访问控制。因为这些都是由LDAP目录服务器完成的，所以不用担心在客户端的应用程序上是否要进行安全检查。<br />
2.2.&nbsp;<wbr>LDAP存储什么数据<br />
LDAP对于这样存储这样的信息最为有用：也就是数据需要从不同的地点读取，但是不需要经常更新。例如，这些信息存储在LDAP目录中是十分有效的：<br />
l&nbsp;<wbr>公司员工的电话号码簿和组织结构图<br />
l&nbsp;<wbr>客户的联系信息<br />
l&nbsp;<wbr>计算机管理需要的信息，包括NIS映射、email假名，等等<br />
l&nbsp;<wbr>软件包的配置信息<br />
l&nbsp;<wbr>公用证书和安全密匙<br />
2.3.&nbsp;<wbr>什么时候该用LDAP存储数据<br />
大多数的LDAP服务器都为读密集型的操作进行专门的优化。因此，当从LDAP服务器中读取数据的时候会比从专门为OLTP优化的关系型数据库中读取数据快一个数量级。也是因为专门为读的性能进行优化，大多数的LDAP目录服务器并不适合存储需要需要经常改变的数据。例如，用LDAP服务器来存储电话号码是一个很好的选择，但是它不能作为电子商务站点的数据库服务器。<br />
如果下面每一个问题的答案都是"是"，那么把数据存在LDAP中就是一个好主意。<br />
l&nbsp;<wbr>需要在任何平台上都能读取数据吗？<br />
l&nbsp;<wbr>每一个单独的记录项是不是每一天都只有很少的改变？<br />
l&nbsp;<wbr>可以把数据存在平面数据库（flat database）而不是关系型数据库中吗？换句话来说，也就是不管什么范式不范式的，把所有东西都存在一个记录中（差不多只要满足第一范式）。<br />
最后一个问题可能会唬住一些人，其实用平面数据库去存储一些关系型的数据也是很一般的。例如，一条公司员工的记录就可以包含经理的登录名。用LDAP来存储这类信息是很方便的。一个简单的判断方法：如果可以把保数据存在一张张的卡片里，就可以很容易地把它存在LDAP目录里。<br />
3.&nbsp;<wbr>LDAP的基本模型<br />
3.1&nbsp;<wbr>信息模型：描述LDAP的信息表示方式<br />
在LDAP中信息以树状方式组织，在树状信息中的基本数据单元是条目，而每个条目由属性构成，属性中存储有属性值；LDAP中的信息模式，类似于面向对象的概念，在LDAP中每个条目必须属于某个或多个对象类（Object Class），每个Object Class由多个属性类型组成，每个属性类型有所对应的语法和匹配规则；对象类和属性类型的定义均可以使用继承的概念。每个条目创建时，必须定义所属的对象类，必须提供对象类中的必选属性类型的属性值，在LDAP中一个属性类型可以对应多个值。<br />
在LDAP中把对象类、属性类型、语法和匹配规则统称为Schema，在LDAP中有许多系统对象类、属性类型、语法和匹配规则，这些系统Schema在LDAP标准中进行了规定，同时不同的应用领域也定义了自己的Schema，同时用户在应用时，也可以根据需要自定义Schema。这有些类似于XML，除了XML标准中的XML定义外，每个行业都有自己标准的DTD或DOM定义，用户也可以自扩展；也如同XML，在LDAP中也鼓励用户尽量使用标准的Schema，以增强信息的互联互通。<br />
在Schema中最难理解的是匹配规则，这是LDAP中为了加快查询的速度，针对不同的数据类型，可以提供不同的匹配方法，如针对字符串类型的相等、模糊、大于小于均提供自己的匹配规则。<br />
3.2&nbsp;<wbr>命名模型：描述LDAP中的数据如何组织<br />
LDAP中的命名模型，也即LDAP中的条目定位方式。在LDAP中每个条目均有自己的DN和RDN。DN是该条目在整个树中的唯一名称标识，RDN是条目在父节点下的唯一名称标识，如同文件系统中，带路径的文件名就是DN，文件名就是RDN。<br />
3.3&nbsp;<wbr>功能模型：描述LDAP中的数据操作访问<br />
在LDAP中共有四类10种操作：查询类操作，如搜索、比较；更新类操作，如添加条目、删除条目、修改条目、修改条目名；认证类操作，如绑定、解绑定；其它操作，如放弃和扩展操作。除了扩展操作，另外9种是LDAP的标准操作；扩展操作是LDAP中为了增加新的功能，提供的一种标准的扩展框架，当前已经成为LDAP标准的扩展操作，有修改密码和StartTLS扩展，在新的RFC标准和草案中正在增加一些新的扩展操作，不同的LDAP厂商也均定义了自己的扩展操作。<br />
3.4&nbsp;<wbr>安全模型：描述LDAP中的安全机制<br />
LDAP中的安全模型主要通过身份认证、安全通道和访问控制来实现。<br />
3.4.1&nbsp;<wbr>身份认证<br />
在LDAP中提供三种认证机制，即匿名、基本认证和SASL（Simple Authentication and Secure Layer）认证。匿名认证即不对用户进行认证，该方法仅对完全公开的方式适用；基本认证均是通过用户名和密码进行身份识别，又分为简单密码和摘要密码认证；SASL认证即LDAP提供的在SSL和TLS安全通道基础上进行的身份认证，包括数字证书的认证。<br />
3.4.2&nbsp;<wbr>通讯安全<br />
在LDAP中提供了基于SSL/TLS的通讯安全保障。SSL/TLS是基于PKI信息安全技术，是目前Internet上广泛采用的安全服务。LDAP通过StartTLS方式启动TLS服务，可以提供通讯中的数据保密性、完整性保护；通过强制客户端证书认证的TLS服务，同时可以实现对客户端身份和服务器端身份的双向验证。<br />
3.4.3&nbsp;<wbr>访问控制<br />
虽然LDAP目前并无访问控制的标准，但从一些草案中或是事实上LDAP产品的访问控制情况，我们不难看出：LDAP访问控制异常的灵活和丰富，在LDAP中是基于访问控制策略语句来实现访问控制的，这不同于现有的关系型数据库系统和应用系统，它是通过基于访问控制列表来实现的，无论是基于组模式或角色模式，都摆脱不了这种限制。<br />
在使用关系型数据库系统开发应用时，往往是通过几个固定的数据库用户名访问数据库。对于应用系统本身的访问控制，通常是需要建立专门的用户表，在应用系统内开发针对不同用户的访问控制授权代码，这样一旦访问控制策略变更时，往往需要代码进行变更。总之一句话，关系型数据库的应用中用户数据管理和数据库访问标识是分离的，复杂的数据访问控制需要通过应用来实现。<br />
而对于LDAP，用户数据管理和访问标识是一体的，应用不需要关心访问控制的实现。这是由于在LDAP中的访问控制语句是基于策略语句来实现的，无论是访问控制的数据对象，还是访问控制的主体对象，均是与这些对象在树中的位置和对象本身的数据特征相关。<br />
在LDAP中，可以把整个目录、目录的子树、制定条目、特定条目属性集或符合某过滤条件的条目作为控制对象进行授权；可以把特定用户、属于特定组或所有目录用户作为授权主体进行授权；最后，还可以定义对特定位置（例如IP地址或DNS名称）的访问权。</p>
<p>4.&nbsp;<wbr>LDAP数据结构<br />
LDAP是实现了指定的数据结构的存贮，它包括以下可以用关系数据库实现的结构要求：树状组织、条目认证、类型定义、许可树形记录拷贝。<br />
4.1&nbsp;<wbr>树状组织<br />
无论是X500还是LDAP都是采用树状方式进行记录。每一个树目录都有一个树根的入口条目，子记录全部是这一根条目的子孙。这是目录与关系数据类型最大的区别（关系数据库的应用结构也可实现树状记录）。因此，把目录看作是更高级的树状数据库也未尝不可，只不过除此外，它不能实现关系存贮的重要功能。<br />
4.2&nbsp;<wbr>条目和条目认证<br />
LDAP是以条目作为认证的根据。ROOT的权限认证与目录本身无关，但除此外所有条目的认证权限由条目本身的密码进行认证。LDAP可以配置成各种各样不同的父子条目权限继承方式。<br />
每一个条目相当于一个单一的平面文本记录，由条目自身或指定的条目认证进行访问控制。因此，LDAP定义的存贮结构等同于一批树状组织的平面数据库，并提供相应的访问控制。<br />
条目中的记录以名-值对的形式存在，每一个名值对必须由数据样式schema预定义。因此，LDAP可以看作是以规定的值类型以名值对形式存贮在一系列以树状组织的平面数据库的记录的集合。<br />
4.3&nbsp;<wbr>数据样式（schema）<br />
数据样式schema是针对不同的应用，由用户指定（设计）类和属性类型预定义，条目中的类(objectclass)和属性必须在在LDAP服务器启动时载入内存的schema已有定义。因此，AD活动目录中的条目记录就必须符合Active Directory的schema中。如果已提供的schema中的定义不够用，用户可以自行定义新的schema.<br />
在<a href="http://ldap.akbkhome.com/index.php"><font color="#007799">http://ldap.akbkhome.com/index.php</font></a>中可以看到常用的schema。<br />
4.4&nbsp;<wbr>对象类型(objectClass)<br />
因为LDAP目录可以定制成存储任何文本或二进制数据，到底存什么要由你自己决定。LDAP目录用对象类型（objectclass）的概念来定义运行哪一类的对象使用什么属性。在几乎所有的LDAP服务器中，你都要根据自己的需要扩展基本的LDAP目录的功能，创建新的对象类型或者扩展现存的对象类型。<br />
条目中的记录通过objectclass实现分类，objectClass是一个继承性的类定义，每一个类定义指定必须具备的属性。如某一条目指定必须符合某个类型，则它必须具备超类所指定的属性。<br />
通过objectclass分类，分散的条目中的记录就实际上建立了一个索引结构，为高速的读查询打下了基础。Objectclass也是过滤器的主要查询对象。<br />
4.5&nbsp;<wbr>过滤器和语法<br />
LDAP是一个查询为主的记录结构，无论是何种查询方式，最终都由过滤器缺点查询的条件。过滤器相当于SQL中的WHERE子句。任何LDAP的类过滤和字符串都必须放在括号内，如（objectclass=*）,指列出所有类型的记录（不过分类）。<br />
可以使用=，&gt;=，&lt;=，~=（约等于）进行比较，如(number&lt;=100)。合并条件是最怪的，必须把操作符放在两个操作对象的前面而不是中间，单一操作对象用括号括起来。如<br />
l&nbsp;<wbr>A与B，不是A&amp;B，而是（&amp;(A)(B)）。<br />
l&nbsp;<wbr>或使用"|"表示；<br />
l&nbsp;<wbr>非使用"！"表示。<br />
l&nbsp;<wbr>对于"与"，或"或"在操作符后可以跟多个条件表达式，但非后则只参是单个表达式。<br />
详见RFC1558。<br />
4.6&nbsp;<wbr>树移植<br />
LDAP最重要的特性和要求并不是读性能，而是扩展性。这一特性是通过树移植和树复制实现的。按LDAP的RFC要求，LDAP目录应该可以任意地在不同的目录间连接、合并并实现自动复制，及自动性同步。这意味着用户可以在任一LDAP中访问条目，而不用管其中某一部分是否复制自全世界另一目录中的记录，同时另一目录中的记录同样在正常运作。<br />
这一特性如果在关系数据库中实现，意味着要使用程序化的非规范化预复制。类似于汇总帐目的设计。<br />
4.7&nbsp;<wbr>LDIF交换文件<br />
LDIF是LDAP约定的记录交换格式，以平面文本的形式存在，是大部分LDAP内容交换的基础，如拷贝、添加、修改等操作，都是基于LDIF文件进行操作。<br />
4.8&nbsp;<wbr>JAVA或CORBA对象串行化存储<br />
网络高效率的访问加上JAVA的跨平台能力，当把JAVA或CORBA对象串行化后存储到LDAP目录上时，可以产生非同一般的集成效果--实际上，这正是EJB和.NET的网络定位基础技术。<br />
使用JAVA或CORBA对象存储时，必须首先让LDAP服务支持该对象定义，也就是说包含qmail.schema或corba.schema。<br />
JAVA必须存储在objectclass=javacontainer的条目中，而且必须带有cn属性，这意味着除非该JAVA类专门实现了DirContext接口，对于大多数JAVA类来说，只能采用DirContext代替Context实现bind的添加操作。取出JAVA类相对要简单得多，只需使用context.lookup()获得该对象的句柄，然后强制造型成所需要的对象就可以了,如：<br />
Person p=(Person)contex.lookup("cn=elvis,dc=daifu,dc=com");<br />
这个句法在EJB的程序中，是经常用到的。<br />
使用CORBA的跨语言性质，使用CORBA存储对象比JAVA更加诱人，这意味着所存储的对象可以被任何语言编写的客户端访问。其实，微软的.net说到底也非常简单，无非是把COM对象存储到微软自家的目录ActiveDirectory里面，从而可以在网络范围内使用任何微软平台的语言进行对象访问而已。众所周知，COM就是与CORBA相对的微软规范。<br />
使用对象串行化技术，可以把常用对象如某个打印机，某个客户直接存储到LDAP中，然后快速获取该对象的引用，这样，就比把对象信息存储到关系数据库中，分别取出属性，然后再初始化对象操作的做法，效率要高得多了。这是LDAP目前比普通关系数据库存储要优秀的地方，而对象数据库还不成熟。</p>
<img src ="http://www.blogjava.net/yifeng/aggbug/230203.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yifeng/" target="_blank">忆风</a> 2008-09-21 00:50 <a href="http://www.blogjava.net/yifeng/archive/2008/09/21/230203.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>openldap界面管理工具—JXplorer</title><link>http://www.blogjava.net/yifeng/archive/2008/09/20/230048.html</link><dc:creator>忆风</dc:creator><author>忆风</author><pubDate>Fri, 19 Sep 2008 16:43:00 GMT</pubDate><guid>http://www.blogjava.net/yifeng/archive/2008/09/20/230048.html</guid><wfw:comment>http://www.blogjava.net/yifeng/comments/230048.html</wfw:comment><comments>http://www.blogjava.net/yifeng/archive/2008/09/20/230048.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yifeng/comments/commentRss/230048.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yifeng/services/trackbacks/230048.html</trackback:ping><description><![CDATA[JXplorer - A Java Ldap Browser<br />
<br />
LDAP(轻量级目录服务访问协议，Lightweight Directory Access Protocol)基于X.500标准，支持TCP/IP，使用简单方便。现在越来越多的网络应用系统都支持LDAP。OpenLDAP是LDAP的一种开源实现，而JXplorer则是openLdap的一种界面管理工具，使openLdap使用更方便&nbsp;<br />
<br />
<a title="JXplorer LDAP Browser download" href="/Files/yifeng/Repository/JXplorerLDAPBrowser.rar">JXplorer LDAP Browser download</a>
<img src ="http://www.blogjava.net/yifeng/aggbug/230048.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yifeng/" target="_blank">忆风</a> 2008-09-20 00:43 <a href="http://www.blogjava.net/yifeng/archive/2008/09/20/230048.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LDAP协议基础概念</title><link>http://www.blogjava.net/yifeng/archive/2008/09/19/229839.html</link><dc:creator>忆风</dc:creator><author>忆风</author><pubDate>Thu, 18 Sep 2008 18:00:00 GMT</pubDate><guid>http://www.blogjava.net/yifeng/archive/2008/09/19/229839.html</guid><wfw:comment>http://www.blogjava.net/yifeng/comments/229839.html</wfw:comment><comments>http://www.blogjava.net/yifeng/archive/2008/09/19/229839.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yifeng/comments/commentRss/229839.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yifeng/services/trackbacks/229839.html</trackback:ping><description><![CDATA[<span style="font-size: large"><strong>LDAP协议基础概念</strong></span> <br />
<br />
1. 从用途上阐述LDAP，它是一个存储静态相关信息的服务，适合&#8220;一次记录多次读取&#8221;。常用LDAP服务存储的信息： <br />
<ul>
    <li>公司的物理设备信息（如打印机，它的IP地址、存放位置、厂商、购买时间等）
    <li> 公开的员工信息（地址、电话、电子邮件&#8230;）
    <li> 合同和账号信息（客户信息、产品交付日期、投标信息、项目信息&#8230;）
    <li> 凭证信息（认证凭证、许可证凭证&#8230;） </li>
</ul>
<br />
2. 从数据结构上阐述LDAP，它是一个树型结构，能有效明确的描述一个组织结构特性的相关信息。在这个树型结构上的每个节点，我们称之为&#8220;条目（Entry）&#8221;，每个条目有自己的唯一可区别的名称（Distinguished Name ，DN）。条目的DN是由条目所在树型结构中的父节点位置（Base DN）和该条目的某个可用来区别身份的属性（称之为RDN如uid , cn）组合而成。对Full DN ：&#8220;shineuserid=linly , ou=Employee , dc=jsoso , dc=net&#8221;而言，其中Base DN：&#8220;ou=Employee , dc=jsoso , dc=net&#8221;，RDN：&#8220;shineuserid=linly&#8221;下面是一个LDAP服务器的数据结构图： <br />
<img src="http://linliangyi2007.javaeye.com/upload/picture/pic/8728/502f1323-8cd9-3c15-b1cf-5412cf110efa.gif" _counted="undefined"  alt="" /> <br />
3. 从协议衍化上阐述LDAP，它是&#8220;目录访问协议DAP——ISO X.500&#8221;的衍生，简化了DAP协议，提供了轻量级的基于TCP/IP协议的网络访问，降低了管理维护成本，但保持了强壮且易于扩充的信息框架。LDAP的应用程序可以很轻松的新增、修改、查询和删除目录内容信息。 <br />
<br />
<span style="font-size: large"><strong>LDAP目录条目（Directory Entry）简述</strong></span> <br />
<strong>从Object Classes谈起</strong> <br />
在LDAP目录数据库中，所有的条目都必须定义objectClass这个属性。这有点像Java语言里说阐述的&#8220;一切皆对象&#8221;的理念，每个条目（LDAP Entry）都要定义自己的Object Classes。Object Class可以看作是LDAP Entry的模板，它定义了条目的属性集，包括必有属性（requited attribute）和可选属性（option attribute）。这里要着重指出的是，在LDAP的Entry中是不能像关系数据库的表那样随意添加属性字段的，一个Entry的属性是由它所继承的所有Object Classes的属性集合决定的，此外可以包括LDAP中规定的&#8220;操作属性&#8221;（操作属性是一种独立于Object Class而存在的属性，它可以赋给目录中的任意条目）。如果你想添加的属性不在Object Classes定义属性的范畴，也不是LDAP规定的操作属性，那么是不能直接绑定（在LDAP中，给Entry赋予属性的过程称为绑定）到条目上的，你必须自定义一个含有你需要的属性的Object Class，而后将此类型赋给条目。 <br />
Object Class是可以被继承的，这使它看上去真的很像Java语言中的POJO对象。继承类的对象实例也必须实现父 <br />
类规定的必有属性（requited attribute），同时拥有父类规定的可选属性（option attribute）。继承类可以扩展父类的必有属性和可选属性。由于Object Class的继承特性，因此在一个LDAP Entry上，objectClass属性是一个多值属性，它涵盖了Object Class的完整继承树，如用户条目uid=Linly , ou=People, dc=jsoso , dc=net，它直接实现了inetorgperson这个对象类，那么它的objectClass属性值为inetorgperson，organizationalPerson，person，top。 <br />
<br />
<strong>从Object Classes到Directory Server Schema</strong> <br />
上一章节中，我们了解了LDAP条目都要遵守的一个最重要的规定Object Classes，而实际上，对Entry更多更细的规范被涵盖在了Directory Server Schema（目录服务模式）中。Directory Schema声明了完整的LDAP数据的存储规范，这包括数据的字节大小、数值范围和格式定义。 <br />
默认的，在一个LDAP服务器上，都定义有一套标准的Schema和一套为服务器功能定制的Schema。用户在需要的时候，是可以定制自己的LDAP属性和Object Class，以扩展标准Schema的功能。在Sun Directory Server中，使用了标准LDAPv3 Schema，并在此基础上做了轻微的扩展。 <br />
<br />
在Schema中的标准属性（Standard Attributes）是一个键-值对,如：cn：linly ，属性ID（属性名）为cn，属性值为linly 。事实上，一个完整的条目就是由一系列的键-值对组成的。以下是一个完整的LDAP Entry： <br />
<div class="quote_title">引用</div>
<div class="quote_div">dn: uid=Linly,ou=People, dc=jsoso,dc=net <br />
telephoneNumber: 13950491407 <br />
mail: linliangyi2005@gmail.com <br />
objectClass: top <br />
objectClass: person <br />
objectClass: organizationalPerson <br />
objectClass: inetorgperson <br />
cn: LinLiangyi <br />
userPassword: {SSHA}aPTgP47LeziVGqjPBI8343FwkcL3QgQQ9kirXw== <br />
creatorsName: uid=admin,ou=administrators,ou=topologymanagement,o=netscaperoot <br />
createTimestamp: 20080219070003Z <br />
nsUniqueId: 2deb0d01-deb811dc-8055dc88-5f880db9 <br />
nsRoleDN: cn=MyAdminRole,ou=People,dc=jsoso,dc=net <br />
nsRoleDN: cn=secondRole,ou=People,dc=jsoso,dc=net <br />
cn;phonetic;lang-zh:: IA== <br />
preferredLanguage: zh-CN <br />
cn;lang-zh:: 5p6X6Imv55uKICA= <br />
givenName: liangyi <br />
givenName;lang-zh:: 6Imv55uK <br />
sn: lin <br />
sn;lang-zh:: 5p6X <br />
uid: linly <br />
manager: cosTemplateForPostalCode <br />
modifiersName: uid=admin,ou=administrators,ou=topologymanagement,o=netscaperoot <br />
modifyTimestamp: 20080227083015Z</div>
<br />
<br />
在Schema中，对属性的定义包含以下内容： <br />
<ul>
    <li> 一个唯一的属性名称
    <li> 一个属性的OID（object&nbsp; identifier）
    <li> 一段属性的文本描述信息
    <li> 一个关联属性文法定义的OID
    <li> 属性的单值/多值描述；属性是否是目录自有的；属性的由来；附加的一些匹配规则 </li>
</ul>
<br />
<br />
此外Schema中最重要的部分就是我们上面提到的Object Classes，它实际上是预定义的一套捆绑成套的属性集合。在Schema定义中，Object Classes要包含以下内容： <br />
<ul>
    <li> 一个唯一的名字
    <li> 一个object identifier (OID) 定义Object Class
    <li> 一个必有的属性集合
    <li> 一个可选的属性集合 </li>
</ul>
<br />
<br />
<strong>高级LDAP条目</strong> <br />
在目录服务中，信息是以条目的形式被分层次的组织在一起的。LDAP提供了几种分组机制，使得信息管理更富有弹性。 <br />
<br />
<strong>静态组和动态组（Static Group and Dynamic Group）</strong> <br />
<strong>组(Group)</strong>，声明一个目录条目的集合 <br />
<strong>静态组（Static Group）：</strong>显式声明了一个它的集合成员，这种方式适用于少量明确的成员组合。 <br />
<strong>动态组（Dynamic Group）</strong>：它定义了一个过滤条件，所有匹配条件的条目都是组的成员。所以称之为动态组，是因为每次读取其组员名单时，要动态计算过滤条件。 <br />
使用组的优点是能够快速的查找所属的成员；缺点是，给出任意的成员，无法获知它所属的组。因此从数据关联关系上看，Group适合一对多的查询。 <br />
<br />
<strong>受管角色、过滤器角色和嵌套角色（Managed Role、Filtered Role and Nested Role）</strong> <br />
<strong>角色（Role）</strong>，它是条目的另一种集合形式。它与组不同的在于，给定一个任意的成员条目，我们能立刻获知它所属的角色。因此从数据关联关系上看，Role适合多对一的查询。角色定义仅对它们的父节点子树下面的目录条目有效。 <br />
<strong>受管角色（Managed Role）</strong>，它等价于Group中的静态组，不同的是，Role不是把组员信息添加到自身属性中，而是将自身的DN添加到组员条目的nsroledn属性中。 <br />
<strong>过滤器角色（Filtered Role）</strong>，它与动态组相似，通过定义条目过滤器来确定组员。 <br />
<strong>嵌套角色（Nested Role）</strong>，它是对角色定义的一种嵌套形式。可以嵌套其他的嵌套角色的。嵌套角色的成员，是其包含的所有角色成员的合集。嵌套角色通过包含从属于其它子树下的角色，可以扩展其搜索的scope。 <br />
<br />
<strong>服务类CoS</strong> <br />
服务类实际上是一种属性的共享机制，它无须定义条目间的关联关系，却可以做到数据同步和空间优化。例如，在一个公司目录下，拥有上千个员工，他们拥有相同的公司地址属性；在传统的条目中，地址属性分别存贮在员工条目里，这样不但浪费存储空间，一旦地址变更，则要对员工条目进行逐一修改。采用CoS机制后，公司地址属性被存放在一个对象内，员工条目通过引用这个对象来获得地址信息，从而缩小的存储空间损耗，并方便了信息的修改。 <br />
CoS仅对其父节点子树下面的目录条目有效。CoS机制包含两个部分，CoS 定义条目和CoS模板条目。定义条目描述了属性是如何被引用的；模板条目描述了属性的值。CoS机制包含3种类型： <br />
<strong>指针服务类(Pointer CoS),</strong> <br />
在Pointer CoS中，CoS包含一个定义Definition Entry，它指定了两个属性：1.共享属性的名称；2.提供共享数据的模板DN。 另外CoS还要有一个Template Entry，它要提供共享的数据。 <br />
在定义了Definition Entry和Template Entry后，Pointer CoS将为其父节点子树下面的所有条目（目标条目Target Entry）分配共享属性和模板所定义的值。示意图如下： <br />
<img src="http://linliangyi2007.javaeye.com/upload/picture/pic/8730/b15cd82a-b22b-3c49-b104-4409aee48c01.gif" _counted="undefined"  alt="" /> <br />
 Definition Entry：cn=PointerCoS , dc=example , dc= com定义了CoS的共享属性cosAttribute：postalCode，同时定义了CoS的模板DN cosTemplateDN：cn=cosTemplateForPostalCode，cn=data。 <br />
 Template Entry: 它是CoS的模板，定义了共享属性值 postalCode：45773。 <br />
 Target Entry：它是目标条目，因为它位于dc=example , dc=com的子树下。所以它获得了共享属性postalCode：45773。 <br />
<br />
<strong>间接服务类(Indirect CoS)</strong>, <br />
在使用间接服务类时，在Definition Entry条目中定义了CoS的共享属性cosAttribut和一个用来间接指向模板的属性cosIndirectSpecifier。 <br />
首先，我们需要用cosIndirectSpecifier的值A作为属性名，来检索CoS父节点子树中所有拥有A属性的条目，作为目标条目Target Entry。 <br />
其次，根据找到的Target Entry条目中A属性的值来定位模板对象。 <br />
最后，再分别根据找到的模板对象中拥有的共享属性值赋给对应的Target Entry。 <br />
例如，定义如下Definition Entry <br />
<div class="quote_title">引用</div>
<div class="quote_div">dn: cn=generateDeptNum,ou=People,dc=example,dc=com <br />
objectclass: top <br />
objectclass: LDAPsubentry <br />
objectclass: cosSuperDefinition <br />
objectclass: cosIndirectDefinition <br />
cosIndirectSpecifier: manager <br />
cosAttribute: departmentNumber</div>
<br />
该CoS定义对条目ou=People,dc=example,dc=com下的子树中所有具有manager属性的 条目有效，同时设定其CoS模板指向manager属性的值所指向的条目。 <br />
又假定有如下的Template Entry条目，它具有属性departmentNumber： <br />
<div class="quote_title">引用</div>
<div class="quote_div">dn: cn=Carla Fuentes,ou=People,dc=example,dc=com <br />
&#8230; <br />
objectclass: cosTemplate <br />
&#8230; <br />
departmentNumber: 318842</div>
<br />
同时在ou=People,dc=example,dc=com下有Target Entry如下： <br />
<div class="quote_title">引用</div>
<div class="quote_div">dn: cn=Babs Jensen,ou=People,dc=example,dc=com <br />
cn: Babs Jensen <br />
... <br />
manager: cn=Carla Fuentes,ou=People,dc=example,dc=com <br />
departmentNumber: 318842 </div>
<br />
因为该Entry具有manager属性，且在ou=People,dc=example,dc=com子树下，所以它成为了Target Entity。并且由于其manager的值指向模板cn=Carla Fuentes,ou=People,dc=example,dc=com，因此，它的departmentNumber为 318842。 <br />
<br />
<strong>经典服务类(Classic CoS)</strong> <br />
经典服务类同间接服务类有点相似，它也是对属性的间接应用。在Classic CoS的定义条目中，除了共享属性定义外，还有两个定义，一个是cosTemplateDn，它指向模板条目的父节点；另一个是cosSpecifier，它的值指向目标条目的属性A。由目标条目的属性A的值来代替模板条目的RND。则目标条目的属性A的值加上cosTemplateDn的值恰好定义一个唯一的模板条目。 <br />
举例如下，首先是一个经典服务类的定义条目： <br />
<div class="quote_title">引用</div>
<div class="quote_div">dn: cn=classicCoS,dc=example,dc=com <br />
objectclass: top <br />
objectclass: LDAPsubentry <br />
objectclass: cosSuperDefinition <br />
objectclass: cosClassicDefinition <br />
cosTemplateDn: ou=People,dc=example,dc=com <br />
cosSpecifier: building <br />
cosAttribute: postalAddress</div>
<br />
该定义条目指明了3个参数， <br />
1． 要共享的属性是postalAddress <br />
2． 模板条目的上下文前缀是ou=People,dc=example,dc=com <br />
3． 模板条目的RDN存储于目标条目的building属性中 <br />
其次，假定有如下模板条目： <br />
<div class="quote_title">引用</div>
<div class="quote_div">dn: cn=B07,ou=People,dc=example,dc=com <br />
objectclass: top <br />
objectclass: LDAPsubentry <br />
objectclass: extensibleobject <br />
objectclass: cosTemplate <br />
postalAddres: 7 Old Oak Street$Anytown, CA 95054</div>
<br />
最后，我们假设有以下目标条目： <br />
<div class="quote_title">引用</div>
<div class="quote_div">dn: cn=Babs Jensen,ou=People,dc=example,dc=com <br />
cn: Babs Jensen <br />
... <br />
building: B07 <br />
postalAddres: 7 Old Oak Street$Anytown, CA 95054</div>
<br />
由于目标条目中，building属性的值是B07，因此该条目的模板定义DN = B07加上ou=People,dc=example,dc=com ，即cn=B07,ou=People,dc=example,dc=com，因此目标条目的postalAddres 引用模板的值7 Old Oak Street$Anytown, CA 95054。 <br />
<br />
<strong>LDAP 目录搜索</strong> <br />
LDAP搜索是目录服务最常用的功能之一。在LDAP服务中搜索要用到相应的Filter语句。Filter语句由3个部分组成： <br />
1． 属性，如：cn ，uid ，操作属性如:objectClass&nbsp; ,&nbsp; nsroledn <br />
2． 比较操作符 ，如 &lt; , &gt; ,= ,&#8230; <br />
3． 逻辑预算符，如: 与操作&amp;&nbsp; , 或操作| , 非操作！ <br />
关于Filter语句组成的详细参数表如下： <br />
<strong>filter的运算符</strong> <br />
<img src="http://linliangyi2007.javaeye.com/upload/picture/pic/8734/d1a62a84-b638-32d7-9d4f-f6829ba54dbf.gif" _counted="undefined"  alt="" /> <br />
<strong>filter布尔运算符</strong> <br />
<img src="http://linliangyi2007.javaeye.com/upload/picture/pic/8736/a151eb07-48b5-3d42-a191-67ea6f694aa8.gif" _counted="undefined"  alt="" /> <br />
<br />
<strong>搜索过滤器示例 </strong><br />
<ul>
    <li>下列过滤器将搜索包含一个或多个 manager 属性值的条目。这也称为存在搜索：manager=*
    <li>下列过滤器将搜索包含通用名 Ray Kultgen 的条目。这也称为等价搜索：cn=Ray Kultgen
    <li>下列过滤器返回所有不包含通用名 Ray Kultgen 的条目：(!(cn=Ray Kultgen))
    <li>下列过滤器返回的所有条目中都有包含子字符串 X.500 的说明属性：description=*X.500*
    <li>下列过滤器返回所有组织单元为 Marketing 且说明字段中不包含子字符串 X.500 的条目：(&amp;(ou=Marketing)(!(description=*X.500*)))
    <li>下列过滤器返回所有组织单元为 Marketing 且 manager 为 Julie Fulmer 或 Cindy Zwaska 的条目：(&amp;(ou=Marketing)(|(manager=cn=Julie Fulmer,ou=Marketing,dc=siroe,dc=com)(manager=cn=Cindy Zwaska,ou=Marketing,dc=siroe,dc=com)))
    <li>下列过滤器返回所有不代表人员的条目：(!(objectClass=person))
    <li>下列过滤器返回所有不代表人员且通用名近似于 printer3b 的条目：(&amp;(!(objectClass=person))(cn~=printer3b)) </li>
</ul>
<br />
<br />
<strong>ldapsearch指令参数</strong>-b 搜索的起始上下文 <br />
<ul>
    <li>-D 绑定搜索的账号Distinguished Name
    <li>-h 主机名。地址
    <li>-p LDAP服务端口
    <li>-l 搜索的最大耗时
    <li>-s 从上下文开始的搜索范围，有三个常量base（表示仅当前根对象）/one（当前根对象及下一级）/sub（当前根对象的全部子树）
    <li>-W 绑定账号密码
    <li>-z 返回结果的最大数量 </li>
</ul>
<br />
<br />
<strong>搜索&#8220;操作属性&#8221;</strong> <br />
在LDAP搜索中，操作属性在默认情况下是不会跟随搜索结果返回的。必须在搜索中明确显示的指定操作属性，如： <br />
<div class="quote_title">引用</div>
<div class="quote_div">ldapsearch -h linly.jsoso.net -p 5201 -D "cn=directory manager" -w password "objectclass=*" aci=accounts。</div>
<br />
<br />
<strong>搜索&#8220;操作对象类&#8221;的条目</strong> <br />
在LDAP中Role、CoS等对象被定义为特殊的Object Class——操作对象类（operational object class），在一般的搜索中，这类对象是不会作为结果返回给用户的。要想查找这些对象，必须在filter中显式定义要找这个对象类。例如：(objectclass=ldapsubentry)。 <br />
<br />
<span style="font-size: large"><strong>ACI权限控制</strong></span> <br />
ACI（Access Control Instruction）访问控制指令是LDAP 服务中用以控制用户访问权限的有力手段。在目录的Entry中，aci属性记录了对该条目的多条访问控制指令。（aci属性是一个多值操作属性，可以赋予任意的LDAP条目） <br />
<strong>ACI的语法格式如下</strong>：aci: (target)(version 3.0;acl "name";permission bind_rules;) <br />
 <strong>target </strong>指定了ACI要控制访问的目标属性（集合）或条目（集合）。target可以用DN，一个或多个属性，或者一个filter来定义。它是一个可选项。 <br />
<strong>target语法是：</strong>关键字 &lt;op&gt; 表达式 <br />
<strong>target关键字表</strong> <br />
<img src="http://linliangyi2007.javaeye.com/upload/picture/pic/8738/a390887b-3640-3ae4-bc54-f4647f5efd9a.gif" _counted="undefined"  alt="" /> <br />
（更多详细的target用法，请参阅 Sun ONE Directory Server 5.2 Administration Guide ） <br />
<br />
<strong>version 3.0 </strong>这是一个必须的常量字窜，用以识别ACI的版本。 <br />
<br />
<strong>name </strong>指定ACI的名称，可以使任意的字窜，只要区别于同一个条目aci属性下的其他ACI，这是一个必须属性。 <br />
<br />
<strong>permission </strong>指定权限许可。 <br />
<strong>权限包括</strong>：read、write、add、delete、search、compare、selfwrite、 proxy 或 all，其中all表示出了proxy之外的所有操作。 <br />
<strong>权限语法</strong>：allow | deny (权限) <br />
<br />
<strong>bind_rules </strong>绑定规则。绑定规则定义了何人、何时，以及从何处可以访问目录。绑定规则可以是如下规则之一： <br />
<ul>
    <li>&#8226; 被授予访问权限的用户、组以及角色
    <li>&#8226; 实体必须从中绑定的位置
    <li>&#8226; 绑定必须发生的时间或日期
    <li>&#8226; 绑定期间必须使用的验证类型 </li>
</ul>
<br />
<strong>绑定规则语法</strong>：keyword&nbsp; = 或者 != "expression"; （注：timeofday 关键字也支持不等式&lt;、&lt;=、&gt;、&gt;=）。 <br />
<strong>LDIF 绑定规则关键字表</strong> <br />
<img src="http://linliangyi2007.javaeye.com/upload/picture/pic/8740/63b92119-18d4-365a-b924-fe6dd8fdd2a3.gif" _counted="undefined"  alt="" /> <br />
<br />
（更多详细的绑定规则用法，请参阅 Sun ONE Directory Server 5.2 Administration Guide ） <br />
<br />
<strong>ACI样例</strong> <br />
<ul>
    <li>1.用户 bjensen 具有修改其自己的目录条目中所有属性的权限。 aci:(target="ldap:///uid=bjensen,dc=example,dc=com")(targetattr=*)(version 3.0; acl "aci1"; allow (write) userdn="ldap:///self";)
    <li>2.允许 Engineering Admins 组的成员修改 Engineering 业务类别中所有条目的 departmentNumber 和 manager 属性 aci:(targetattr="departmentNumber || manager")(targetfilter="(businessCategory=Engineering)") (version 3.0; acl "eng-admins-write"; allow (write) groupdn ="ldap:///cn=Engineering Admins, dc=example,dc=com";)
    <li>3.允许匿名用户对o=NetscapeRoot下的条目读取和搜索 aci:(targetattr="*")(targetfilter=(o=NetscapeRoot))(version 3.0; acl "Default anonymous access"; allow (read, search) userdn="ldap:///anyone";)
    <li>4.向所有经过验证的用户授予对整个树的读取访问，可以在dc=example,dc=com 节点创建下列 ACI： aci:(version 3.0; acl "all-read"; allow (read)userdn="ldap:///all";)
    <li>5.允许对整个 example.com 树进行匿名读取和搜索访问，可以在dc=example,dc=com 节点创建下列 ACI： aci:(version 3.0; acl "anonymous-read-search";allow (read, search) userdn = "ldap:///anyone";)
    <li>授予Administrators 组对整个目录树写入的权限，则可以在 dc=example,dc=com 节点创建下列 ACI： aci:(version 3.0; acl "Administrators-write"; allow (write) groupdn="ldap:///cn=Administrators,dc=example,dc=com";) <br />
    </li>
</ul>
<img src ="http://www.blogjava.net/yifeng/aggbug/229839.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yifeng/" target="_blank">忆风</a> 2008-09-19 02:00 <a href="http://www.blogjava.net/yifeng/archive/2008/09/19/229839.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> LDAP学习者必看</title><link>http://www.blogjava.net/yifeng/archive/2008/09/17/229406.html</link><dc:creator>忆风</dc:creator><author>忆风</author><pubDate>Wed, 17 Sep 2008 05:44:00 GMT</pubDate><guid>http://www.blogjava.net/yifeng/archive/2008/09/17/229406.html</guid><wfw:comment>http://www.blogjava.net/yifeng/comments/229406.html</wfw:comment><comments>http://www.blogjava.net/yifeng/archive/2008/09/17/229406.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yifeng/comments/commentRss/229406.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yifeng/services/trackbacks/229406.html</trackback:ping><description><![CDATA[<p><span style="font-family: 宋体">如果你在计算机行业工作，那么对</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">可能早有耳闻了。想深入地了解</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">吗？那么可以好好地读一下这篇文章。这篇介绍性的文章是一系列介绍如何在企业中设计、实现和集成</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">环境的文章的头一篇。主要是先让你熟悉一下</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">的基本概念，那些比较困难的细节问题将放到以后讨论。在这篇文章中我们将要介绍：</span></p>
<br />
<p><strong>什么是LDAP?</strong></p>
<p><strong>什么时候该用LDAP存储数据？</strong></p>
<p><strong>LDAP目录树的结构</strong></p>
<p><strong>单独的LDAP记录</strong></p>
<p><strong>作为例子的一个单独的数据项</strong></p>
<p><strong>LDAP复制</strong></p>
<p><strong>安全和访问控制</strong></p>
<p>&nbsp;</p>
<p><span style="font-family: 宋体">现在</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">技术不仅发展得很快而且也是激动人心的。在企业范围内实现</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">可以让运行在几乎所有计算机平台上的所有的应用程序从</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录中获取信息。</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录中可以存储各种类型的数据：电子邮件地址、邮件路由信息、人力资源数据、公用密匙、联系人列表，等等。通过把</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录作为系统集成中的一个重要环节，可以简化员工在企业内部查询信息的步骤，甚至连主要的数据源都可以放在任何地方。如果</span><span lang="EN-US">Oracle</span><span style="font-family: 宋体">、</span><span lang="EN-US">Sybase</span><span style="font-family: 宋体">、</span><span lang="EN-US">Informix</span><span style="font-family: 宋体">或</span><span lang="EN-US">Microsoft SQL</span><span style="font-family: 宋体">数据库中已经存储了类似的数据，那么</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">和这些数据库到底有什么不同呢？是什么让它更具优势？请继续读下去吧！</span></p>
<br />
<h2><a name="_什么是LDAP?"></a><span style="font-family: 黑体">什么是</span><span lang="EN-US">LDAP?</span></h2>
<br />
<p><span lang="EN-US">LDAP</span><span style="font-family: 宋体">的英文全称是</span><span lang="EN-US" style="color: black">Lightweight Directory Access Protocol</span><span style="font-family: 宋体">，一般都简称为</span><span lang="EN-US" style="color: black">LDAP</span><span style="color: black; font-family: 宋体">。它是基于</span><span lang="EN-US" style="color: black">X.500</span><span style="font-family: 宋体">标准的，但是简单多了并且可以根据需要定制。与</span><span lang="EN-US" style="color: black">X.500</span><span style="font-family: 宋体">不同，</span><span lang="EN-US" style="color: black">LDAP</span><span style="color: black; font-family: 宋体">支持</span><span lang="EN-US" style="color: black">TCP/IP</span><span style="font-family: 宋体">，这对访问</span><span lang="EN-US" style="color: black">Internet</span><span style="font-family: 宋体">是必须的。</span><span lang="EN-US" style="color: black">LDAP</span><span style="font-family: 宋体">的核心规范在</span><span lang="EN-US" style="color: black">RFC</span><span style="font-family: 宋体">中都有定义，所有与</span><span lang="EN-US" style="color: black">LDAP</span><span style="font-family: 宋体">相关的</span><span lang="EN-US" style="color: black">RFC</span><span style="color: black; font-family: 宋体">都可以在</span><span lang="EN-US" style="color: black"><a href="http://book.chinaz.com/others/www.ldapman.org/ldap_rfcs.html">LDAPman RFC</a></span><span style="font-family: 宋体">网页中找到。</span></p>
<br />
<h3><span style="font-family: 宋体">怎么使用</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">这个术语呢？</span></h3>
<br />
<p><span style="font-family: 宋体">在日常交谈中，你可能会听到有些人这么说：&#8220;我们要把那些东西存在</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">中吗？&#8221;，或者&#8220;从</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">数据库中取出那些数据！&#8221;，又或者&#8220;我们怎么把</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">和关系型数据库集成在一起？&#8221;。严格地说，</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">根本不是数据库而是用来访问存储在信息目录（也就是</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录）中的信息的<strong>协议</strong>。更为确切和正式的说法应该是象这样的：&#8220;通过使用</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">，可以在信息目录的正确位置读取（或存储）数据&#8221;。但是，也没有必要吹毛求疵，尽管表达得不够准确，我们也都知道对方在说什么。</span></p>
<br />
<h3><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录是数据库吗？</span></h3>
<br />
<p><span style="font-family: 宋体">就象</span><span lang="EN-US">Sybase</span><span style="font-family: 宋体">、</span><span lang="EN-US">Oracle</span><span style="font-family: 宋体">、</span><span lang="EN-US">Informix</span><span style="font-family: 宋体">或</span><span lang="EN-US">Microsoft</span><span style="font-family: 宋体">的数据库管理系统（</span><span lang="EN-US">DBMS</span><span style="font-family: 宋体">）是用于处理查询和更新关系型数据库那样，</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">服务器也是用来处理查询和更新</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录的。换句话来说</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录也是<strong>一种类型</strong>的数据库，但是不是关系型数据库。不象被设计成每分钟需要处理成百上千条数据变化的数据库，例如：在电子商务中经常用到的在线交易处理（</span><span lang="EN-US">OLTP</span><span style="font-family: 宋体">）系统，</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">主要是优化数据读取的性能。</span></p>
<br />
<h3><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录的优势</span></h3>
<br />
<p><span style="font-family: 宋体">现在该说说</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录到底有些什么优势了。现在</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">的流行是很多因数共同作用的结果。我在这里说的不过是一些基本的原因，请你注意一下这不过是一小部分原因。</span></p>
<br />
<p><span style="font-family: 宋体">可能</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">最大的优势是：可以在任何计算机平台上，用很容易获得的而且数目不断增加的</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">的客户端程序访问</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录。而且也很容易定制应用程序为它加上</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">的支持。</span></p>
<br />
<p><span lang="EN-US">LDAP</span><span style="font-family: 宋体">协议是跨平台的和标准的协议，因此应用程序就不用为</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录放在什么样的服务器上操心了。实际上，</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">得到了业界的广泛认可，因为它是</span><span lang="EN-US">Internet</span><span style="font-family: 宋体">的标准。产商都很愿意在产品中加入对</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">的支持，因为他们根本不用考虑另一端（客户端或服务端）是怎么样的。</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">服务器可以是任何一个开发源代码或商用的</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录服务器（或者还可能是具有</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">界面的关系型数据库），因为可以用同样的协议、客户端连接软件包和查询命令与</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">服务器进行交互。与</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">不同的是，如果软件产商想在软件产品中集成对</span><span lang="EN-US">DBMS</span><span style="font-family: 宋体">的支持，那么通常都要对每一个数据库服务器单独定制。</span></p>
<br />
<p><span style="font-family: 宋体">不象很多商用的关系型数据库，你不必为</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">的每一个客户端连接或许可协议付费。</span></p>
<br />
<p><span style="font-family: 宋体">大多数的</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">服务器安装起来很简单，也容易维护和优化。</span></p>
<br />
<p><span lang="EN-US">LDAP</span><span style="font-family: 宋体">服务器可以用&#8220;推&#8221;或&#8220;拉&#8221;的方法复制部分或全部数据，例如：可以把数据&#8220;推&#8221;到远程的办公室，以增加数据的安全性。复制技术是内置在</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">服务器中的而且很容易配置。如果要在</span><span lang="EN-US">DBMS</span><span style="font-family: 宋体">中使用相同的复制功能，数据库产商就会要你支付额外的费用，而且也很难管理。</span></p>
<br />
<p><span lang="EN-US">LDAP</span><span style="font-family: 宋体">允许你根据需要使用</span><span lang="EN-US">ACI</span><span style="font-family: 宋体">（一般都称为</span><span lang="EN-US">ACL</span><span style="font-family: 宋体">或者访问控制列表）控制对数据读和写的权限。例如，设备管理员可以有权改变员工的工作地点和办公室号码，但是不允许改变记录中其它的域。</span><span lang="EN-US">ACI</span><span style="font-family: 宋体">可以根据谁访问数据、访问什么数据、数据存在什么地方以及其它对数据进行访问控制。因为这些都是由</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录服务器完成的，所以不用担心在客户端的应用程序上是否要进行安全检查。</span></p>
<br />
<p><span lang="EN-US">LDAP</span><span style="font-family: 宋体">对于这样存储这样的信息最为有用，也就是数据需要从不同的地点读取，但是不需要经常更新。例如，这些信息存储在</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录中是十分有效的：</span></p>
<br />
<p class="MsoListBullet"><span lang="EN-US" style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">公司员工的电话号码簿和组织结构图</span></p>
<br />
<p class="MsoListBullet"><span lang="EN-US" style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">客户的联系信息</span></p>
<br />
<p class="MsoListBullet"><span lang="EN-US" style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">计算机管理需要的信息，包括</span><span lang="EN-US">NIS</span><span style="font-family: 宋体">映射、</span><span lang="EN-US">email</span><span style="font-family: 宋体">假名，等等</span></p>
<br />
<p class="MsoListBullet"><span lang="EN-US" style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">软件包的配置信息</span></p>
<br />
<p class="MsoListBullet"><span lang="EN-US" style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">公用证书和安全密匙</span></p>
<br />
<h2><a name="_什么时候该用LDAP存储数据"></a><a name="_什么时候该用LDAP存储数据？"></a><span style="font-family: 黑体">什么时候该用</span><span lang="EN-US">LDAP</span><span style="font-family: 黑体">存储数据？</span></h2>
<br />
<p><span style="color: black; font-family: 宋体">大多数的</span><span lang="EN-US" style="color: black">LDAP</span><span style="font-family: 宋体">服务器都为读密集型的操作进行专门的优化。因此，当从</span><span lang="EN-US" style="color: black">LDAP</span><span style="color: black; font-family: 宋体">服务器中读取数据的时候会比从专门为</span><span lang="EN-US" style="color: black">OLTP</span><span style="font-family: 宋体">优化的关系型数据库中读取数据快一个数量级。也是因为专门为读的性能进行优化，大多数的</span><span lang="EN-US" style="color: black">LDAP</span><span style="color: black; font-family: 宋体">目录服务器并不适合存储需要需要经常改变的数据。例如，用</span><span lang="EN-US" style="color: black">LDAP</span><span style="font-family: 宋体">服务器来存储电话号码是一个很好的选择，但是它不能作为电子商务站点的数据库服务器。</span></p>
<br />
<p><span style="color: black; font-family: 宋体">如果下面每一个问题的答案都是&#8220;是&#8221;，那么把数据存在</span><span lang="EN-US" style="color: black">LDAP</span><span style="color: black; font-family: 宋体">中就是一个好主意。</span></p>
<br />
<p class="MsoListBullet"><span lang="EN-US" style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">需要在任何平台上都能读取数据吗？</span></p>
<br />
<p class="MsoListBullet"><span lang="EN-US" style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">每一个单独的记录项是不是每一天都只有很少的改变？</span></p>
<br />
<p class="MsoListBullet"><span lang="EN-US" style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">可以把数据存在平面数据库（</span><span lang="EN-US">flat database</span><span style="font-family: 宋体">）而不是关系型数据库中吗？换句话来说，也就是不管什么范式不范式的，把所有东西都存在一个记录中（差不多只要满足第一范式）。</span></p>
<br />
<p><span style="font-family: 宋体">最后一个问题可能会唬住一些人，其实用平面数据库去存储一些关系型的数据也是很一般的。例如，一条公司员工的记录就可以包含经理的登录名。用</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">来存储这类信息是很方便的。一个简单的判断方法：如果可以把保数据存在一张张的卡片里，就可以很容易地把它存在</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录里。</span></p>
<br />
<h2><a name="_LDAP目录树的结构"></a><span lang="EN-US">LDAP</span><span style="font-family: 黑体">目录树的结构</span></h2>
<br />
<p><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录以树状的层次结构来存储数据。如果你对自顶向下的</span><span lang="EN-US">DNS</span><span style="font-family: 宋体">树或</span><span lang="EN-US">UNIX</span><span style="font-family: 宋体">文件的目录树比较熟悉，也就很容易掌握</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录树这个概念了。就象</span><span lang="EN-US">DNS</span><span style="font-family: 宋体">的主机名那样，</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录记录的标识名（</span><span lang="EN-US">Distinguished Name</span><span style="font-family: 宋体">，简称</span><span lang="EN-US">DN</span><span style="font-family: 宋体">）是用来读取单个记录，以及回溯到树的顶部。后面会做详细地介绍。</span></p>
<br />
<p><span style="font-family: 宋体">为什么要用层次结构来组织数据呢？原因是多方面的。下面是可能遇到的一些情况：</span></p>
<br />
<p><span lang="EN-US" style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">如果你想把所有的美国客户的联系信息都&#8220;推&#8221;到位于到西雅图办公室（负责营销）的</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">服务器上，但是你不想把公司的资产管理信息&#8220;推&#8221;到那里。</span></p>
<br />
<p><span lang="EN-US" style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">你可能想根据目录树的结构给予不同的员工组不同的权限。在下面的例子里，资产管理组对&#8220;</span><span lang="EN-US">asset-mgmt</span><span style="font-family: 宋体">&#8221;部分有完全的访问权限，但是不能访问其它地方。</span></p>
<br />
<p><span lang="EN-US" style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">把</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">存储和复制功能结合起来，可以定制目录树的结构以降低对</span><span lang="EN-US">WAN</span><span style="font-family: 宋体">带宽的要求。位于西雅图的营销办公室需要每分钟更新的美国销售状况的信息，但是欧洲的销售情况就只要每小时更新一次就行了。</span></p>
<br />
<h3><span style="font-family: 宋体">刨根问底：基准</span><span lang="EN-US">DN</span></h3>
<br />
<p><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录树的最顶部就是根，也就是所谓的&#8220;基准</span><span lang="EN-US">DN</span><span style="font-family: 宋体">&#8221;。基准</span><span lang="EN-US">DN</span><span style="font-family: 宋体">通常使用下面列出的三种格式之一。假定我在名为</span><span lang="EN-US">FooBar</span><span style="font-family: 宋体">的电子商务公司工作，这家公司在</span><span lang="EN-US">Internet</span><span style="font-family: 宋体">上的名字是</span><span lang="EN-US">foobar.com</span><span style="font-family: 宋体">。</span></p>
<br />
<p class="a"><strong><span lang="EN-US">o="FooBar, Inc.", c=US </span></strong></p>
<br />
<p><em><span style="color: black; font-family: 宋体">（以</span><span lang="EN-US" style="color: black">X.500</span></em><em><span style="font-family: 宋体">格式表示的基准</span><span lang="EN-US" style="color: black">DN</span></em><em><span style="color: black; font-family: 宋体">）</span></em></p>
<br />
<p><span style="font-family: 宋体">在这个例子中，</span><span lang="EN-US" style="font-size: 10.5pt; color: black; font-family: 'Courier New'">o=FooBar, Inc. </span><span style="font-family: 宋体">表示组织名，在这里就是公司名的同义词。</span><span lang="EN-US" style="font-size: 10.5pt; color: black; font-family: 'Courier New'">c=US </span><span style="font-family: 宋体">表示公司的总部在美国。以前，一般都用这种方式来表示基准</span><span lang="EN-US">DN</span><span style="font-family: 宋体">。但是事物总是在不断变化的，现在所有的公司都已经（或计划）上</span><span lang="EN-US">Internet</span><span style="font-family: 宋体">上。随着</span><span lang="EN-US">Internet</span><span style="font-family: 宋体">的全球化，在基准</span><span lang="EN-US">DN</span><span style="font-family: 宋体">中使用国家代码很容易让人产生混淆。现在，</span><span lang="EN-US">X.500</span><span style="font-family: 宋体">格式发展成下面列出的两种格式。</span></p>
<br />
<p class="a"><strong><span lang="EN-US">o=foobar.com</span></strong></p>
<br />
<p><em><span style="font-family: 宋体">（用公司的</span><span lang="EN-US">Internet</span></em><em><span style="font-family: 宋体">地址表示的基准</span><span lang="EN-US">DN</span></em><em><span style="font-family: 宋体">）</span></em></p>
<br />
<p><span style="font-family: 宋体">这种格式很直观，用公司的域名作为基准</span><span lang="EN-US">DN</span><span style="font-family: 宋体">。这也是现在最常用的格式。</span></p>
<br />
<p class="a"><strong><span lang="EN-US">dc=foobar, dc=com</span></strong></p>
<br />
<p><em><span style="font-family: 宋体">（用</span><span lang="EN-US">DNS</span></em><em><span style="font-family: 宋体">域名的不同部分组成的基准</span><span lang="EN-US">DN</span></em><em><span style="font-family: 宋体">）</span></em></p>
<br />
<p><span style="font-family: 宋体">就象上面那一种格式，这种格式也是以</span><span lang="EN-US">DNS</span><span style="font-family: 宋体">域名为基础的，但是上面那种格式不改变域名（也就更易读），而这种格式把域名：</span><span lang="EN-US" style="font-size: 10.5pt; color: black; font-family: 'Courier New'">foobar.com</span><span style="font-family: 宋体">分成两部分</span> <span lang="EN-US" style="font-size: 10.5pt; color: black; font-family: 'Courier New'">dc=foobar, dc=com</span><span style="font-size: 10.5pt; font-family: 黑体">。</span><span style="font-family: 宋体">在理论上，这种格式可能会更灵活一点，但是对于最终用户来说也更难记忆一点。考虑一下</span><span lang="EN-US">foobar.com</span><span style="font-family: 宋体">这个例子。当</span><span lang="EN-US">foobar.com</span><span style="font-family: 宋体">和</span><span lang="EN-US">gizmo.com</span><span style="font-family: 宋体">合并之后，可以简单的把&#8220;</span><span lang="EN-US">dc=com</span><span style="font-family: 宋体">&#8221;当作基准</span><span lang="EN-US">DN</span><span style="font-family: 宋体">。把新的记录放到已经存在的</span><span lang="EN-US">dc=gizmo, dc=com</span><span style="font-family: 宋体">目录下，这样就简化了很多工作（当然，如果</span><span lang="EN-US">foobar.com</span><span style="font-family: 宋体">和</span><span lang="EN-US">wocket.edu</span><span style="font-family: 宋体">合并，这个方法就不能用了）。如果</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">服务器是新安装的，我建议你使用这种格式。再请注意一下，如果你打算使用活动目录（</span><span lang="EN-US">Actrive Directory</span><span style="font-family: 宋体">），</span><span lang="EN-US">Microsoft</span><span style="font-family: 宋体">已经限制你必须使用这种格式。</span></p>
<br />
<h3><span style="font-family: 宋体">更上一层楼：在目录树中怎么组织数据</span></h3>
<br />
<p><span style="font-family: 宋体">在</span><span lang="EN-US">UNIX</span><span style="font-family: 宋体">文件系统中，最顶层是根目录（</span><span lang="EN-US">root</span><span style="font-family: 宋体">）。在根目录的下面有很多的文件和目录。象上面介绍的那样，</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录也是用同样的方法组织起来的。</span></p>
<br />
<p><span style="font-family: 宋体">在根目录下，要把数据从逻辑上区分开。因为历史上（</span><span lang="EN-US">X.500</span><span style="font-family: 宋体">）的原因，大多数</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录用</span><span lang="EN-US">OU</span><span style="font-family: 宋体">从逻辑上把数据分开来。</span><span lang="EN-US">OU</span><span style="font-family: 宋体">表示&#8220;</span><span lang="EN-US">Organization Unit</span><span style="font-family: 宋体">&#8221;，在</span><span lang="EN-US">X.500</span><span style="font-family: 宋体">协议中是用来表示公司内部的机构：销售部、财务部，等等。现在</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">还保留</span><span lang="EN-US" style="font-size: 10.5pt; color: black; font-family: 'Courier New'">ou=</span><span style="font-family: 宋体">这样的命名规则，但是扩展了分类的范围，可以分类为：</span><span lang="EN-US" style="font-size: 10.5pt; color: black; font-family: 'Courier New'">ou=people, ou=groups, ou=devices</span><span style="font-family: 宋体">，等等。更低一级的</span><span lang="EN-US" style="color: black">OU</span><span style="font-family: 宋体">有时用来做更细的归类。例如：</span><span lang="EN-US" style="color: black">LDAP</span><span style="color: black; font-family: 宋体">目录树（不包括单独的记录）可能会是这样的：</span></p>
<br />
<p class="a"><span>&nbsp;&nbsp;&nbsp; </span>dc=foobar, dc=com </p>
<br />
<p class="a"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>ou=customers </p>
<br />
<p class="a"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>ou=asia </p>
<br />
<p class="a"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>ou=europe </p>
<br />
<p class="a"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>ou=usa </p>
<br />
<p class="a"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>ou=employees </p>
<br />
<p class="a"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>ou=rooms </p>
<br />
<p class="a"><span>&nbsp;&nbsp; </span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ou=groups </p>
<br />
<p class="a"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>ou=assets-mgmt </p>
<br />
<p class="a"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>ou=nisgroups </p>
<br />
<p class="a"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>ou=recipes</p>
<br />
<h2><a name="_单独的LDAP记录"></a><span style="font-family: 黑体">单独的</span><span lang="EN-US">LDAP</span><span style="font-family: 黑体">记录</span></h2>
<br />
<h3><span lang="EN-US">DN</span><span style="font-family: 宋体">是</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">记录项的名字</span></h3>
<br />
<p><span style="font-family: 宋体">在</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录中的所有记录项都有一个唯一的&#8220;</span><span lang="EN-US">Distinguished Name</span><span style="font-family: 宋体">&#8221;，也就是</span><span lang="EN-US">DN</span><span style="font-family: 宋体">。每一个</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">记录项的</span><span lang="EN-US">DN</span><span style="font-family: 宋体">是由两个部分组成的：相对</span><span lang="EN-US">DN</span><span style="font-family: 宋体">（</span><span lang="EN-US">RDN</span><span style="font-family: 宋体">）和记录在</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录中的位置。</span></p>
<br />
<p><span lang="EN-US">RDN</span><span style="font-family: 宋体">是</span><span lang="EN-US">DN</span><span style="font-family: 宋体">中与目录树的结构无关的部分。在</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录中存储的记录项都要有一个名字，这个名字通常存在</span><span lang="EN-US">cn</span><span style="font-family: 宋体">（</span><span lang="EN-US">Common Name</span><span style="font-family: 宋体">）这个属性里。因为几乎所有的东西都有一个名字，在</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">中存储的对象都用它们的</span><span lang="EN-US">cn</span><span style="font-family: 宋体">值作为</span><span lang="EN-US">RDN</span><span style="font-family: 宋体">的基础。如果我把最喜欢的吃燕麦粥食谱存为一个记录，我就会用</span><strong><span lang="EN-US" style="font-size: 10.5pt; color: black; font-family: 'Courier New'">cn=Oatmeal Deluxe</span></strong><span style="font-family: 宋体">作为记录项的</span><span lang="EN-US">RDN</span><span style="font-family: 宋体">。</span></p>
<br />
<p><span lang="EN-US" style="font-size: 10.5pt; color: black; font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">我的</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录的基准</span><span lang="EN-US">DN</span><span style="font-family: 宋体">是</span><strong><span lang="EN-US" style="font-size: 10.5pt; color: black; font-family: 'Courier New'">dc=foobar,dc=com</span></strong></p>
<br />
<p><span lang="EN-US" style="font-size: 10.5pt; color: black; font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">我把自己的食谱作为</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">的记录项存在</span><strong><span lang="EN-US" style="font-size: 10.5pt; color: black; font-family: 'Courier New'">ou=recipes</span></strong></p>
<br />
<p><span lang="EN-US" style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">我的</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">记录项的</span><span lang="EN-US">RDN</span><span style="font-family: 宋体">设为</span><strong><span lang="EN-US" style="font-size: 10.5pt; color: black; font-family: 'Courier New'">cn=Oatmeal Deluxe</span></strong></p>
<br />
<p><span style="font-family: 宋体">上面这些构成了燕麦粥食谱的</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">记录的完整</span><span lang="EN-US">DN</span><span style="font-family: 宋体">。记住，</span><span lang="EN-US">DN</span><span style="font-family: 宋体">的读法和</span><span lang="EN-US">DNS</span><span style="font-family: 宋体">主机名类似。下面就是完整的</span><span lang="EN-US">DN</span><span style="font-family: 宋体">：</span></p>
<br />
<p class="a"><strong><span lang="EN-US">cn=Oatmeal Deluxe,ou=recipes,dc=foobar,dc=com</span></strong></p>
<br />
<h3><span style="font-family: 宋体">举一个实际的例子来说明</span><span lang="EN-US">DN</span></h3>
<br />
<p><span style="font-family: 宋体">现在为公司的员工设置一个</span><span lang="EN-US">DN</span><span style="font-family: 宋体">。可以用基于</span><span lang="EN-US" style="font-size: 10.5pt; color: black; font-family: 'Courier New'">cn</span><span style="font-family: 宋体">或</span><span lang="EN-US" style="font-size: 10.5pt; color: black; font-family: 'Courier New'">uid</span><span style="font-family: 宋体">（</span><span lang="EN-US">User ID</span><span style="font-family: 宋体">），作为典型的用户帐号。例如，</span><span lang="EN-US">FooBar</span><span style="font-family: 宋体">的员工</span><span lang="EN-US">Fran Smith</span><span style="font-family: 宋体">（登录名：</span><span lang="EN-US">fsmith</span><span style="font-family: 宋体">）的</span><span lang="EN-US">DN</span><span style="font-family: 宋体">可以为下面两种格式：</span></p>
<br />
<p class="a"><strong><span lang="EN-US">uid=fsmith,ou=employees,dc=foobar,dc=com</span></strong></p>
<br />
<p><em><span style="font-family: 宋体">（基于登录名）</span></em></p>
<br />
<p><span lang="EN-US">LDAP</span><span style="font-family: 宋体">（以及</span><span lang="EN-US">X.500</span><span style="font-family: 宋体">）用</span><span lang="EN-US" style="font-size: 10.5pt; color: black; font-family: 'Courier New'">uid</span><span style="font-family: 宋体">表示&#8220;</span><span lang="EN-US">User ID</span><span style="font-family: 宋体">&#8221;，不要把它和</span><span lang="EN-US">UNIX</span><span style="font-family: 宋体">的</span><span lang="EN-US">uid</span><span style="font-family: 宋体">号混淆了。大多数公司都会给每一个员工唯一的登录名，因此用这个办法可以很好地保存员工的信息。你不用担心以后还会有一个叫</span><span lang="EN-US">Fran Smith</span><span style="font-family: 宋体">的加入公司，如果</span><span lang="EN-US">Fran</span><span style="font-family: 宋体">改变了她的名字（结婚？离婚？或宗教原因？），也用不着改变</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">记录项的</span><span lang="EN-US">DN</span><span style="font-family: 宋体">。</span></p>
<br />
<p class="a"><strong><span lang="EN-US">cn=Fran Smith,ou=employees,dc=foobar,dc=com</span></strong></p>
<br />
<p><em><span style="font-family: 宋体">（基于姓名）</span></em></p>
<br />
<p><span style="font-family: 宋体">可以看到这种格式使用了</span><span lang="EN-US">Common Name</span><span style="font-family: 宋体">（</span><span lang="EN-US">CN</span><span style="font-family: 宋体">）。可以把</span><span lang="EN-US">Common Name</span><span style="font-family: 宋体">当成一个人的全名。这种格式有一个很明显的缺点就是：如果名字改变了，</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">的记录就要从一个</span><span lang="EN-US">DN</span><span style="font-family: 宋体">转移到另一个</span><span lang="EN-US">DN</span><span style="font-family: 宋体">。但是，我们应该尽可能地避免改变一个记录项的</span><span lang="EN-US">DN</span><span style="font-family: 宋体">。</span></p>
<br />
<h2><span style="font-family: 黑体">定制目录的对象类型</span></h2>
<br />
<p><span style="font-family: 宋体">你可以用</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">存储各种类型的数据对象，只要这些对象可以用属性来表示，下面这些是可以在</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">中存储的一些信息：</span></p>
<br />
<p><span lang="EN-US" style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">员工信息：员工的姓名、登录名、口令、员工号、他的经理的登录名，邮件服务器，等等。</span></p>
<br />
<p><span lang="EN-US" style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">物品跟踪信息：计算机名、</span><span lang="EN-US">IP</span><span style="font-family: 宋体">地址、标签、型号、所在位置，等等。</span></p>
<br />
<p><span lang="EN-US" style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">客户联系列表：客户的公司名、主要联系人的电话、传真和电子邮件，等等。</span></p>
<br />
<p><span lang="EN-US" style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">会议厅信息：会议厅的名字、位置、可以坐多少人、电话号码、是否有投影机。</span></p>
<br />
<p><span lang="EN-US" style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">食谱信息：菜的名字、配料、烹调方法以及准备方法。</span></p>
<br />
<p><span style="font-family: 宋体">因为</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录可以定制成存储任何文本或二进制数据，到底存什么要由你自己决定。</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录用对象类型（</span><span lang="EN-US">object classes</span><span style="font-family: 宋体">）的概念来定义运行哪一类的对象使用什么属性。在几乎所有的</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">服务器中，你都要根据自己的需要扩展基本的</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录的功能，创建新的对象类型或者扩展现存的对象类型。</span></p>
<br />
<p><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录以一系列&#8220;属性对&#8221;的形式来存储记录项，每一个记录项包括属性类型和属性值（这与关系型数据库用行和列来存取数据有根本的不同）。下面是我存在</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录中的一部分食谱记录：</span></p>
<br />
<p class="a"><span>&nbsp; </span>dn: cn=Oatmeal Deluxe, ou=recipes, dc=foobar, dc=com </p>
<br />
<p class="a"><span>&nbsp; </span>cn: Instant Oatmeal Deluxe </p>
<br />
<p class="a"><span>&nbsp; </span>recipeCuisine: breakfast </p>
<br />
<p class="a"><span>&nbsp; </span>recipeIngredient: 1 packet instant oatmeal </p>
<br />
<p class="a"><span>&nbsp; </span>recipeIngredient: 1 cup water </p>
<br />
<p class="a"><span>&nbsp; </span>recipeIngredient: 1 pinch salt </p>
<br />
<p class="a"><span>&nbsp; </span>recipeIngredient: 1 tsp brown sugar </p>
<br />
<p class="a"><span>&nbsp; </span>recipeIngredient: 1/4 apple, any type</p>
<br />
<p><span style="font-family: 宋体">请注意上面每一种配料都作为属性</span><span lang="EN-US" style="font-size: 10.5pt; color: black; font-family: 'Courier New'">recipeIngredient</span><span style="font-family: 宋体">值。</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录被设计成象上面那样为一个属性保存多个值的，而不是在每一个属性的后面用逗号把一系列值分开。</span></p>
<br />
<p><span style="font-family: 宋体">因为用这样的方式存储数据，所以数据库就有很大的灵活性，不必为加入一些新的数据就重新创建表和索引。更重要的是，</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录不必花费内存或硬盘空间处理&#8220;空&#8221;域，也就是说，实际上不使用可选择的域也不会花费你任何资源。</span></p>
<br />
<h2><a name="_作为例子的一个单独的数据项"></a><span style="font-family: 黑体">作为例子的一个单独的数据项</span></h2>
<br />
<p><span style="font-family: 宋体">让我们看看下面这个例子。我们用</span><span lang="EN-US">Foobar, Inc.</span><span style="font-family: 宋体">的员工</span><span lang="EN-US">Fran Smith</span><span style="font-family: 宋体">的</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">记录。这个记录项的格式是</span><span lang="EN-US">LDIF</span><span style="font-family: 宋体">，用来导入和导出</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">目录的记录项。</span></p>
<br />
<p class="a"><span>&nbsp; </span>dn: uid=fsmith, ou=employees, dc=foobar, dc=com</p>
<br />
<p class="a"><span>&nbsp; </span>objectclass: person</p>
<br />
<p class="a"><span>&nbsp; </span>objectclass: organizationalPerson</p>
<br />
<p class="a"><span>&nbsp; </span>objectclass: inetOrgPerson</p>
<br />
<p class="a"><span>&nbsp; </span>objectclass: foobarPerson</p>
<br />
<p class="a"><span>&nbsp; </span>uid: fsmith</p>
<br />
<p class="a"><span>&nbsp; </span>givenname: Fran</p>
<br />
<p class="a"><span>&nbsp; </span>sn: Smith</p>
<br />
<p class="a"><span>&nbsp; </span>cn: Fran Smith</p>
<br />
<p class="a"><span>&nbsp;</span>&nbsp;cn: Frances Smith</p>
<br />
<p class="a"><span>&nbsp; </span>telephonenumber: 510-555-1234</p>
<br />
<p class="a"><span>&nbsp; </span>roomnumber: 122G</p>
<br />
<p class="a"><span>&nbsp; </span>o: Foobar, Inc.</p>
<br />
<p class="a"><span>&nbsp; </span>mailRoutingAddress: fsmith@foobar.com</p>
<br />
<p class="a"><span>&nbsp; </span>mailhost: mail.foobar.com</p>
<br />
<p class="a"><span>&nbsp; </span>userpassword: {crypt}3x1231v76T89N</p>
<br />
<p class="a"><span>&nbsp; </span>uidnumber: 1234</p>
<br />
<p class="a"><span>&nbsp; </span>gidnumber: 1200</p>
<br />
<p class="a"><span>&nbsp; </span>homedirectory: /home/fsmith</p>
<br />
<p class="a"><span>&nbsp; </span>loginshell: /usr/local/bin/bash</p>
<br />
<p><span style="font-family: 宋体">属性的值在保存的时候是保留大小写的，但是在默认情况下搜索的时候是不区分大小写的。某些特殊的属性（例如，</span><span lang="EN-US">password</span><span style="font-family: 宋体">）在搜索的时候需要区分大小写。</span></p>
<br />
<p><span style="font-family: 宋体">让我们一点一点地分析上面的记录项。</span></p>
<br />
<p class="a"><span lang="EN-US">dn: uid=fsmith, ou=employees, dc=foobar, dc=com</span></p>
<br />
<p><span style="font-family: 宋体">这是</span><span lang="EN-US">Fran</span><span style="font-family: 宋体">的</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">记录项的完整</span><span lang="EN-US">DN</span><span style="font-family: 宋体">，包括在目录树中的完整路径。</span><span lang="EN-US">LDAP</span><span style="font-family: 宋体">（和</span><span lang="EN-US">X.500</span><span style="font-family: 宋体">）使用</span><span lang="EN-US" style="font-size: 10.5pt; color: black; font-family: 'Courier New'">uid</span><span style="font-family: 宋体">（</span><span lang="EN-US">User ID</span><span style="font-family: 宋体">），不要把它和</span><span lang="EN-US">UNIX</span><span style="font-family: 宋体">的</span><span lang="EN-US">uid</span><span style="font-family: 宋体">号混淆了。</span></p>
<br />
<p class="a"><span>&nbsp; </span>objectclass: person </p>
<br />
<p class="a"><span>&nbsp; </span>objectclass: organizationalPerson </p>
<br />
<p class="a"><span>&nbsp; </span>objectclass: inetOrgPerson </p>
<br />
<p class="a"><span>&nbsp; </span>objectclass: foobarPerson</p>
<br />
<p><span style="font-family: 宋体">可以为任何一个对象根据需要分配多个对象类型。</span><span lang="EN-US" style="font-size: 10.5pt; color: black; font-family: 'Courier New'">person</span><span style="font-family: 宋体">对象类型要求</span><span lang="EN-US" style="font-size: 10.5pt; color: black; font-family: 'Courier New'">cn</span><span style="font-family: 宋体">（</span><span lang="EN-US">common name</span><span style="font-family: 宋体">）和</span><span lang="EN-US" style="font-size: 10.5pt; color: black; font-family: 'Courier New'">sn</span><span style="font-family: 宋体">（</span></p>
&nbsp;
 <img src ="http://www.blogjava.net/yifeng/aggbug/229406.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yifeng/" target="_blank">忆风</a> 2008-09-17 13:44 <a href="http://www.blogjava.net/yifeng/archive/2008/09/17/229406.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转】面试必问的16个经典问题的回答思路 </title><link>http://www.blogjava.net/yifeng/archive/2008/08/27/225154.html</link><dc:creator>忆风</dc:creator><author>忆风</author><pubDate>Wed, 27 Aug 2008 14:56:00 GMT</pubDate><guid>http://www.blogjava.net/yifeng/archive/2008/08/27/225154.html</guid><wfw:comment>http://www.blogjava.net/yifeng/comments/225154.html</wfw:comment><comments>http://www.blogjava.net/yifeng/archive/2008/08/27/225154.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yifeng/comments/commentRss/225154.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yifeng/services/trackbacks/225154.html</trackback:ping><description><![CDATA[　面试过程中，面试官会向应聘者发问，而应聘者的回答将成为面试官考虑是否接受他的重要依据。对应聘者而言，了解这些问题背后的&#8220;猫腻&#8221;至关重要。本文对面试中经常出现的一些典型问题进行了整理，并给出相应的回答思路和参考答案。读者无需过分关注分析的细节，关键是要从这些分析中&#8220;悟&#8221;出面试的规律及回答问题的思维方式，达到&#8220;活学活用&#8221;。
<p>　　<strong>问题一：&#8220;请你自我介绍一下&#8221;</strong></p>
<p>　　思路：</p>
<p>　　1、这是面试的必考题目。</p>
<p>　　2、介绍内容要与个人简历相一致。</p>
<p>　　3、表述方式上尽量口语化。</p>
<p>　　4、要切中要害，不谈无关、无用的内容。</p>
<p>　　5、条理要清晰，层次要分明。<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp; 6、事先最好以文字的形式写好背熟。</p>
<p>　　<strong>问题二：&#8220;谈谈你的家庭情况&#8221;</strong></p>
<p>　　思路：</p>
<p>　　1、家庭情况对于了解应聘者的性格、观念、心态等有一定的作用，这是招聘单位问该问题的主要原因。</p>
<p>　　2、简单地罗列家庭人口。</p>
<p>　　3、宜强调温馨和睦的家庭氛围。</p>
<p>　　4、宜强调父母对自己教育的重视。</p>
<p>　　5、宜强调各位家庭成员的良好状况。</p>
<p>　　6、宜强调家庭成员对自己工作的支持。</p>
<p>　　7、宜强调自己对家庭的责任感。</p>
<p>　　<strong>问题三：&#8220;你有什么业余爱好?&#8221;</strong></p>
<p>　　思路：</p>
<p>　　1、业余爱好能在一定程度上反映应聘者的性格、观念、心态，这是招聘单位问该问题的主要原因。</p>
<p>　　2、最好不要说自己没有业余爱好。</p>
<p>　　3、不要说自己有那些庸俗的、令人感觉不好的爱好。</p>
<p>　　4、最好不要说自己仅限于读书、听音乐、上网，否则可能令面试官怀疑应聘者性格孤僻。</p>
<p>　　5、最好能有一些户外的业余爱好来&#8220;点缀&#8221;你的形象。</p>
<p>　　<strong>问题四：&#8220;你最崇拜谁?&#8221;</strong></p>
<p>　　思路：</p>
<p>　　1、最崇拜的人能在一定程度上反映应聘者的性格、观念、心态，这是面试官问该问题的主要原因。</p>
<p>　　2、不宜说自己谁都不崇拜。</p>
<p>　　3、不宜说崇拜自己。</p>
<p>　　4、不宜说崇拜一个虚幻的、或是不知名的人。</p>
<p>　　5、不宜说崇拜一个明显具有负面形象的人。</p>
<p>　　6、所崇拜的人人最好与自己所应聘的工作能&#8220;搭&#8221;上关系。</p>
<p>　　7、最好说出自己所崇拜的人的哪些品质、哪些思想感染着自己、鼓舞着自己。<br />
</p>
<p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 问题五：&#8220;你的座右铭是什么?&#8221;</strong> </p>
<p>　　思路：</p>
<p>　　1、座右铭能在一定程度上反映应聘者的性格、观念、心态，这是面试官问这个问题的主要原因。</p>
<p>　　2、不宜说那些医引起不好联想的座右铭。</p>
<p>　　3、不宜说那些太抽象的座右铭。</p>
<p>　　4、不宜说太长的座右铭。</p>
<p>　　5、座右铭最好能反映出自己某种优秀品质。</p>
<p>　　6、参考答案--&#8220;只为成功找方法，不为失败找借口&#8221;。</p>
<p>　　<strong>问题六：&#8220;谈谈你的缺点&#8221;</strong></p>
<p>　　思路：</p>
<p>　　1、不宜说自己没缺点。</p>
<p>　　2、不宜把那些明显的优点说成缺点。</p>
<p>　　3、不宜说出严重影响所应聘工作的缺点。</p>
<p>　　4、不宜说出令人不放心、不舒服的缺点。</p>
<p>　　5、可以说出一些对于所应聘工作&#8220;无关紧要&#8221;的缺点，甚至是一些表面上看是缺点，从工作的角度看却是优点的缺点。</p>
<p>　　<strong>问题七：&#8220;谈一谈你的一次失败经历&#8221;</strong></p>
<p>　　思路：</p>
<p>　　1、不宜说自己没有失败的经历。</p>
<p>　　2、不宜把那些明显的成功说成是失败。</p>
<p>　　3、不宜说出严重影响所应聘工作的失败经历。</p>
<p>　　4、所谈经历的结果应是失败的。</p>
<p>　　5、宜说明失败之前自己曾信心白倍、尽心尽力。</p>
<p>　　6、说明仅仅是由于外在客观原因导致失败。</p>
<p>　　7、失败后自己很快振作起来，以更加饱满的热情面对以后的工作。</p>
<p>　　<strong>问题八：&#8220;你为什么选择我们公司?&#8221;</strong></p>
<p>　　思路：</p>
<p>　　1、面试官试图从中了解你求职的动机、愿望以及对此项工作的态度。</p>
<p>　　2、建议从行业、企业和岗位这三个角度来回答。</p>
<p>　　3、参考答案--&#8220;我十分看好贵公司所在的行业，我认为贵公司十分重视人才，而且这项工作很适合我，相信自己一定能做好。&#8221;</p>
<p>　　<strong>问题九：&#8220;对这项工作，你有哪些可预见的困难?&#8221;</strong></p>
<p>　　思路：</p>
<p>　　1、不宜直接说出具体的困难，否则可能令对方怀疑应聘者不行。</p>
<p>　　2、可以尝试迂回战术，说出应聘者对困难所持有的态度--&#8220;工作中出现一些困难是正常的，也是难免的，但是只要有坚忍不拔的毅力、良好的合作精神以及事前周密而充分的准备，任何困难都是可以克服的。&#8221;</p>
<p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 问题十：&#8220;如果我录用你，你将怎样开展工作&#8221;</strong> </p>
<p>　　思路：</p>
<p>　　1、如果应聘者对于应聘的职位缺乏足够的了解，最好不要直接说出自己开展工作的具体办法。</p>
<p>　　2、可以尝试采用迂回战术来回答，如&#8220;首先听取领导的指示和要求，然后就有关情况进行了解和熟悉，接下来制定一份近期的工作计划并报领导批准，最后根据计划开展工作。&#8221;</p>
<p>　　<strong>问题十一：&#8220;与上级意见不一是，你将怎么办?&#8221;</strong></p>
<p>　　思路：</p>
<p>　　1、一般可以这样回答&#8220;我会给上级以必要的解释和提醒，在这种情况下，我会服从上级的意见。&#8221;</p>
<p>　　2、如果面试你的是总经理，而你所应聘的职位另有一位经理，且这位经理当时不在场，可以这样回答：&#8220;对于非原则性问题，我会服从上级的意见，对于涉及公司利益的重大问题，我希望能向更高层领导反映。&#8221;</p>
<p>　　<strong>问题十二：&#8220;我们为什么要录用你?&#8221;</strong></p>
<p>　　思路：</p>
<p>　　1、应聘者最好站在招聘单位的角度来回答。</p>
<p>　　2、招聘单位一般会录用这样的应聘者：基本符合条件、对这份共组感兴趣、有足够的信心。</p>
<p>　　3、如&#8220;我符合贵公司的招聘条件，凭我目前掌握的技能、高度的责任感和良好的饿适应能力及学习能力，完全能胜任这份工作。我十分希望能为贵公司服务，如果贵公司给我这个机会，我一定能成为贵公司的栋梁!&#8221;</p>
<p>　　<strong>问题十三：&#8220;你能为我们做什么?&#8221;</strong></p>
<p>　　思路：</p>
<p>　　1、基本原则上&#8220;投其所好&#8221;。</p>
<p>　　2、回答这个问题前应聘者最好能&#8220;先发制人&#8221;，了解招聘单位期待这个职位所能发挥的作用。</p>
<p>　　3、应聘者可以根据自己的了解，结合自己在专业领域的优势来回答这个问题。</p>
<p>　　<strong>问题十四：&#8220;你是应届毕业生，缺乏经验，如何能胜任这项工作?&#8221;</strong></p>
<p>　　思路：</p>
<p>　　1、如果招聘单位对应届毕业生的应聘者提出这个问题，说明招聘单位并不真正在乎&#8220;经验&#8221;，关键看应聘者怎样回答。</p>
<p>　　2、对这个问题的回答最好要体现出应聘者的诚恳、机智、果敢及敬业。</p>
<p>　　3、如&#8220;作为应届毕业生，在工作经验方面的确会有所欠缺，因此在读书期间我一直利用各种机会在这个行业里做兼职。我也发现，实际工作远比书本知识丰富、复杂。但我有较强的责任心、适应能力和学习能力，而且比较勤奋，所以在兼职中均能圆满完成各项工作，从中获取的经验也令我受益非浅。请贵公司放心，学校所学及兼职的工作经验使我一定能胜任这个职位。&#8221;</p>
<p>　　<strong>问题十五：&#8220;你希望与什么样的上级共事?&#8221;</strong></p>
<p>　　思路：</p>
<p>　　1、通过应聘者对上级的&#8220;希望&#8221;可以判断出应聘者对自我要求的意识，这既是一个陷阱，又是一次机会。</p>
<p>　　2、最好回避对上级具体的希望，多谈对自己的要求。</p>
<p>　　3、如&#8220;做为刚步入社会新人，我应该多要求自己尽快熟悉环境、适应环境，而不应该对环境提出什么要求，只要能发挥我的专长就可以了。&#8221;</p>
<p>　　<strong>问题十六：&#8220;您在前一家公司的离职原因是什么?&#8221;</strong></p>
<p>　　思路：</p>
<p>　　1、最重要的是：应聘者要使找招聘单位相信，应聘者在过往的单位的&#8220;离职原因&#8221;在此家招聘单位里不存在。</p>
<p>　　2、避免把&#8220;离职原因&#8221;说得太详细、太具体。</p>
<p>　　3、不能掺杂主观的负面感受，如&#8220;太幸苦&#8221;、&#8220;人际关系复杂&#8221;、&#8220;管理太混乱&#8221;、&#8220;公司不重视人才&#8221;、&#8220;公司排斥我们某某的员工&#8221;等。</p>
<p>　　4、但也不能躲闪、回避，如&#8220;想换换环境&#8221;、&#8220;个人原因&#8221;等。</p>
<p>　　5、不能涉及自己负面的人格特征，如不诚实、懒惰、缺乏责任感、不随和等。</p>
<p>　　6、尽量使解释的理由为应聘者个人形象添彩。</p>
<p>　　7、如&#8220;我离职是因为这家公司倒闭。我在公司工作了三年多，有较深的感情。从去年始，由于市场形势突变，公司的局面急转直下。到眼下这一步我觉得很遗憾，但还要面对现实，重新寻找能发挥我能力的舞台。&#8221;</p>
<p>　　同一个面试问题并非只有一个答案，而同一个答案并不是在任何面试场合都有效，关键在于应聘者掌握了规律后，对面试的具体情况进行把握，有意识地揣摩面试官提出问题的心理背景，然后投其所好。</p>
<img src ="http://www.blogjava.net/yifeng/aggbug/225154.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yifeng/" target="_blank">忆风</a> 2008-08-27 22:56 <a href="http://www.blogjava.net/yifeng/archive/2008/08/27/225154.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java面试题及答案（基础题122道，代码题19道） </title><link>http://www.blogjava.net/yifeng/archive/2008/08/27/225153.html</link><dc:creator>忆风</dc:creator><author>忆风</author><pubDate>Wed, 27 Aug 2008 14:55:00 GMT</pubDate><guid>http://www.blogjava.net/yifeng/archive/2008/08/27/225153.html</guid><wfw:comment>http://www.blogjava.net/yifeng/comments/225153.html</wfw:comment><comments>http://www.blogjava.net/yifeng/archive/2008/08/27/225153.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/yifeng/comments/commentRss/225153.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yifeng/services/trackbacks/225153.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: JAVA相关基础知识1、面向对象的特征有哪些方面 1.抽象：抽象就是忽略一个主题中与当前目标无关的那些方面，以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题，而只是选择其中的一部分，暂时不用部分细节。抽象包括两个方面，一是过程抽象，二是数据抽象。2.继承：继承是一种联结类的层次模型，并且允许和鼓励类的重用，它提供了一种明确表述共性的方法。对象的一个新类可以从现有的...&nbsp;&nbsp;<a href='http://www.blogjava.net/yifeng/archive/2008/08/27/225153.html'>阅读全文</a><img src ="http://www.blogjava.net/yifeng/aggbug/225153.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yifeng/" target="_blank">忆风</a> 2008-08-27 22:55 <a href="http://www.blogjava.net/yifeng/archive/2008/08/27/225153.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>有趣的网址收集</title><link>http://www.blogjava.net/yifeng/archive/2008/08/27/224905.html</link><dc:creator>忆风</dc:creator><author>忆风</author><pubDate>Tue, 26 Aug 2008 21:46:00 GMT</pubDate><guid>http://www.blogjava.net/yifeng/archive/2008/08/27/224905.html</guid><wfw:comment>http://www.blogjava.net/yifeng/comments/224905.html</wfw:comment><comments>http://www.blogjava.net/yifeng/archive/2008/08/27/224905.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yifeng/comments/commentRss/224905.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yifeng/services/trackbacks/224905.html</trackback:ping><description><![CDATA[常常喜欢在网上看，而且经常看到一些有趣的东西，现在找个地方收集记录下来，说不定哪天就用上了，以后慢慢往上加！！！<br />
<br />
<p>1、在线制作Button<br />
http://www.buttonator.com/</p>
<p>2、查询某个网站所采用的技术的网站<br />
http://builtwith.com</p>
<p>3、JavaFX做的很漂亮的网站，太COOL了<br />
http://china.jooce.com/</p>
<p>4、Flex做的3D，很帅<br />
http://dev.getoutsmart.com/os3d/demos/videoroom/</p>
<p><br />
5、Flex的Grooveshark-在线音乐服务网站<br />
http://listen.grooveshark.com/<br />
</p>
<img src ="http://www.blogjava.net/yifeng/aggbug/224905.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yifeng/" target="_blank">忆风</a> 2008-08-27 05:46 <a href="http://www.blogjava.net/yifeng/archive/2008/08/27/224905.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>分享jbpm3.1中文文档</title><link>http://www.blogjava.net/yifeng/archive/2008/08/24/223947.html</link><dc:creator>忆风</dc:creator><author>忆风</author><pubDate>Sun, 24 Aug 2008 00:02:00 GMT</pubDate><guid>http://www.blogjava.net/yifeng/archive/2008/08/24/223947.html</guid><wfw:comment>http://www.blogjava.net/yifeng/comments/223947.html</wfw:comment><comments>http://www.blogjava.net/yifeng/archive/2008/08/24/223947.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yifeng/comments/commentRss/223947.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yifeng/services/trackbacks/223947.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;下载地址：&nbsp;&nbsp;&nbsp;&nbsp;<a title="jbpm3.1中文文档" href="/Files/yifeng/Repository/jbpm3.1.rar">jbpm3.1中文文档</a></p>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/introduction.html#d0e17"><font face="宋体"><font size="+0">1.1.&nbsp;综述</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/introduction.html#d0e28"><font face="宋体"><font size="+0">1.2. The JBoss jBPM&nbsp;新手工具箱</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/introduction.html#d0e77"><font face="宋体"><font size="+0">1.3. The JBoss jBPM&nbsp;流程图形设计器</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/introduction.html#d0e88"><font face="宋体"><font size="+0">1.4. The JBoss jBPM&nbsp;核心组件</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/introduction.html#d0e105"><font face="宋体"><font size="+0">1.5. The JBoss jBPM 控制台web应用</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/introduction.html#d0e110"><font face="宋体"><font size="+0">1.6. The JBoss jBPM&nbsp;身份组件</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/introduction.html#d0e118"><font face="宋体"><font size="+0">1.7. The JBoss jBPM&nbsp;日程安排程序</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/introduction.html#d0e125"><font face="宋体"><font size="+0">1.8. The JBoss jBPM 兼容数据库包</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/introduction.html#d0e130"><font face="宋体"><font size="+0">1.9. The JBoss jBPM BPEL&nbsp;扩展</font> </font></a></span></dt></dl>
<dt><span class="chapter"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/gettingstarted.html"><font face="宋体"><font size="+0">2.&nbsp;开始</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/gettingstarted.html#downloadablesoverview"><font face="宋体"><font size="+0">2.1.下载一览</font>&nbsp; </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/gettingstarted.html#packagejbpm"><font face="宋体"><font size="+0">2.1.1. jBPM 3</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/gettingstarted.html#jbpm-starters-kit-version.zip"><font face="宋体"><font size="+0">2.1.1.1. 新手工具箱</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/gettingstarted.html#jbpm-version.zip"><font face="宋体"><font size="+0">2.1.1.2. 核心引擎和身份组件</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/gettingstarted.html#jbpm-db-version.zip"><font face="宋体"><font size="+0">2.1.1.3. 数据库扩展</font> </font></a></span></dt></dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/gettingstarted.html#packagejbpmprocessdesigner"><font face="宋体"><font size="+0">2.1.2. jBPM&nbsp;流程设计器</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/gettingstarted.html#jbpm-gpd-site-version.zip"><font face="宋体"><font size="+0">2.1.2.1. Eclipse&nbsp;更新站点</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/gettingstarted.html#jbpm-gpd-feature-version.zip"><font face="宋体"><font size="+0">2.1.2.2. Eclipse&nbsp;特点</font> </font></a></span></dt></dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/gettingstarted.html#packagejbpmbpelextension"><font face="宋体"><font size="+0">2.1.3. jBPM BPEL&nbsp;扩展</font> </font></a></span></dt></dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/gettingstarted.html#d0e201"><font face="宋体"><font size="+0">2.2. The JBoss jBPM&nbsp;项目目录</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/gettingstarted.html#d0e258"><font face="宋体"><font size="+0">2.3. 公开CVS访问</font> </font></a></span></dt></dl>
<dt><span class="chapter"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/tutorial.html"><font face="宋体"><font size="+0">3.&nbsp;指南</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/tutorial.html#helloworldexample"><font face="宋体"><font size="+0">3.1. Hello World&nbsp;例子</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/tutorial.html#databaseexample"><font face="宋体"><font size="+0">3.2. 数据库 例子</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/tutorial.html#d0e661"><font face="宋体"><font size="+0">3.3. 上下问(context) 例子: 流程变量</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/tutorial.html#taskassignmentexample"><font face="宋体"><font size="+0">3.4. 任务分派例子</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/tutorial.html#customactionexample"><font face="宋体"><font size="+0">3.5. 定制动作Action例子</font> </font></a></span></dt></dl>
<dt><span class="chapter"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/graphorientedprogramming.html"><font face="宋体"><font size="+0">4. 面向图的程序设计</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/graphorientedprogramming.html#missinglink"><font face="宋体"><font size="+0">4.1.&nbsp;缺少的一环</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/graphorientedprogramming.html#graphicalrepresentationandthedevelopmentprocess"><font face="宋体"><font size="+0">4.2. 图解表示和开发过程</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/graphorientedprogramming.html#traditionalapproach"><font face="宋体"><font size="+0">4.3. 习惯方法</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/graphorientedprogramming.html#whatisgraphorientedprogramming"><font face="宋体"><font size="+0">4.4. 什么是面向图的程序设计</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/graphorientedprogramming.html#buildingblocks"><font face="宋体"><font size="+0">4.5. 组建块</font> </font></a></span></dt></dl>
<dt><span class="chapter"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/deployment.html"><font face="宋体"><font size="+0">5.&nbsp;发布</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/deployment.html#d0e1298"><font face="宋体"><font size="+0">5.1.&nbsp;运行时的相关部分</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/deployment.html#javaruntimeenvironment"><font face="宋体"><font size="+0">5.1.1.&nbsp;Java运行环境</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/deployment.html#jbpmlibraries"><font face="宋体"><font size="+0">5.1.2. jBPM&nbsp;库</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/deployment.html#runtimelibraries"><font face="宋体"><font size="+0">5.1.3.&nbsp;运行时需要的库</font> </font></a></span></dt></dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/deployment.html#configurationfiles"><font face="宋体"><font size="+0">5.2.&nbsp;配置文件</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/deployment.html#jbpmproperties"><font face="宋体"><font size="+0">5.2.1. jbpm.properties</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/deployment.html#hibernatecfgxmlfile"><font face="宋体"><font size="+0">5.2.2. Hibernate cfg xml file</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/deployment.html#businesscalendarconfigurationfile"><font face="宋体"><font size="+0">5.2.3.&nbsp;业务日历配置文件</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/deployment.html#variablemappingconfigurationfile"><font face="宋体"><font size="+0">5.2.4. 变量映射配置稳健</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/deployment.html#converterconfigurationfile"><font face="宋体"><font size="+0">5.2.5. 转换器配置文件</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/deployment.html#defaultmodulesconfigurationfile"><font face="宋体"><font size="+0">5.2.6. 缺省模块配置文件</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/deployment.html#parsersconfigurationfile"><font face="宋体"><font size="+0">5.2.7. 流程文档解析器配置文件</font> </font></a></span></dt></dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/deployment.html#d0e1586"><font face="宋体"><font size="+0">5.3. 在Web应用程序中使用jBPM</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/deployment.html#d0e1597"><font face="宋体"><font size="+0">5.4. 在EJB 包容器中使用jBPM</font> </font></a></span></dt></dl>
<dt><span class="chapter"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/persistence.html"><font face="宋体"><font size="+0">6.&nbsp;永久化</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/persistence.html#d0e1635"><font face="宋体"><font size="+0">6.1.&nbsp;永久化API</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/persistence.html#databaseconfiguration"><font face="宋体"><font size="+0">6.2. 数据库配置</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/persistence.html#managingtransactions"><font face="宋体"><font size="+0">6.3. 管理事务</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/persistence.html#d0e1758"><font face="宋体"><font size="+0">6.4.&nbsp;jBPM数据库</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/persistence.html#d0e1765"><font face="宋体"><font size="+0">6.4.1. Hibernate集成</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/persistence.html#developmentdatabaseishsqldb"><font face="宋体"><font size="+0">6.4.2. 开发数据库是hsqldb</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/persistence.html#supportforotherdatabases"><font face="宋体"><font size="+0">6.4.3. 其他数据库的支持</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/persistence.html#d0e1851"><font face="宋体"><font size="+0">6.4.4.&nbsp;高速缓冲存储器</font> </font></a></span></dt></dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/persistence.html#d0e1856"><font face="宋体"><font size="+0">6.5. Hibernate&nbsp;定制</font> </font></a></span></dt></dl>
<dt><span class="chapter"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html"><font face="宋体"><font size="+0">7.&nbsp;流程模型</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#overview"><font face="宋体"><font size="+0">7.1.&nbsp;综述</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#processgraph"><font face="宋体"><font size="+0">7.2.&nbsp;流程图(process Graph)</font>&nbsp; </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#nodes"><font face="宋体"><font size="+0">7.3. 节点(Nodes)</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#noderesponsibilities"><font face="宋体"><font size="+0">7.3.1. 节点(Node)职责</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#nodetypetasknode"><font face="宋体"><font size="+0">7.3.2. 节点类型(Nodetype)任务(task-node)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#nodetypetaskstate"><font face="宋体"><font size="+0">7.3.3. 节点类型(Nodetype) 状态(state)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#nodetypedecision"><font face="宋体"><font size="+0">7.3.4. 节点类型(Nodetype) 判定(decision)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#nodetypefork"><font face="宋体"><font size="+0">7.3.5. 节点类型(Nodetype) 分叉(fork)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#nodetypejoin"><font face="宋体"><font size="+0">7.3.6. 节点类型(Nodetype) 联合(join)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#nodetypenode"><font face="宋体"><font size="+0">7.3.7. 节点类型(Nodetype)&nbsp;节点(node)</font> </font></a></span></dt></dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#actions"><font face="宋体"><font size="+0">7.4. 动作(Actions)</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#actionconfiguration"><font face="宋体"><font size="+0">7.4.1.&nbsp;动作配置</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#actionreferences"><font face="宋体"><font size="+0">7.4.2. 动作引用</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#events"><font face="宋体"><font size="+0">7.4.3.&nbsp;事件</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#eventpropagation"><font face="宋体"><font size="+0">7.4.4.&nbsp;事件传播</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#s.c.r.i.p.t"><font face="宋体"><font size="+0">7.4.5. s.c.r.i.p.t</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#customevents"><font face="宋体"><font size="+0">7.4.6. 定制事件</font> </font></a></span></dt></dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#superstates"><font face="宋体"><font size="+0">7.5.&nbsp;超状态(superstate)</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#superstatetransitions"><font face="宋体"><font size="+0">7.5.1.&nbsp;超状态 <span style="font-size: 11pt; color: black; font-family: 宋体"><strong>变迁</strong></span> </font></font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#superstateevents"><font face="宋体"><font size="+0">7.5.2. 超状态 事件</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#hierarchicalnames"><font face="宋体"><font size="+0">7.5.3. 分级名字</font> </font></a></span></dt></dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#exceptionhandling"><font face="宋体"><font size="+0">7.6. 异常处理</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#processcomposition"><font face="宋体"><font size="+0">7.7. 流程组成</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#customnodebehaviour"><font face="宋体"><font size="+0">7.8. 定制节点行为</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/processmodelling.html#graphexecution"><font face="宋体"><font size="+0">7.9. 图(Graph)执行</font> </font></a></span></dt></dl>
<dt><span class="chapter"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/context.html"><font face="宋体"><font size="+0">8. 上下文(Context)</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/context.html#accessingvariables"><font face="宋体"><font size="+0">8.1. 存取变量</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/context.html#variablelifetime"><font face="宋体"><font size="+0">8.2. 变量的使用期限</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/context.html#variablepersistence"><font face="宋体"><font size="+0">8.3. 变量永久化</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/context.html#variablescopes"><font face="宋体"><font size="+0">8.4. 变量范围</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/context.html#variableoverloading"><font face="宋体"><font size="+0">8.4.1. 变量<span id="ArticleContent1_ArticleContent1_lblContent">重载(</span> overloading)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/context.html#variableoverriding"><font face="宋体"><font size="+0">8.4.2.&nbsp;变量<span id="ArticleContent1_ArticleContent1_lblContent">重写</span> (overriding)</font> </font></a></span></dt></dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/context.html#transientvariables"><font face="宋体"><font size="+0">8.5. 瞬间变量</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/context.html#customizingvariablepersistence"><font face="宋体"><font size="+0">8.6. 定制变量永久化</font> </font></a></span></dt></dl>
<dt><span class="chapter"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/taskmanagement.html"><font face="宋体"><font size="+0">9. 任务管理</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/taskmanagement.html#tasks"><font face="宋体"><font size="+0">9.1.&nbsp;任务</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/taskmanagement.html#taskinstances"><font face="宋体"><font size="+0">9.2.&nbsp;任务实例</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/taskmanagement.html#taskinstancelifecycle"><font face="宋体"><font size="+0">9.2.1. 任务实例生命周期</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/taskmanagement.html#taskinstancesandgraphexecution"><font face="宋体"><font size="+0">9.2.2. 任务实例及图执行</font> </font></a></span></dt></dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/taskmanagement.html#assignment"><font face="宋体"><font size="+0">9.3. 委派(Assignment)</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/taskmanagement.html#assignmentinterfaces"><font face="宋体"><font size="+0">9.3.1. 委派接口</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/taskmanagement.html#theassignmentdatamodel"><font face="宋体"><font size="+0">9.3.2. 委派数据模型</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/taskmanagement.html#pushmodel"><font face="宋体"><font size="+0">9.3.3. "推"模型</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/taskmanagement.html#pullmodel"><font face="宋体"><font size="+0">9.3.4. "拉"模型</font> </font></a></span></dt></dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/taskmanagement.html#swimlanes"><font face="宋体"><font size="+0">9.4. 泳道(Swimlanes)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/taskmanagement.html#taskevents"><font face="宋体"><font size="+0">9.5. 任务 事件</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/taskmanagement.html#tasktimers"><font face="宋体"><font size="+0">9.6.&nbsp;任务 定时器</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/taskmanagement.html#taskcontrollers"><font face="宋体"><font size="+0">9.7. 任务 控制器</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/taskmanagement.html#customizingtaskinstances"><font face="宋体"><font size="+0">9.8. 定制 任务实例</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/taskmanagement.html#theidentitycomponent"><font face="宋体"><font size="+0">9.9. 身份组件</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/taskmanagement.html#theidentitymodel"><font face="宋体"><font size="+0">9.9.1. 身份模型</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/taskmanagement.html#assignmentexpressions"><font face="宋体"><font size="+0">9.9.2. 赋值表达式</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/taskmanagement.html#firstterms"><font face="宋体"><font size="+0">9.9.2.1. 第一个术语</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/taskmanagement.html#nextterms"><font face="宋体"><font size="+0">9.9.2.2. 下一个术语</font> </font></a></span></dt></dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/taskmanagement.html#removingtheidentitycomponent"><font face="宋体"><font size="+0">9.9.3. 删除身份组件</font> </font></a></span></dt></dl></dd></dl>
<dt><span class="chapter"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/scheduler.html"><font face="宋体"><font size="+0">10. 调度程序</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/scheduler.html#timers"><font face="宋体"><font size="+0">10.1. 定时器</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/scheduler.html#schedulerdeployment"><font face="宋体"><font size="+0">10.2. 调度程序发布</font> </font></a></span></dt></dl>
<dt><span class="chapter"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/businesscalendar.html"><font face="宋体"><font size="+0">11. 业务日历</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/businesscalendar.html#duration"><font face="宋体"><font size="+0">11.1.&nbsp;持久时间</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/businesscalendar.html#configuration"><font face="宋体"><font size="+0">11.2. 配置</font> </font></a></span></dt></dl>
<dt><span class="chapter"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/logging.html"><font face="宋体"><font size="+0">12. 记录</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/logging.html#creationoflogs"><font face="宋体"><font size="+0">12.1.&nbsp;建立日志</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/logging.html#logretrieval"><font face="宋体"><font size="+0">12.2. 日志检索</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/logging.html#datawarehousing"><font face="宋体"><font size="+0">12.3. 数据仓库</font> </font></a></span></dt></dl>
<dt><span class="chapter"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html"><font face="宋体"><font size="+0">13. jBPM&nbsp;流程定义语言 (JPDL)</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#theprocessarchive"><font face="宋体"><font size="+0">13.1.&nbsp;流程档案</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#deployingaprocessarchive"><font face="宋体"><font size="+0">13.1.1. 发布流程档案</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#processversioning"><font face="宋体"><font size="+0">13.1.2. 流程版本(versioning)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#processconversion"><font face="宋体"><font size="+0">13.1.3. 流程转换(conversion)</font> </font></a></span></dt></dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#delegation"><font face="宋体"><font size="+0">13.2. 代理</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#thejbpmclassloader"><font face="宋体"><font size="+0">13.2.1.&nbsp; jBPM类载入器</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#theprocessclassloader"><font face="宋体"><font size="+0">13.2.2. 流程类载入器(class loader)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#configurationofdelegations"><font face="宋体"><font size="+0">13.2.3. 代理配置</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#configtypefield"><font face="宋体"><font size="+0">13.2.3.1.&nbsp;配置类型 field</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#configtypebean"><font face="宋体"><font size="+0">13.2.3.2. 配置类型 bean</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#configtypeconstructor"><font face="宋体"><font size="+0">13.2.3.3. 配置类型 constructor</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#configtypeconfigurationproperty"><font face="宋体"><font size="+0">13.2.3.4. 配置类型 configuration-property</font> </font></a></span></dt></dl></dd></dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#d0e3606"><font face="宋体"><font size="+0">13.3. JPDL xml schema</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#processdefinition.element"><font face="宋体"><font size="+0">13.3.1. process-definition(流程定义)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#node.element"><font face="宋体"><font size="+0">13.3.2. node(节点)</font>&nbsp; </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#common.node.elements"><font face="宋体"><font size="+0">13.3.3. common node elements(常见节点元素)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#startstate.element"><font face="宋体"><font size="+0">13.3.4. start-state(开始状态)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#endstate.element"><font face="宋体"><font size="+0">13.3.5. end-state(结束状态)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#state.element"><font face="宋体"><font size="+0">13.3.6. state(状态)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#tasknode.element"><font face="宋体"><font size="+0">13.3.7. task-node(任务节点)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#processstate.element"><font face="宋体"><font size="+0">13.3.8. process-state(流程状态)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#superstate.element"><font face="宋体"><font size="+0">13.3.9. super-state(超状态)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#fork.element"><font face="宋体"><font size="+0">13.3.10. fork(交叉)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#join.element"><font face="宋体"><font size="+0">13.3.11. join(联合)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#decision.element"><font face="宋体"><font size="+0">13.3.12. decision(判定)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#event.element"><font face="宋体"><font size="+0">13.3.13. event(事件)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#transition.element"><font face="宋体"><font size="+0">13.3.14. transition(转换)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#action.element"><font face="宋体"><font size="+0">13.3.15. action(动作)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#s.c.r.i.p.t.element"><font face="宋体"><font size="+0">13.3.16. s.c.r.i.p.t(脚本)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#expression.element"><font face="宋体"><font size="+0">13.3.17. expression(表达式)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#variable.element"><font face="宋体"><font size="+0">13.3.18. variable(变量)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#handler.element"><font face="宋体"><font size="+0">13.3.19. handler(处理器)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#timer.element"><font face="宋体"><font size="+0">13.3.20. timer(定时器)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#create.timer.element"><font face="宋体"><font size="+0">13.3.21. create-timer(建立定时器)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#cancel.timer.element"><font face="宋体"><font size="+0">13.3.22. cancel-timer(放弃定时器)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#task.element"><font face="宋体"><font size="+0">13.3.23. task(任务)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#swimlane.element"><font face="宋体"><font size="+0">13.3.24. swimlane(泳道)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#assignment.element"><font face="宋体"><font size="+0">13.3.25. assignment(委派)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#controller.element"><font face="宋体"><font size="+0">13.3.26. controller(控制器)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#subprocess.element"><font face="宋体"><font size="+0">13.3.27. sub-process(子流程)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#condition.element"><font face="宋体"><font size="+0">13.3.28. condition(条件)</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/jpdl.html#exceptionhandler.element"><font face="宋体"><font size="+0">13.3.29. exception-handler(异常处理)</font> </font></a></span></dt></dl></dd></dl>
<dt><span class="chapter"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/security.html"><font face="宋体"><font size="+0">14.&nbsp;安全</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/security.html#securitytodos"><font face="宋体"><font size="+0">14.1.&nbsp;要做的</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/security.html#authentication"><font face="宋体"><font size="+0">14.2. 验证</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/security.html#authorization"><font face="宋体"><font size="+0">14.3. 授权</font> </font></a></span></dt></dl>
<dt><span class="chapter"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/tdd.html"><font face="宋体"><font size="+0">15. TDD for workflow</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/tdd.html#intoducingtddforworkflow"><font face="宋体"><font size="+0">15.1. Introducing TDD for workflow</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/tdd.html#xmlsources"><font face="宋体"><font size="+0">15.2. XML sources</font> </font></a></span>
<dd>
<dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/tdd.html#parsingaprocessarchive"><font face="宋体"><font size="+0">15.2.1. Parsing a process archive</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/tdd.html#parsinganxmlfile"><font face="宋体"><font size="+0">15.2.2. Parsing an xml file</font> </font></a></span>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/tdd.html#parsinganxmlstring"><font face="宋体"><font size="+0">15.2.3. Parsing an xml String</font> </font></a></span></dt></dl>
<dt><span class="section"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/tdd.html#testingsubprocesses"><font face="宋体"><font size="+0">15.3. Testing sub processes</font> </font></a></span></dt></dl>
<dt><span class="chapter"><a href="mk:@MSITStore:F:\temp\JBPM31~1.CHM::/pluggable.html"><font face="宋体"><font size="+0">16. 可插入架构</font> </font></a></span></dt>
<img src ="http://www.blogjava.net/yifeng/aggbug/223947.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yifeng/" target="_blank">忆风</a> 2008-08-24 08:02 <a href="http://www.blogjava.net/yifeng/archive/2008/08/24/223947.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EJB简介</title><link>http://www.blogjava.net/yifeng/archive/2008/08/24/223938.html</link><dc:creator>忆风</dc:creator><author>忆风</author><pubDate>Sat, 23 Aug 2008 21:02:00 GMT</pubDate><guid>http://www.blogjava.net/yifeng/archive/2008/08/24/223938.html</guid><wfw:comment>http://www.blogjava.net/yifeng/comments/223938.html</wfw:comment><comments>http://www.blogjava.net/yifeng/archive/2008/08/24/223938.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yifeng/comments/commentRss/223938.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yifeng/services/trackbacks/223938.html</trackback:ping><description><![CDATA[<span class="bright-message-list">1、ejb 基础知识<br />
（1） 无状态会话bean<br />
&nbsp;&nbsp;&nbsp; 不保存客户机的会话状态<br />
&nbsp;&nbsp;&nbsp; 优点：使用小量的实例即可满足大量的客户。每个实例都没有标识，相互之间是等价的。<br />
&nbsp;&nbsp;&nbsp; 等？的无状态会话bean： 多次和一次调用的结果和效应相同。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在集群中可以负载均衡 a 机器失败，可以在b机器上重试<br />
&nbsp;&nbsp;&nbsp; 非等？的无状态会话bean： 如：计数器<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不能自动因故障而进行切换。<br />
（2） 有状态会话bean<br />
&nbsp;&nbsp;&nbsp; 保存客户机的会话状态<br />
&nbsp;&nbsp;&nbsp; 特点： 在有会话状态会话的bean例子中，出纳员的数量等于活动的顾客的数量，这可以简化编程模式<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; weblogic 通过内存复制技术 在集群中进行负载均衡<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 内存复制技术： 每个有会话状态的bean实例都将存储在两个服务器的内存中，一个服务器作为主服务器，另一个作为辅助服务器。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果主失败，辅助变为主，然后自动选择别的可用的服务器作为辅助。<br />
&nbsp;&nbsp;&nbsp; 遗憾： 很难在servlet 和jsp中用好有状态会话bean。可能会发生并发现象，产生RemoteException<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; weblogic 的&lt;allow-concurrent-calls&gt; 可以封锁任何并发的调用。<br />
&nbsp;&nbsp;&nbsp; 同步： 可以有选择地实现 javax.ejb.SessionSynchronization接口<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; afeterBegin()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //进入事务时<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; beforeCompletion()&nbsp;&nbsp;&nbsp; //提交事务前,用于提交前把缓存的数据写到数据库中.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; afterCompletion()&nbsp;&nbsp;&nbsp;&nbsp; //提交事务后,用于释放共享资源或者更新事务提交和终止方面的统计信息.<br />
&nbsp;&nbsp;&nbsp;&nbsp; 会话bean通过其 SessionContext 对象中的 getUserTransaction() 方法,取得对UserTransaction的应用<br />
&nbsp;&nbsp;&nbsp;&nbsp; 通常 SessionContext 被存放在成员变量中<br />
&nbsp;&nbsp;&nbsp;&nbsp; ** 记住是在调用ejb.create()方法前调用 setUserTransaction() 方法<br />
&nbsp;&nbsp;&nbsp;&nbsp; 利用对 UserTransaction 的引用会话可以使用 begin() 、commit()、rollback() 方法界定一个事务.<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
（3） 实体 bean： <br />
&nbsp;&nbsp;&nbsp; 它有一个主健作为唯一的标识符<br />
&nbsp;&nbsp;&nbsp; 组成部分: 由本地接口、远程接口、bean类、主健类和配置描述器组成。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 本地接口：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 扩展了javax.ejb.EJBHome接口，包括create（）、remove（）、finder 和home等方法<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1)create（）方法调用bean类中的ejbCreate（）方法。相当于数据的insert 方法。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2)remove（）方法相当于数据库的delete操作。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3)finder（）方法，使客户能够查询和接收满足查询条件的实体bean的引用。每个实体bean的本地接口中都必须<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 有一个findByPrimaryKey() 方法<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4)home 方法，类似于无状态会话bean。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 主健类：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 实体bean必须包括一个主健类，主健类用于标识实体bean实例，而且实体bean数据类型必须是唯一的。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 主健类可以是java的基本类型String Integer 也可以是用户自定义的。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 也可以是多个字段的主健的复合主健。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bean 类和bean的上下文环境：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 实现javax.ejb.EJBObject 接口,其中包含业务方法的语法格式定义.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bean 类实现了javax.ejb.EntityBean接口,同javax.ejb.SessionBean接口一样,EntityBean 接口包含了EJB<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 容器调用bean实例的语法格式.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在bean的构造器执行之后,立即调用setEntityContext() 方法,同时把bean实例的EntityContext 传递给它.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bean类实现了home方法和远程接口中的业务方法,home方法是针对匿名实例的方法不应使用有关的主健值.<br />
<br />
&nbsp;&nbsp;&nbsp; 分为：<br />
&nbsp;&nbsp;&nbsp; 容器管理持久性（Container－Managerd Persistence）CMP<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 特点： EJB 容器自动生成，用于把实体bean的数据写入到数据库中。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 优点： bean作者可以避免编写实体bean与关系数据库数据访问方面的代码。cmp将自动处理这一过程。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 个性: 每一个cmp 实体bean 都有一组容器管理的字段,这些字段存储在数据库,并可从中加载.通常,每个容器管理的字段都对应于<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 关系数据库中的一个列.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 容器管理的每个字段必须在ejb-jar.xml中定义,这使容器能够把容器管理的字段与bean类中的set和get方法进行匹配比较.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 另外,bean作者可以增加另外一个cmp配置描述文件 weblogic-cmp-rdbms.xml,其中包含数据库表名和每个容器管理的字<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 段和相应的数据列的映射.<br />
<br />
&nbsp;&nbsp;&nbsp; bean管理持久性（Bean－Managerd Persistence ） BMP<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 特点： 在bmp实体中，bean作者需要自己编写数据库访问代码，也就是编写JDBC代码，插入、删除和查询数据库中的实体bean数据。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 优点： 可以让bean的作者完全灵活的处理实体bean的持久性数据，因为作者需要写数据访问的代码，他几乎可以使用任何持久性存<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 储方式ejb2.0 cmp提供实体bean之间的标准关系映射，使容器能自动管理业务对象之间的交互。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmp拥有更多的访问控制，因此cmp比bmp有较好的性能。<br />
<br />
（4） 消息 bean<br />
&nbsp;&nbsp;&nbsp; 把JMS 和EJB 成功结合在一起，集成的结果<br />
&nbsp;&nbsp;&nbsp; 特点：客户机不需要调用消息bean 相反： 客户机只需要发一个消息给jMS目的。<br />
&nbsp;&nbsp;&nbsp; 在消息到达以后，消息bean的onmessage（）方法将被调用，以处理这个消息。<br />
&nbsp;&nbsp;&nbsp; 消息bean用于在服务器中执行异步操作。<br />
<br />
2。EJB 组成<br />
（1）远程接口<br />
&nbsp;&nbsp;&nbsp; public interface HelloWord extents EJBObject<br />
&nbsp;&nbsp;&nbsp; ｛<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //EJBObject 接口方法<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EJBHome getEJBHome() throws RemoteException;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object getPrimaryKey() throws RemoteException;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void remove() throws RemoteException, RemoveException;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Handle getHandle() throws RemoteException;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boolean isIdentical(EJBObject ejbObject) throws RemoteException;<br />
&nbsp;&nbsp;&nbsp; ｝<br />
（2）本地接口<br />
&nbsp;&nbsp;&nbsp; 本地接口是ejb工厂，客户机可以使用本地接口创建、找出和删除ejb实例。只需写本地接口中的方法的语法调用格式<br />
&nbsp;&nbsp;&nbsp; public class HelloWorldHome extends EJBHome<br />
&nbsp;&nbsp;&nbsp; ｛<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //EJBHome 接口方法<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void remove(Handle handle) throws RemoteException, RemoveException;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void remove(Object o) throws RemoteException, RemoveException;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EJBMetaData getEJBMetaData() throws RemoteException;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HomeHandle getHomeHandle() throws RemoteException;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Home<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public HelloWorld create() throws CreateException, RemoteException;<br />
&nbsp;&nbsp;&nbsp; ｝<br />
<br />
（3）bean 类<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; public class HelloWorldBean implements SessionBean<br />
&nbsp;&nbsp;&nbsp; ｛<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // SessionBean 中的方法<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void setSessionContext(SessionContext sessionContext) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**调用次方法会话结束*/<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void ejbRemove() <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //ejb通过待命和活动的机制，管理一组正在工作的有状态会话bean实例<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**活动*/<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void ejbActivate() <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**待命*/<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void ejbPassivate() <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // bean类<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 每个home 的create 方法对应一个ejbCreate（）方法<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 有会话状态有很多不同版本的create（）方法。而create 方法必须有ejbCreate（）方法与之一一对应<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void ejbCreate()<br />
<br />
<br />
&nbsp;&nbsp;&nbsp; ｝<br />
<br />
&nbsp;&nbsp;&nbsp; 不要在ejb类中类中实现远程接口<br />
3. EJB 配置描述器<br />
（1）ejb－jar.xml<br />
&lt;ejb-jar&gt; (注释) <br />
&nbsp;&nbsp;&nbsp; &lt;enterprise-beans&gt;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;session&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ejb-name&gt;HelloWorld（ejbname）&lt;/ejb-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;home&gt;com.dhc.helloworld.HelloWorldHome（本地接口类）&lt;/home&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;remote&gt;com.dhc.helloworld.HelloWorld（远程接口类）&lt;/remote&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ejb-class&gt;com.dhc.helloworld.HelloWorldBean（bean类）&lt;/ejb-class&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;session-type&gt;Stateless（无状态会话）&lt;/session-type&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;transaction-type&gt;Bean（bean管理的事务）&lt;/transaction-type&gt;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/session&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/enterprise-beans&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;container-transaction&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;method&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ejb-name&gt;ShoppingCartEjb&lt;/ejb-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;method-name&gt;*（说明ShoppingCartEjb的默认事务属性指定为Required）&lt;/method-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/method&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;trans-attribute&gt;Required（容器管理的事务使用的属性 Nerver、NotSupported<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 、Supports、Mandatory、Required、RequiredNew）&lt;/trans-attribute&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/container-transaction&gt;<br />
&lt;/ejb-jar&gt;<br />
（2）weblogic-ejb-jar.xml (注释)<br />
&lt;weblogic-ejb-jar&gt;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; &lt;weblogic-enterprise-bean&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ejb-name&gt;HelloWorld（ejb名称）&lt;/ejb-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;jndi-name&gt;HelloWorldEJB（jndi名称）&lt;/jndi-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;max-bean-in-freepool&gt;10（限制不会有超过10个无状态会话bean并发运行）&lt;/max-bean-in-freepool&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;max-bean-in-cache&gt;10（放到内存缓存中的有状态会话bean的最大数量）&lt;/max-bean-in-cache&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/weblogic-enterprise-bean&gt;<br />
&lt;/weblogic-ejb-jar&gt; <br />
<br />
4 . 建立ejb 档案文件<br />
com/dhc/helloworld/（package）<br />
com/dhc/helloworld/HelloWorld（远程接口）<br />
com/dhc/helloworld/HelloWorldHome（本地接口）<br />
com/dhc/helloworld/HelloWorldBean（bean类）<br />
META-INF<br />
META-INF/ejb－jar.xml（配置描述器）<br />
META-INF/weblogic-ejb-jar.xml（weblogic服务器配置描述器）<br />
<br />
说明： META-INF 必须为大写<br />
<br />
5 . 容器管理的事务<br />
Nerver :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不参与事务,如果参与产生RemoteException<br />
NotSupported:&nbsp;&nbsp; 不能参与<br />
Supports:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果调用者正在参与事务,相应的EJB调用也可以参与事务,否则不能<br />
Mandatory&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果调用者有一个事务,相应的EJB可以参与事务,否则,TransactionRequiredException<br />
Required&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果调用者有一个事务,相应的EJB可以参与事务,否则,容器将在调用相应的EJB之前,开始一个事务.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当方法调用完成以后,即提交该事务.<br />
RequiresNew&nbsp;&nbsp;&nbsp;&nbsp; 在调用相应的EJB之前,开始一个新的事务,当方法调用返回时,即提交这个事务.<br />
<br />
<br />
6、ejb 引用<br />
<br />
在ejb－jar.xml<br />
&lt;ejb-ref&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;description&gt; an EJB reference to the Widget EJB(描述)&lt;/description&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;ejb-ref-name&gt;ejb/WidgetEJB&lt;/ejb-ref-name&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;ejb-ref-type&gt;session&lt;/ejb-ref-type&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;home&gt;com.dhc.WidgetHome&lt;/home&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;remote&gt;com.dhc.Widget&lt;/remote&gt;<br />
&lt;/ejb-ref&gt;<br />
<br />
在 weblogic-ejb-jar.xml <br />
&lt;ejb-reference-description&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;ejb-ref-name&gt;ejb/WidgeEJB&lt;/ejb-ref-name&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;jndi-name&gt;DeployedWidge&lt;/jndi-name&gt;<br />
&lt;/ejb-reference-description&gt;<br />
<br />
程序<br />
Content ctx = new InitialContent();<br />
Object h = ctx.lookup("java:/comp/env/ejb");&nbsp;&nbsp;&nbsp; //环境变量是只读的,而且是当前ejb的本地变量.<br />
WidgetHome home = (WidgetHome)PortableRemoteObject.narrow(h,WidgeHome.class);<br />
<br />
7. 资源管理器的引用<br />
定义资源管理的引用<br />
例子： 建立 jdbc、DBPool与JDBC数据源的映射<br />
在ejb－jar.xml<br />
&lt;resource-ref&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;description&gt;(描述)&lt;/description&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;res-ref-name&gt;jdbc/BDPool&lt;/res-ref-name&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;res-type&gt;javax.sql.DataSource&lt;/res-type&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;res-auth&gt;Container&lt;/res-auth&gt;<br />
&lt;/resource-ref&gt;<br />
<br />
在 weblogic-ejb-jar.xml <br />
&lt;resource-description&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;res-ref-name&gt;jdbc/DBPool&lt;/res-ref-name&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;jndi-name&gt;DBPool&lt;/jndi-name&gt;<br />
&lt;/resource-description&gt;<br />
<br />
config.xml<br />
<br />
&lt;JDBCTxDataSource <br />
&nbsp;&nbsp;&nbsp; name="DBPool"<br />
&nbsp;&nbsp;&nbsp; Targets="myserver"<br />
&nbsp;&nbsp;&nbsp; JDDIName="DBPool" (jndi名称)<br />
&nbsp;&nbsp;&nbsp; PoolName ="DevelopmentPool"<br />
/&gt;<br />
<br />
引用的优点<br />
我们用大量的映射和配置，才建立了资源管理器的引用，但是还是很值得的。<br />
以为便于部署人员重新配置应用而不需要修改实际的bean类代码。甚至也不需要修改ejb的配置描述器<br />
java bean 代码<br />
<br />
Content ctx = new InitialContent();<br />
DataSource dataSource = (DataSource)ctx.lookup("java:/comp/env/jdbc/DBPool");<br />
<br />
8 . 句柄： 作为一个串行化的对象，句柄中封装了足够的信息，以便重建对EJBObject的引用。<br />
句柄可用于在两个相互合作的进程中传递EJBObject的引用。接受进程即可从句柄中取得EJBObject的引用。<br />
<br />
为了取得句柄，可以调用EJBObject接口的getHandle（）方法，返回一个Handle实例<br />
为了重建EJBObject 引用。可以使用Handle 接口的getEJBObject（）方法。<br />
<br />
例子：<br />
&nbsp;&nbsp;&nbsp; HelloWorld hw = home.create();<br />
&nbsp;&nbsp;&nbsp; javax.ejb.Handle handle = hw.getHandle();<br />
&nbsp;&nbsp;&nbsp; HelloWorld helloworld = (HelloWorld)PortableRemoteObject.narrow(handle.getEJBObject(),HelloWorld.class);<br />
<br />
<br />
HomeHandle:<br />
&nbsp;&nbsp;&nbsp; 类似handle ，但不能用于引用EJBObject<br />
&nbsp;&nbsp;&nbsp; HomeHandle 包含足够的信息，可以重建EJBHome（）的引用。<br />
&nbsp;&nbsp;&nbsp; 差异：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 是调用 getHomeHandle（）方法 和getEJBHome（）方法<br />
例子片断：<br />
&nbsp;&nbsp;&nbsp;&nbsp; Content ctx ＝ new InitialContext();<br />
&nbsp;&nbsp;&nbsp;&nbsp; Object h = ctx.lookup("HelloWorldEJB");<br />
&nbsp;&nbsp;&nbsp;&nbsp; HelloWorldHome home = (HelloWorldHome)PortableRemoteObject.narrow(h,HelloWorldHome.class);<br />
&nbsp;&nbsp;&nbsp;&nbsp; HomeHandle homehandle = home.getHomeHandle();<br />
&nbsp;&nbsp;&nbsp;&nbsp; Object nh = homehandle.getEJBHome();<br />
&nbsp;&nbsp;&nbsp;&nbsp; HelloWorldHome newHomeReference = (HelloWorldHome)PortableRemoteObject.narrow(nh,HelloWorldHome.class);<br />
<br />
优点:<br />
&nbsp;&nbsp;&nbsp;&nbsp; 他们可以自动的存储重建引用所需的信息<br />
<br />
9.使用事务的技巧:<br />
(1) 一个事务不要涉及太多的操作.<br />
(2) 容器管理和bean管理的事务<br />
&nbsp;&nbsp;&nbsp; 事务既耗费应用服务器中的资源,又耗费数据库资源,所以事务越短越好.<br />
&nbsp;&nbsp;&nbsp; 尽量使用容器管理事务而不要采用bean管理事务的方式.<br />
(3) ejb遇到错误,需要强制事务回滚. 使用EJBObject.setRollbackOnly();<br />
(4) 不能让事务涉及web层和表示逻辑<br />
(5) 企业应用中不应当选用supports 事务属性,因为只有调用者开始一个事务后,ejb才能在事务中运行.<br />
</span>
<img src ="http://www.blogjava.net/yifeng/aggbug/223938.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yifeng/" target="_blank">忆风</a> 2008-08-24 05:02 <a href="http://www.blogjava.net/yifeng/archive/2008/08/24/223938.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>