﻿<?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-&lt;b&gt;&lt;font size='4'&gt;萧秋水的博客&lt;/font&gt;&lt;/b&gt;</title><link>http://www.blogjava.net/Benjamin/</link><description>&lt;br&gt;&lt;font size='2.5'&gt;带着淡淡的倦意，轻轻的忧惺，宛若远山含笑迷蒙，但又如闪电惊雷般震人心魄……&lt;/font&gt;</description><language>zh-cn</language><lastBuildDate>Sat, 18 Apr 2026 17:59:10 GMT</lastBuildDate><pubDate>Sat, 18 Apr 2026 17:59:10 GMT</pubDate><ttl>60</ttl><item><title>如何使用af:selectManyChoice组件 - 转载</title><link>http://www.blogjava.net/Benjamin/archive/2011/09/16/358789.html</link><dc:creator>萧秋水</dc:creator><author>萧秋水</author><pubDate>Fri, 16 Sep 2011 05:48:00 GMT</pubDate><guid>http://www.blogjava.net/Benjamin/archive/2011/09/16/358789.html</guid><wfw:comment>http://www.blogjava.net/Benjamin/comments/358789.html</wfw:comment><comments>http://www.blogjava.net/Benjamin/archive/2011/09/16/358789.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/Benjamin/comments/commentRss/358789.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Benjamin/services/trackbacks/358789.html</trackback:ping><description><![CDATA[<div><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">af:selectManyChoice 是一个下拉多选框，如下图：</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">&nbsp;<img alt="" height="158" src="http://www.ofmclub.com/sites/default/files/lov.png" title="" width="99" style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; " />&nbsp; 这个组件使用起来不是那么容易，它需要将表单中的一个column的attribute 和 组件中的selectitems之间互相转换。</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">正好今天有个客户问起，兴致所致就写了简单的例子，<a href="http://115.com/file/aq1zp7jc" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; font-weight: bold; color: #3c7c41; ">下载</a>。</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">&nbsp;</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">我不详细展开讲了，简要描述下：</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">1） af:selectManyChoice 的value attribute 绑定到一个managed bean的get和set 方法上</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">2） af:selectManyChoice的autosumit=true, immediate=true</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">3)&nbsp;&nbsp; 可选择值为一个Static List的View Object， 在页面的binding中配置该lov，并且在selectItems的value属性绑定到该lov。</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">4）在af:selectManyChoice 的value对应的manage bean的get/set方法中，将页面选择的index对应到lov的具体值并存放到数据库，读取则反之。</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">&nbsp;</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">下载包的密码是:&nbsp;<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#103;&#101;&#110;&#101;&#46;&#120;&#117;&#106;&#105;&#110;&#64;&#103;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; font-weight: bold; color: #3c7c41; ">gene.xujin@gmail.com</a>&nbsp;</p></div><img src ="http://www.blogjava.net/Benjamin/aggbug/358789.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Benjamin/" target="_blank">萧秋水</a> 2011-09-16 13:48 <a href="http://www.blogjava.net/Benjamin/archive/2011/09/16/358789.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>row.attributeName vs. row.bindings.attributeName - 转载</title><link>http://www.blogjava.net/Benjamin/archive/2011/09/16/358788.html</link><dc:creator>萧秋水</dc:creator><author>萧秋水</author><pubDate>Fri, 16 Sep 2011 05:46:00 GMT</pubDate><guid>http://www.blogjava.net/Benjamin/archive/2011/09/16/358788.html</guid><wfw:comment>http://www.blogjava.net/Benjamin/comments/358788.html</wfw:comment><comments>http://www.blogjava.net/Benjamin/archive/2011/09/16/358788.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Benjamin/comments/commentRss/358788.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Benjamin/services/trackbacks/358788.html</trackback:ping><description><![CDATA[<div><span style="color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">在ADF页面上有两种EL的引用af:tree,af:treeTable,af:table的数据集合的方式。一种是#{row.attributeName}，另一种是#{row.bindings.attributeName.inputValue}。 这两者的区别是：前者是只读的 而后者是可读写的。前者这是将该属性以字符串的形式返回，该EL的返回值是一个String类型，后者则不同，#{row.bindings.attributeName}是一个Attribute Binding, 在运行时是一个FacesCtrlAttrsBinding 类的实例，该类是框架内部使用的类，继承了JUCtrlAttrsBinding。所以只要表格需要更新，就应该使用{row.bindings.attributeName.inputValue}，另外一个例子是#{node.attributeName}，node表示了树组件中的一个节点，可以对应到table组件的row。</span></div><img src ="http://www.blogjava.net/Benjamin/aggbug/358788.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Benjamin/" target="_blank">萧秋水</a> 2011-09-16 13:46 <a href="http://www.blogjava.net/Benjamin/archive/2011/09/16/358788.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ADF Faces中如何跳过验证 - 转载</title><link>http://www.blogjava.net/Benjamin/archive/2011/09/16/358787.html</link><dc:creator>萧秋水</dc:creator><author>萧秋水</author><pubDate>Fri, 16 Sep 2011 05:42:00 GMT</pubDate><guid>http://www.blogjava.net/Benjamin/archive/2011/09/16/358787.html</guid><wfw:comment>http://www.blogjava.net/Benjamin/comments/358787.html</wfw:comment><comments>http://www.blogjava.net/Benjamin/archive/2011/09/16/358787.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Benjamin/comments/commentRss/358787.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Benjamin/services/trackbacks/358787.html</trackback:ping><description><![CDATA[<div><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">ADF具有一个非常健壮的验证框架。表单验证可以在各个层次上进行（view, model和business service）。如果需要详细研究验证机制，请参考<a href="http://download.oracle.com/docs/cd/E16162_01/web.1112/e16182/bcvalidation.htm#sm0231" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; font-weight: bold; color: #3c7c41; ">Fusion Developer's Guide for Oracle Application Development Framework.</a></p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">在现实的开发过程中，经常有一些页面需要暂时的跳过默认的验证，本文旨在讨论下常见的use case:</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; "><span style="font-size: 16px; "><strong style="font-weight: 700; ">1. Keep immediate=true</strong></span></p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">&nbsp;一个最常用的方式就是将UICOMPONENT的immediate属性设置为true，这样可以将对组件的处理提前到<strong style="font-weight: 700; ">Apply Request Values阶段。关于immediate属性可以参考&nbsp;<a href="https://cwiki.apache.org/confluence/display/MYFACES/How+the+immediate+attribute+works" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; color: #3c7c41; ">wiki</a></strong></p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; "><strong style="font-weight: 700; ">典型用例：</strong>cancel button，在取消按钮点击时，页面是不需要验证提交的表单的。可以将按钮组建的immediate属性设为'true'来实现这个功能。 如果是一个reset按钮，那么除了immediate属性需要设为'true&#8216;外，最好还要调用下相关其他input组件的<a href="http://java.sun.com/javaee/javaserverfaces/1.2/docs/api/javax/faces/component/UIInput.html#resetValue()" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; font-weight: bold; color: #3c7c41; ">resetValue()</a>方法，来恢复初始状态。</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">&nbsp;</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; "><span style="font-size: 16px; "><strong style="font-weight: 700; ">2. SkipValidation</strong></span></p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">另外一种方式，是设置pagedefinition 文件的SkipValidation 属性。该属性可以控制跳过model层的验证。需要注意的是，这个属性只对entity level的validation rule起作用，对于entity object的attribute上定义的validation rule是没有作用的。另外对于浏览器端的验证(javascript），这个属性也是没法控制的。</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">这个属性可以在每个页面对应的Page Definition 文件中找到，如下图：</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">&nbsp;<img alt="" height="380" src="http://www.ofmclub.com/sites/default/files/skip1.png" title="" width="640" style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; " /></p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">&nbsp;这个属性可能有的值，见下图：</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; "><img alt="" height="409" src="http://www.ofmclub.com/sites/default/files/skip2.png" title="" width="411" style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; " /></p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; "><strong style="font-weight: 700; ">a. SkipValidation=true</strong></p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">设为true则在form提交过程中会跳过Model层的验证，直到commit的时候才会进行验证。</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; "><strong style="font-weight: 700; ">典型场景：</strong>如需要在一张表中输入很多行信息，用户可能希望可以在页面中以任何顺序输入信息，不希望每次table selection事件都会触发验证。</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; "><strong style="font-weight: 700; ">b. SkipValidation=custom</strong></p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">设为custom的时候，需要开发人员实现一个oracle.binding.BindingContainerValidator的接口的类，并用EL配置，如图：</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">&nbsp;<img alt="" height="405" src="http://www.ofmclub.com/sites/default/files/skip3.png" title="" width="411" style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; " /></p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">&nbsp;这个选择项给了开发人员更多的空间来应对复杂的业务需求，开发人员可以自定义如何对表单进行验证。</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; "><strong style="font-weight: 700; ">c. SkipValidation =&nbsp;<strong style="font-weight: 700; ">skipDataControls</strong></strong></p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; ">skipDataControls 选择项的意思是会跳过data control这个level的验证，或者说是事务级别的验证。它只会对当前的binding container中的iterator的current row进行验证，而不会对其他不相关的提交的数据进行验证。</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; "><strong style="font-weight: 700; ">典型场景:&nbsp;</strong>在一个页面上使用了多个data control，提交一个data control不会验证同一个页面中的其他data control中的数据。</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; "><strong style="font-weight: 700; ">d. SkipValidation=false</strong></p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; "><strong style="font-weight: 700; ">默认值，不会跳过验证。</strong></p></div><img src ="http://www.blogjava.net/Benjamin/aggbug/358787.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Benjamin/" target="_blank">萧秋水</a> 2011-09-16 13:42 <a href="http://www.blogjava.net/Benjamin/archive/2011/09/16/358787.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何开始学习ADF和Jdeveroper 11g - 转载</title><link>http://www.blogjava.net/Benjamin/archive/2011/09/16/358779.html</link><dc:creator>萧秋水</dc:creator><author>萧秋水</author><pubDate>Fri, 16 Sep 2011 03:58:00 GMT</pubDate><guid>http://www.blogjava.net/Benjamin/archive/2011/09/16/358779.html</guid><wfw:comment>http://www.blogjava.net/Benjamin/comments/358779.html</wfw:comment><comments>http://www.blogjava.net/Benjamin/archive/2011/09/16/358779.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Benjamin/comments/commentRss/358779.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Benjamin/services/trackbacks/358779.html</trackback:ping><description><![CDATA[<div><header style="margin-left: 10px; margin-right: 10px; color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; "><h1><br /></h1></header><div region-content"="" style="color: #555555; font-family: 'Helvetica Nueue', 'Trebuchet MS', Arial, 'Nimbus Sans L', FreeSans, sans-serif; font-size: 12px; line-height: 18px; background-color: #ffffff; "><div id="block-system-main" block-system="" block-odd="" block-count-3=""  block-region-content"="" role="main" style="position: relative; clear: both; margin-bottom: 15px; margin-top: 0px; margin-right: 0px; margin-left: 0px; "><div clearfix"="" style="margin-left: 10px; margin-right: 10px; background-image: none; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: initial; border-top-left-radius: 4px 4px; border-top-right-radius: 4px 4px; border-bottom-right-radius: 4px 4px; border-bottom-left-radius: 4px 4px; background-position: initial initial; background-repeat: initial initial; "><div><article id="article-15" article-type-blog="" article-promoted="" odd="" article-full=""  clearfix"="" about="/content/%E5%A6%82%E4%BD%95%E5%BC%80%E5%A7%8B%E5%AD%A6%E4%B9%A0adf%E5%92%8Cjdeveroper-11g" typeof="sioc:Post sioct:BlogPost" role="article" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; "><footer style="font-size: 0.9em; margin-top: 3px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span property="dc:date dc:created" content="2011-09-04T08:36:02+08:00" datatype="xsd:dateTime" rel="sioc:has_creator">由&nbsp;<span xml:lang="" about="/users/gene" typeof="sioc:UserAccount" property="foaf:name">gene</span>&nbsp;</span></footer><div style="line-height: 1.5em; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; "><div field-name-body="" field-type-text-with-summary=""  field-label-hidden"=""><div even"="" property="content:encoded"><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">作为第一篇博客，先给一些资料可以帮助初学者开始学习ADF和Jdeveloper11g</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">1.首先毫无疑问，你要懂java语言， 可以看看<a href="http://www.mindview.net/Books/TIJ/" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; font-weight: bold; color: #3c7c41; ">Thinking In Java</a>， 或者原来sun的网上的一些文档<a href="http://java.sun.com/docs/books/tutorial/getStarted/index.html" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; font-weight: bold; color: #3c7c41; ">&nbsp;Sun&#8216;s Online Docs</a>.</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">2. 在学习语言的过程中，可以使用jdeveloper作为开发的工具，可以熟悉一下编码/Debug/Syntax的环境。jdev也提供了丰富的代码模板，自动补全以及重构的功能。具体可以参考<a href="http://st-curriculum.oracle.com/obe/jdev/obe11jdev/ps1/introjdevide/introjdevide.htm" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; font-weight: bold; color: #3c7c41; ">IDE教程</a>。</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">3.接下去，可以开始ADF的学习。可以先看一下&nbsp;<a href="http://www.oracle.com/technetwork/developer-tools/jdev/overview/jdeveloper-reviewrguide-086026.html" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; font-weight: bold; color: #3c7c41; ">Getting Started Guides</a>。看一下该框架的白皮书，知道这个框架可以做些什么，也可以在那里找到一些demo。</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">4.然后做一个step by step的教程，<a href="http://download.oracle.com/docs/cd/E18941_01/tutorials/jdtut_11r2_55/jdtut_11r2_55_1.html" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; font-weight: bold; color: #3c7c41; ">文档链接</a>。通过这个教程你可以了解ADF学习的过程，有个初次的印象。如果仔细阅读每一步的说明，在做这个练习的同时也会了解很多的开发细节。 除此之外，还有两个深入学习的教程，<a href="http://st-curriculum.oracle.com/obe/jdev/obe11jdev/ps1/adf_richclient/adfrichclient.htm" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; font-weight: bold; color: #3c7c41; ">ADF Focused Tutorial</a>&nbsp;，&nbsp;<a href="http://st-curriculum.oracle.com/obe/jdev/obe11jdev/ps1/boundedtaskflow/bounded_task_flow.html" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; font-weight: bold; color: #3c7c41; ">ADF Task Flow</a>。</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">还有很多其他的教程可以在这里找到：<a href="http://download.oracle.com/docs/cd/E18941_01/tutorials/toc.htm" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; font-weight: bold; color: #3c7c41; ">链接</a>&nbsp;&nbsp;<a href="http://www.oracle.com/technetwork/developer-tools/jdev/overview/index-100269.html" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; font-weight: bold; color: #3c7c41; ">OTN</a></p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">相关的书籍，培训：&nbsp;<a href="http://www.oracle.com/technetwork/developer-tools/jdev/training11g-090355.html" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; font-weight: bold; color: #3c7c41; ">链接</a></p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">5. 接下去会有一些痛苦，如果你已经完成了所有的培训，不管你是自学还是参加ORACLE的课程。请阅读一下完成的<a href="http://download.oracle.com/docs/cd/E16162_01/index.htm" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; font-weight: bold; color: #3c7c41; ">开发手册</a>。 开发手册会给你更加深入的ADF相关的知识。有基本oracle 官方的书可以参考以下：<span style="border-collapse: separate; font: normal normal normal 12px/normal arial, helvetica, sans-serif; color: #000000; "><a href="http://www.mhprofessional.com/product.php?isbn=0071744282" target="_blank" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; font-weight: bold; color: #3c7c41; ">Quick Start Guide to Oracle Fusion Development</a>&nbsp;</span>，<a href="http://www.mhprofessional.com/product.php?isbn=0071602380&amp;%E2%81%9Ecat=112" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; font-weight: bold; color: #3c7c41; ">Oracle JDeveloper 11g Handbook</a>，<a href="http://www.mhprofessional.com/product.php?cat=112&amp;isbn=0071622543" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; font-weight: bold; color: #3c7c41; ">Oracle Fusion Developer Guide</a>。当然这些书都是收费的，在国内网上可能能找到免费的 :)</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">6. 如果走到了第六步，说明你已经有了比较完整的基础。但是，当你真正开始用ADF和JDEV做开发时，你会有很多问题，这些问题是以上一些教程和书籍没有告诉你怎么解决的。这个时候你就需要<a href="http://forums.oracle.com/forums/forum.jspa?forumID=83" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; font-weight: bold; color: #3c7c41; ">JDeveloper and ADF discussion forum</a>。 或者到我们的 OFMCLUB来寻求答案。 当然在google上也能搜到很多ADF有用的信息，比如一些BLOG&nbsp;<a href="http://www.connotea.org/user/jdeveloper" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; font-weight: bold; color: #3c7c41; ">searchable ADF/JDeveloper blog repository</a>.</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><a href="http://www.oracle.com/technetwork/developer-tools/adf/learnmore/index-101235.html" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; font-weight: bold; color: #3c7c41; ">ADF Code Corner</a>提供了很多的问题解决方案。<br />&nbsp;</p><p style="margin-top: 0.4em; margin-bottom: 0.8em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">7. 在goolge上有一些专家，建立个讨论组&nbsp;<a href="http://groups.google.com/group/adf-methodology" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-decoration: none; font-weight: bold; color: #3c7c41; ">Oracle ADF Enterprise Methodology Group</a>。 主要讨论一些高级的议题，和最佳实践</p></div></div></div></article></div></div></div></div></div><img src ="http://www.blogjava.net/Benjamin/aggbug/358779.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Benjamin/" target="_blank">萧秋水</a> 2011-09-16 11:58 <a href="http://www.blogjava.net/Benjamin/archive/2011/09/16/358779.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在af|inputDate 组件上防止键盘输入 - 转载</title><link>http://www.blogjava.net/Benjamin/archive/2011/09/16/358778.html</link><dc:creator>萧秋水</dc:creator><author>萧秋水</author><pubDate>Fri, 16 Sep 2011 03:55:00 GMT</pubDate><guid>http://www.blogjava.net/Benjamin/archive/2011/09/16/358778.html</guid><wfw:comment>http://www.blogjava.net/Benjamin/comments/358778.html</wfw:comment><comments>http://www.blogjava.net/Benjamin/archive/2011/09/16/358778.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Benjamin/comments/commentRss/358778.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Benjamin/services/trackbacks/358778.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 在af|inputDate 组件上防止键盘输入&nbsp;gene&nbsp;有些情况下，我们会需要日期输入控件不允许用户用键盘输入日期。要实现这样的功能就需要使用到Javascript。功能的效果如下图：&nbsp;Javascript：?12&lt;af:resource&gt; function disableEntry(evt){ evt.cancel(); }&lt;/af:resour...&nbsp;&nbsp;<a href='http://www.blogjava.net/Benjamin/archive/2011/09/16/358778.html'>阅读全文</a><img src ="http://www.blogjava.net/Benjamin/aggbug/358778.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Benjamin/" target="_blank">萧秋水</a> 2011-09-16 11:55 <a href="http://www.blogjava.net/Benjamin/archive/2011/09/16/358778.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多选js控制权选中，点击删除按钮弹出是否确认删除对话框</title><link>http://www.blogjava.net/Benjamin/archive/2007/04/01/107724.html</link><dc:creator>萧秋水</dc:creator><author>萧秋水</author><pubDate>Sun, 01 Apr 2007 01:39:00 GMT</pubDate><guid>http://www.blogjava.net/Benjamin/archive/2007/04/01/107724.html</guid><wfw:comment>http://www.blogjava.net/Benjamin/comments/107724.html</wfw:comment><comments>http://www.blogjava.net/Benjamin/archive/2007/04/01/107724.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Benjamin/comments/commentRss/107724.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Benjamin/services/trackbacks/107724.html</trackback:ping><description><![CDATA[
		<p>
				<font face="Verdana" size="2">在删除某几条数数据的时候，可以用多选项选中多条记录，再点击删除按钮的时候需要做一下判断是否确认删除，如果一条记录都没有删除，那么就不弹出确认的对话框。<br /><br /></font>
				<font style="BACKGROUND-COLOR: #ffffff" face="Verdana" color="#000000" size="2">&lt;script&gt;<br /><br />function CheckAll(srcElem, do_check){<br />        if(typeof(srcElem)=='undefined') return;<br />        var cnt = (typeof(srcElem.length)!='undefined')? srcElem.length : 0;<br />        if(cnt){<br />                for(var i=0;i&lt;cnt; i++)<br />                        srcElem[i].checked = do_check;<br />        }else<br />                srcElem.checked = do_check;<br />}<br /><br />function deleteYN(){<br />//if(YN(this.form.elements['delBox'], this.checked)){if(!confirm('确实要删除吗?')) return false;}else return false;<br />if(typeof(form1.elements['delBox'])=='undefined'){<br />return false;</font>
		</p>
		<p>
				<font style="BACKGROUND-COLOR: #ffffff" face="Verdana" color="#000000" size="2">}else{<br /> if(form1.delBox.checked==true){  <br />  if(!confirm('确实要删除吗?')) <br />    return false;<br />   else<br />       return true;<br /> }else{ <br /> for(var i=0;i&lt;form1.delBox.length; i++){<br />  if(form1.delBox[i].checked==true){<br />   if(!confirm('确实要删除吗?')) <br />    return false;<br />   else<br />       return true; <br />  }<br /> }<br /> }<br />return false; <br />}<br />return false;<br />}<br />&lt;/script&gt;<br /><br /><br />&lt;input type="submit" name="delSubmit" value="删除" onClick="return YN();" &gt;<br />&lt;input type="checkbox" name="alcheck" value="0" title="点击全选或者全不选" onclick="CheckAll(this.form.elements['delBox'], this.checked)" &gt;<br /></font>
		</p>
<img src ="http://www.blogjava.net/Benjamin/aggbug/107724.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Benjamin/" target="_blank">萧秋水</a> 2007-04-01 09:39 <a href="http://www.blogjava.net/Benjamin/archive/2007/04/01/107724.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Like A Rock  《天气预报员》插曲</title><link>http://www.blogjava.net/Benjamin/archive/2007/02/07/98595.html</link><dc:creator>萧秋水</dc:creator><author>萧秋水</author><pubDate>Wed, 07 Feb 2007 06:25:00 GMT</pubDate><guid>http://www.blogjava.net/Benjamin/archive/2007/02/07/98595.html</guid><wfw:comment>http://www.blogjava.net/Benjamin/comments/98595.html</wfw:comment><comments>http://www.blogjava.net/Benjamin/archive/2007/02/07/98595.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Benjamin/comments/commentRss/98595.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Benjamin/services/trackbacks/98595.html</trackback:ping><description><![CDATA[
		<object id="MediaPlayer1" codebase="http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=6,4,5,715" type="application/x-oleobject" height="68" standby="Loading Microsoft Windows Media Player components..." width="460" align="bottom" border="0" classid="CLSID:22d6f312-b0f6-11d0-94ab-0080c74c7e95">
				<embed src="http://www.kungfu360.cn/like%20a%20rock.mp3" type="application/x-mplayer2" pluginspage="http://www.microsoft.com/isapi/redir.dll?prd=windows&amp;sbp=mediaplayer&amp;ar=media&amp;sba=plugin&amp;" name="MediaPlayer" showcontrols="1" showpositioncontrols="0" showaudiocontrols="1" showtracker="1" showdisplay="0" showstatusbar="1" autosize="0" showgotobar="0" showcaptioning="0" autostart="1" autorewind="0" animationatstart="0" transparentatstart="0" allowscan="1" enablecontextmenu="1" clicktoplay="0" invokeurls="1" defaultframe="datawindow" align="baseline" border="0" height="68" width="460">
				</embed>
		</object>
		<br />
		<br />
		<font color="#000000" size="2">
				<table style="TABLE-LAYOUT: fixed; BORDER-COLLAPSE: collapse" cellspacing="0" cellpadding="8" width="100%" border="0">
						<tbody>
								<tr>
										<td class="logtxt" width="100%">
												<p>
														<font face="Verdana" size="2">Stood there boldly <br />Sweatin' in the sun <br />Felt like a million <br />Felt like number one <br />The height of summer <br />I'd never felt that strong <br />Like a rock <br /><br />I was eighteen <br />Didn't have a care <br />Working for peanuts <br />Not a dime to spare <br />But I was lean and <br />Solid everywhere <br />Like a rock <br /><br />My hands were steady <br />My eyes were clear and bright <br />My walk had purpose <br />My steps were quick and light <br />And I held firmly <br />To what I felt was right <br />Like a rock <br /><br />Like a rock, I was strong as I could be <br />Like a rock, nothin' ever got to me <br />Like a rock, I was something to see <br />Like a rock <br /><br />And I stood arrow straight <br />Unencumbered by the weight <br />Of all these hustlers and their schemes <br />I stood proud, I stood tall <br />High above it all <br />I still believed in my dreams <br /><br />Twenty years now <br />Where'd they go? <br />twenty years <br />I don't know <br />sit and I wonder sometimes <br />Where they've gone <br /><br />And sometimes late at night <br />When I'm bathed in the firelight <br />The moon comes callin' a ghostly white <br />And I recall <br />recall <br /><br />Like a rock. standin' arrow straight <br />Like a rock, chargin' from the gate <br />Like a rock, carryin' the weight <br />Like a rock <br /><br />Lihe a rock, the sun upon my skin <br />Like a rock, hard against the wind <br />Like a rock, I see myself again <br />Like a rock </font>
												</p>
										</td>
								</tr>
								<tr>
										<td class="info" height="36">
												<div align="right">
														<font face="Verdana">
														</font>
														<font size="2">
														</font>
												</div>
										</td>
								</tr>
						</tbody>
				</table>
		</font>
<img src ="http://www.blogjava.net/Benjamin/aggbug/98595.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Benjamin/" target="_blank">萧秋水</a> 2007-02-07 14:25 <a href="http://www.blogjava.net/Benjamin/archive/2007/02/07/98595.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Acegi简介--转载</title><link>http://www.blogjava.net/Benjamin/archive/2007/02/02/97403.html</link><dc:creator>萧秋水</dc:creator><author>萧秋水</author><pubDate>Fri, 02 Feb 2007 00:51:00 GMT</pubDate><guid>http://www.blogjava.net/Benjamin/archive/2007/02/02/97403.html</guid><wfw:comment>http://www.blogjava.net/Benjamin/comments/97403.html</wfw:comment><comments>http://www.blogjava.net/Benjamin/archive/2007/02/02/97403.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Benjamin/comments/commentRss/97403.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Benjamin/services/trackbacks/97403.html</trackback:ping><description><![CDATA[
		<p>
				<font face="Verdana" size="2">     Acegi安全系统，是一个用于Spring Framework的安全框架，能够和目前流行的Web容器无缝集成。它使用了Spring的方式提供了安全和认证安全服务，包括使用Bean Context，拦截器和面向接口的编程方式。因此，Acegi安全系统能够轻松地适用于复杂的安全需求。<br />       安全涉及到两个不同的概念，认证和授权。前者是关于确认用户是否确实是他们所宣称的身份。授权则是关于确认用户是否有允许执行一个特定的操作。<br />       在Acegi安全系统中，需要被认证的用户，系统或代理称为"Principal"。Acegi安全系统和其他的安全系统不同，它并没有角色和用户组的概念。<br />Acegi系统设计<br />  关键组件<br />      Acegi安全系统包含以下七个关键的功能组件：<br />        1 Authentication对象，包含了Principal，Credential和Principal的授权信息。同时还可以包含关于发起认证请求的客户的其他信息，如IP地址。<br />        2 ContextHolder对象，使用ThreadLocal储存Authentication对象的地方。<br />        3 AuthenticationManager，用于认证ContextHolder中的Authentication对象。<br />        4 AccessDecissionManager，用于授权一个特定的操作。<br />        5 RunAsManager，当执行特定的操作时，用于选择性地替换Authentication对象。<br />        6 Secure Object拦截器，用于协调AuthenticationManager，AccessDecissionManager，RunAsManager和特定操作的执行。<br />        7 ObjectDefinitionSource，包含了特定操作的授权定义。<br />      这七个关键的功能组件的关系如下图所示（图中灰色部分是关键组件）：<br /><br /><br /><b>安全管理对象</b><br />       Acegi安全系统目前支持两类安全管理对象。<br />       第一类的安全管理对象管理AOP Alliance的MethodInvocation，开发人员可以用它来保护Spring容器中的业务对象。为了使Spring管理的Bean可以作为MethodInvocation来使用，Bean可以通过ProxyFactoryBean和BeanNameAutoProxyCreator来管理，就像在Spring的事务管理一样使用。<br />       第二类是FilterInvocation。它用过滤器（Filter）来创建，并简单地包装了HTTP的ServletRequest，ServletResponse和FilterChain。FilterInvocation可以用来保护HTTP资源。通常，开发人员并不需要了解它的工作机制，因为他们只需要将Filter加入web.xml，Acegi安全系统就可以工作了。<br /><br /><b>安全配置参数</b><br />       每个安全管理对象都可以描述数量不限的各种安全认证请求。例如，MethodInvocation对象可以描述带有任意参数的任意方法的调用，而FilterInvocation可以描述任意的HTTP URL。<br />       Acegi安全系统需要记录应用于每个认证请求的安全配置参数。例如，对于BankManager.getBalance（int accountNumber）方法和BankManager.approveLoan（int applicationNumber）方法，它们需要的认证请求的安全配置很不相同。<br />       为了保存不同的认证请求的安全配置，需要使用配置参数。从实现的视角来看，配置参数使用ConfigAttribute接口来表示。Acegi安全系统提供了ConfigAttribute接口的一个实现，SecurityConfig，它把配置参数保存为一个字符串。<br />       ConfigAttributeDefinition类是ConfigAttribute对象的一个简单的容器，它保存了和特定请求相关的ConfigAttribute的集合。<br />       当安全拦截器收到一个安全认证请求时，需要决定应用哪一个配置参数。换句话说，它需要找出应用于这个请求的ConfigAttributeDefinition对象。这个查找的过程是由ObjectDefinitionSource接口来处理的。这个接口的主要方法是public ConfigAttributeDefinition getAttributes(Object object)，其中Object参数是一个安全管理对象。因为安全管理对象包含有认证请求的详细信息，所以ObjectDefinitionSource接口的实现类可以从中获得所需的详细信息，以查找相关的ConfigAttributeDefiniton对象。<br /><br /><br /><b>Acegi如何工作</b><br />       为了说明Acegi安全系统如何工作，我们设想一个使用Acegi的例子。通常，一个安全系统需要发挥作用，它必须完成以下的工作：<br />      1 首先，系统从客户端请求中获得Principal和Credential；<br />      2 然后系统认证Principal和Credential信息；<br />      3 如果认证通过，系统取出Principal的授权信息；<br />      4 接下来，客户端发起操作请求；<br />      5 系统根据预先配置的参数检查Principal对于该操作的授权；<br />      6 如果授权检查通过则执行操作，否则拒绝。<br />      那么，Acegi安全系统是如何完成这些工作的呢？首先，我们来看看Acegi安全系统的认证和授权的相关类： <br />      安全拦截器的抽象基类，它包含有两个管理类，AuthenticationManager和AccessDecisionManager。AuthenticationManager用于认证ContextHolder中的Authentication对象（包含了Principal，Credential和Principal的授权信息）；AccessDecissionManager则用于授权一个特定的操作。<br /><br />      下面来看一个MethodSecurityInterceptor的例子：<br />  <br /></font>
				<font face="Verdana" size="2">   &lt;bean id="bankManagerSecurity" <br />                     class="net.sf.acegisecurity.intercept.method.MethodSecurityInterceptor"&gt;<br />             &lt;property name="validateConfigAttributes"&gt;<br />                    &lt;value&gt;true&lt;/value&gt;<br />            &lt;/property&gt;<br />            &lt;property name="authenticationManager"&gt;<br />                   &lt;ref bean="authenticationManager"/&gt;<br />            &lt;/property&gt;<br />            &lt;property name="accessDecisionManager"&gt;<br />                  &lt;ref bean="accessDecisionManager"/&gt;<br />            &lt;/property&gt;<br />            &lt;property name="objectDefinitionSource"&gt;<br />                  &lt;value&gt;<br />                     net.sf.acegisecurity.context.BankManager.delete*=<br />                             ROLE_SUPERVISOR,RUN_AS_SERVER<br />                     net.sf.acegisecurity.context.BankManager.getBalance=<br />                             ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER,RUN_<br />                  &lt;/value&gt;<br />            &lt;/property&gt;<br />      &lt;/bean&gt; </font>
				<br />
		</p>
		<p>
				<br />
				<font face="Verdana" size="2">      上面的配置文件中，MethodSecurityInterceptor是AbstractSecurityInterceptor的一个实现类。它包含了两个管理器，authenticationManager和accessDecisionManager。这两者的配置如下：<br />      </font>
		</p>
		<pre class="overflow">
				<font face="Verdana" size="2">
						<br />   &lt;bean id="authenticationDao" class="net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl"&gt;<br />               &lt;property name="dataSource"&gt;&lt;ref bean="dataSource"/&gt;&lt;/property&gt;<br />      &lt;/bean&gt;<br />      &lt;bean id="daoAuthenticationProvider" <br />                     class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider"&gt;<br />               &lt;property name="authenticationDao"&gt;&lt;ref bean="authenticationDao"/&gt;&lt;/property&gt;<br />      &lt;/bean&gt;<br />      &lt;bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager"&gt;<br />               &lt;property name="providers"&gt;<br />                      &lt;list&gt;&lt;ref bean="daoAuthenticationProvider"/&gt;&lt;/list&gt;<br />               &lt;/property&gt;<br />      &lt;/bean&gt;<br />      &lt;bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/&gt;<br />      &lt;bean id="accessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased"&gt;<br />               &lt;property name="allowIfAllAbstainDecisions"&gt;&lt;value&gt;false&lt;/value&gt;&lt;/property&gt;<br />               &lt;property name="decisionVoters"&gt;<br />                      &lt;list&gt;&lt;ref bean="roleVoter"/&gt;&lt;/list&gt;<br />               &lt;/property&gt;<br />      &lt;/bean&gt;</font>
		</pre>
		<p>
				<br />
				<br />
				<font face="Verdana" size="2">       准备工作做好了，现在我们来看看Acegi安全系统是如何实现认证和授权机制的。以使用HTTP BASIC认证的应用为例子，它包括下面的步骤：<br />       1. 用户登录系统，Acegi从acegisecurity.ui子系统的安全拦截器（如BasicProcessingFilter）中得到用户的登录信息（包括Principal和Credential）并放入Authentication对象，并保存在ContextHolder对象中；<br />       2. 安全拦截器将Authentication对象交给AuthenticationManager进行身份认证，如果认证通过，返回带有Principal授权信息的Authentication对象。此时ContextHolder对象的Authentication对象已拥有Principal的详细信息；<br />       3. 用户登录成功后，继续进行业务操作；<br />       4. 安全拦截器（bankManagerSecurity）收到客户端操作请求后，将操作请求的数据包装成安全管理对象（FilterInvocation或MethodInvocation对象）；<br />       5. 然后，从配置文件（ObjectDefinitionSource）中读出相关的安全配置参数ConfigAttributeDefinition；<br />       6. 接着，安全拦截器取出ContextHolder中的Authentication对象，把它传递给AuthenticationManager进行身份认证，并用返回值更新ContextHolder的Authentication对象；<br />       7. 将Authentication对象，ConfigAttributeDefinition对象和安全管理对象（secure Object）交给AccessDecisionManager，检查Principal的操作授权；<br />       8. 如果授权检查通过则执行客户端请求的操作，否则拒绝；<br /><br /><b>AccessDecisionVoter</b><br />       注意上节的accessDecisionManager是一个AffirmativeBased类，它对于用户授权的投票策略是，只要通过其中的一个授权投票检查，即可通过；它的allowIfAllAbstainDecisions属性值是false，意思是如果所有的授权投票是都是弃权，则通不过授权检查。<br />       Acegi安全系统包括了几个基于投票策略的AccessDecisionManager，上节的RoleVoter就是其中的一个投票策略实现，它是AccessDecisionVoter的一个子类。AccessDecisionVoter的具体实现类通过投票来进行授权决策，AccessDecisionManager则根据投票结果来决定是通过授权检查，还是抛出AccessDeniedException例外。<br />       AccessDecisionVoter接口共有三个方法：<br />public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config);<br />public boolean supports(ConfigAttribute attribute);<br />public boolean supports(Class clazz);<br />       其中的vote方法返回int返回值，它们是AccessDecisionVoter的三个静态成员属性：ACCESS_ABSTAIN,，ACCESS_DENIED和ACCESS_GRANTED，它们分别是弃权，否决和赞成。<br />       Acegi安全系统中，使用投票策略的AccessDecisionManager共有三个具体实现类：AffirmativeBased、ConsensusBased和UnanimousBased。它们的投票策略是，AffirmativeBased类只需有一个投票赞成即可通过；ConsensusBased类需要大多数投票赞成即可通过；而UnanimousBased类需要所有的投票赞成才能通过。<br />       RoleVoter类是一个Acegi安全系统AccessDecisionVoter接口的实现。如果ConfigAttribute以ROLE_开头，RoleVoter则进行投票。如果GrantedAuthority的getAutority方法的String返回值匹配一个或多个以ROLE_开头的ConfigAttribute，则投票通过，否则不通过。如果没有以ROLE_开头的ConfigAttribute，RoleVoter则弃权。<br /><br /><b>安全拦截器</b><br />  拦截器如何工作<br />  MethodInvocation拦截器<br />  FilterInvocation拦截器<br />认证<br />  认证请求<br />  认证管理器<br />  Authentication Provider<br />授权<br />  Access Decision Manager<br />  Voting Decision Manager<br />  授权管理推荐<br />ContextHolder的用户接口<br />  用户接口目标<br />  HTTP会话认证<br />  HTTP Basic认证<br /><br />1、Log4j的概念<br />   Log4j中有三个主要的组件，它们分别是Logger、Appender和Layout，Log4j 允许开发人员定义多个Logger，每个Logger拥有自己的名字，Logger之间通过名字来表明隶属关系。有一个Logger称为Root，它永远 存在，且不能通过名字检索或引用，可以通过Logger.getRootLogger()方法获得，其它Logger通过 Logger.getLogger(String name)方法。<br />   Appender则是用来指明将所有的log信息存放到什么地方，Log4j中支持多种appender，如 console、files、GUI components、NT Event Loggers等，一个Logger可以拥有多个Appender，也就是你既可以将Log信息输出到屏幕，同时存储到一个文件中。<br />   Layout的作用是控制Log信息的输出方式，也就是格式化输出的信息。<br />   Log4j中将要输出的Log信息定义了5种级别，依次为DEBUG、INFO、WARN、ERROR和FATAL，当输出时，只有级别高过配置中规定的 级别的信息才能真正的输出，这样就很方便的来配置不同情况下要输出的内容，而不需要更改代码，这点实在是方便啊。<br /><br />2、Log4j的配置文件<br />  虽然可以不用配置文件，而在程序中实现配置，但这种方法在如今的系统开发中显然是不可取的，能采用配置文件的地方一定一定要用配置文件。Log4j支持两 种格式的配置文件：XML格式和Java的property格式，本人更喜欢后者，首先看一个简单的例子吧，如下：<br /><br />  </font>
				<font face="Verdana" size="2">log4j.rootLogger=debug, stdout, R<br />  log4j.appender.stdout=org.apache.log4j.ConsoleAppender<br />  log4j.appender.stdout.layout=org.apache.log4j.PatternLayout<br /><br />  # Pattern to output the caller's file name and line number.<br />  log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n<br /><br />  log4j.appender.R=org.apache.log4j.RollingFileAppender<br />  log4j.appender.R.File=example.log<br />  log4j.appender.R.MaxFileSize=100KB<br /><br />  # Keep one backup file<br />  log4j.appender.R.MaxBackupIndex=1<br /><br />  log4j.appender.R.layout=org.apache.log4j.PatternLayout<br />  log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n</font>
				<br />
		</p>
		<p>
				<font face="Verdana" size="2">         <br /><br />  首先，是设置root，格式为 log4j.rootLogger=[level],appenderName, ...，其中level就是设置需要输出信息的级别，后面是appender的输出的目的地，appenderName就是指定日志信息输出到哪个地方。您可以同时指定多个输出目的地。配置日志信息输出目的地Appender，其语法为<br />  log4j.appender.appenderName = fully.qualified.name.of.appender.class<br />  log4j.appender.appenderName.option1 = value1<br />  ...<br />  log4j.appender.appenderName.option = valueN<br />Log4j提供的appender有以下几种：<br />  org.apache.log4j.ConsoleAppender（控制台）<br />  org.apache.log4j.FileAppender（文件）<br />  org.apache.log4j.DailyRollingFileAppender（每天产生一个日志文件）<br />  org.apache.log4j.RollingFileAppender（文件大小到达指定尺寸的时候产生新文件）<br />  org.apache.log4j.WriterAppender（将日志信息以流格式发送到任意指定的地方）<br />配置日志信息的格式（布局），其语法为：<br />  log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class<br />  log4j.appender.appenderName.layout.option1 = value1<br />  ....<br />  log4j.appender.appenderName.layout.option = valueN<br />Log4j提供的layout有以下几种：<br />  org.apache.log4j.HTMLLayout（以HTML表格形式布局），<br />  org.apache.log4j.PatternLayout（可以灵活地指定布局模式），<br />  org.apache.log4j.SimpleLayout（包含日志信息的级别和信息字符串），<br />  org.apache.log4j.TTCCLayout（包含日志产生的时间、线程、类别等等信息） <br /><br />3、Log4j在程序中的使用<br />  要在自己的类中使用Log4j，首先声明一个静态变量Logger logger=Logger.getLog("classname")；在使用之前，用PropertyConfigurator.configure ("配置文件")配置一下，现在就可以使用了，用法如下：logger.debug("debug message")或者logger.info("info message")，看下面一个小例子：<br /><br /><br />  </font>
				<font face="Verdana" size="2">import com.foo.Bar;<br />  import org.apache.log4j.Logger;<br />  import org.apache.log4j.PropertyConfigurator;<br />  public class MyApp {<br />    static Logger logger = Logger.getLogger(MyApp.class.getName());<br />    public static void main(String[] args) {<br />      // BasicConfigurator replaced with PropertyConfigurator.<br />      PropertyConfigurator.configure(args[0]);<br />      logger.info("Entering application.");<br />      Bar bar = new Bar();<br />      bar.doIt();<br />      logger.info("Exiting application.");<br />    }<br />  }</font>
				<br />
		</p>
		<p>
				<br />
				<br />
				<br />
				<font face="Verdana" size="2">[简介]<br /><br />对于一个典型的Web应用，完善的认证和授权机制是必不可少的，在SpringFramework中，Juergen Hoeller提供的范例JPetStore给了一些这方面的介绍，但还远远不够，Acegi是一个专门为SpringFramework提供安全机制的 项目，全称为Acegi Security System for Spring，当前版本为0.5.1，就其目前提供的功能，应该可以满足绝大多数应用的需求。<br /><br />本文的主要目的是希望能够说明如何在基于Spring构架的Web应用中使用Acegi，而不是详细介绍其中的每个接口、每个类。注意，即使对已经存在的Spring应用，通过下面介绍的步骤，也可以马上享受到Acegi提供的认证和授权。<br /><br />[基础工作]<br />在你的Web应用的lib中添加Acegi下载包中的acegi-security.jar<br /><br />[web.xml]<br />实现认证和授权的最常用的方法是通过filter，Acegi亦是如此，通常Acegi需要在web.xml添加以下5个filter:<br /><br /></font>
				<font face="Verdana" size="2">&lt;filter&gt;<br />  &lt;filter-name&gt;Acegi Channel Processing Filter&lt;/filter-name&gt;<br />  &lt;filter-class&gt;net.sf.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt;<br />  &lt;init-param&gt;<br />    &lt;param-name&gt;targetClass&lt;/param-name&gt;<br />    &lt;param-value&gt;net.sf.acegisecurity.securechannel.ChannelProcessingFilter&lt;/param-value&gt;<br />  &lt;/init-param&gt;<br />&lt;/filter&gt;<br />&lt;filter&gt;<br />  &lt;filter-name&gt;Acegi Authentication Processing Filter&lt;/filter-name&gt;<br />  &lt;filter-class&gt;net.sf.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt;<br />  &lt;init-param&gt;<br />    &lt;param-name&gt;targetClass&lt;/param-name&gt;<br />    &lt;param-value&gt;net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter&lt;/param-value&gt;<br />  &lt;/init-param&gt;<br />&lt;/filter&gt;<br />&lt;filter&gt;<br />  &lt;filter-name&gt;Acegi HTTP BASIC Authorization Filter&lt;/filter-name&gt;<br />  &lt;filter-class&gt;net.sf.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt;<br />  &lt;init-param&gt;<br />    &lt;param-name&gt;targetClass&lt;/param-name&gt;<br />    &lt;param-value&gt;net.sf.acegisecurity.ui.basicauth.BasicProcessingFilter&lt;/param-value&gt;<br />  &lt;/init-param&gt;<br />&lt;/filter&gt;<br />&lt;filter&gt;<br />  &lt;filter-name&gt;Acegi Security System for Spring Auto Integration Filter&lt;/filter-name&gt;<br />  &lt;filter-class&gt;net.sf.acegisecurity.ui.AutoIntegrationFilter&lt;/filter-class&gt;<br />&lt;/filter&gt;<br />&lt;filter&gt;<br />  &lt;filter-name&gt;Acegi HTTP Request Security Filter&lt;/filter-name&gt;<br />  &lt;filter-class&gt;net.sf.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt;<br />  &lt;init-param&gt;<br />    &lt;param-name&gt;targetClass&lt;/param-name&gt;<br />    &lt;param-value&gt;net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter&lt;/param-value&gt;<br />  &lt;/init-param&gt;<br />&lt;/filter&gt;</font>
				<br />
		</p>
		<p>
				<br />
				<br />
				<font face="Verdana" size="2">最先引起迷惑的是net.sf.acegisecurity.util.FilterToBeanProxy，Acegi自己的文档上解释是： “What  FilterToBeanProxy does is delegate the Filter's methods through to a bean which is obtained from the <br />Spring application context. This enables the bean to benefit from the Spring application context lifecycle support and configuration flexibility.”，如希望深究的话，去看看源代码应该不难理解。<br /><br />再下来就是添加filter-mapping了：<br /><br /></font>
				<font face="Verdana" size="2">&lt;filter-mapping&gt;<br />  &lt;filter-name&gt;Acegi Channel Processing Filter&lt;/filter-name&gt;<br />  &lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br />&lt;/filter-mapping&gt;<br />&lt;filter-mapping&gt;<br />  &lt;filter-name&gt;Acegi Authentication Processing Filter&lt;/filter-name&gt;<br />  &lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br />&lt;/filter-mapping&gt;<br />&lt;filter-mapping&gt;<br />  &lt;filter-name&gt;Acegi HTTP BASIC Authorization Filter&lt;/filter-name&gt;<br />  &lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br />&lt;/filter-mapping&gt;<br />&lt;filter-mapping&gt;<br />  &lt;filter-name&gt;Acegi Security System for Spring Auto Integration Filter&lt;/filter-name&gt;<br />  &lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br />&lt;/filter-mapping&gt;<br />&lt;filter-mapping&gt;<br />  &lt;filter-name&gt;Acegi HTTP Request Security Filter&lt;/filter-name&gt;<br />  &lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br />&lt;/filter-mapping&gt;</font>
				<br />
		</p>
		<p>
				<br />
				<br />
				<font face="Verdana" size="2">这里，需要注意以下两点：<br />1) 这几个filter的顺序是不能更改的，顺序不对将无法正常工作；<br />2) 如果你的应用不需要安全传输，如https，则将"Acegi Channel Processing Filter"相关内容注释掉即可；<br />3) 如果你的应用不需要Spring提供的远程访问机制，如Hessian and Burlap，将"Acegi HTTP BASIC Authorization <br />Filter"相关内容注释掉即可。<br /><br />[applicationContext.xml]<br />接下来就是要添加applicationContext.xml中的内容了，从刚才FilterToBeanFactory的解释可以看出，真正的filter都<br />在Spring的applicationContext中管理：<br /><br />1) 首先，你的数据库中必须具有保存用户名和密码的table，Acegi要求table的schema必须如下：<br /><br /></font>
				<font face="Verdana" size="2">CREATE TABLE users (<br />    username VARCHAR(50) NOT NULL PRIMARY KEY,<br />    password VARCHAR(50) NOT NULL,<br />    enabled BIT NOT NULL<br />);<br />CREATE TABLE authorities (<br />    username VARCHAR(50) NOT NULL,<br />    authority VARCHAR(50) NOT NULL<br />);<br />CREATE UNIQUE INDEX ix_auth_username ON authorities ( username, authority );<br />ALTER TABLE authorities ADD CONSTRAINT fk_authorities_users foreign key (username) REFERENCES users<br />(username);</font>
				<br />
		</p>
		<p>
				<br />
				<br />
				<font face="Verdana" size="2">2) 添加访问你的数据库的datasource和Acegi的jdbcDao，如下：<br /><br /><br /></font>
				<font face="Verdana" size="2">&lt;bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"&gt;<br />  &lt;property name="driverClassName"&gt;&lt;value&gt;${jdbc.driverClassName}&lt;/value&gt;&lt;/property&gt;<br />  &lt;property name="url"&gt;&lt;value&gt;${jdbc.url}&lt;/value&gt;&lt;/property&gt;<br />  &lt;property name="username"&gt;&lt;value&gt;${jdbc.username}&lt;/value&gt;&lt;/property&gt;<br />  &lt;property name="password"&gt;&lt;value&gt;${jdbc.password}&lt;/value&gt;&lt;/property&gt;<br />&lt;/bean&gt;<br />&lt;bean id="jdbcDaoImpl" class="net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl"&gt;<br />  &lt;property name="dataSource"&gt;&lt;ref bean="dataSource"/&gt;&lt;/property&gt;<br />&lt;/bean&gt;</font>
				<br />
		</p>
		<p>
				<br />
				<br />
				<font face="Verdana" size="2">3) 添加DaoAuthenticationProvider:<br /><br /></font>
				<font face="Verdana" size="2">&lt;bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider"&gt;<br />  &lt;property name="authenticationDao"&gt;&lt;ref bean="authenticationDao"/&gt;&lt;/property&gt;<br />  &lt;property name="userCache"&gt;&lt;ref bean="userCache"/&gt;&lt;/property&gt;<br />&lt;/bean&gt;<br /><br />&lt;bean id="userCache" class="net.sf.acegisecurity.providers.dao.cache.EhCacheBasedUserCache"&gt;<br />  &lt;property name="minutesToIdle"&gt;&lt;value&gt;5&lt;/value&gt;&lt;/property&gt;<br />&lt;/bean&gt;</font>
				<br />
		</p>
		<p>
				<br />
				<br />
				<font face="Verdana" size="2">如果你需要对密码加密，则在daoAuthenticationProvider中加入：&lt;property name="passwordEncoder"&gt;&lt;ref <br />bean="passwordEncoder"/&gt;&lt;/property&gt;，Acegi提供了几种加密方法，详细情况可看包<br />net.sf.acegisecurity.providers.encoding<br /><br />4) 添加authenticationManager:<br /><br /><br /></font>
				<font face="Verdana" size="2">&lt;bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager"&gt;<br />  &lt;property name="providers"&gt;<br />    &lt;list&gt;<br />      &lt;ref bean="daoAuthenticationProvider"/&gt;<br />    &lt;/list&gt;<br />   &lt;/property&gt;<br />&lt;/bean&gt;</font>
				<br />
		</p>
		<p>
				<br />
				<br />
				<font face="Verdana" size="2">5) 添加accessDecisionManager:<br /><br /></font>
				<font face="Verdana" size="2">&lt;bean id="accessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased"&gt;<br />  &lt;property name="allowIfAllAbstainDecisions"&gt;<br />    &lt;value&gt;false&lt;/value&gt;<br />  &lt;/property&gt;<br />  &lt;property name="decisionVoters"&gt;<br />    &lt;list&gt;&lt;ref bean="roleVoter"/&gt;&lt;/list&gt;<br />  &lt;/property&gt;<br />&lt;/bean&gt;<br />&lt;bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/&gt;</font>
				<br />
		</p>
		<p>
				<br />
				<br />
				<font face="Verdana" size="2">6) 添加authenticationProcessingFilterEntryPoint:<br /><br /></font>
				<font face="Verdana" size="2">&lt;bean id="authenticationProcessingFilterEntryPoint" <br />class="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint"&gt;<br />  &lt;property name="loginFormUrl"&gt;&lt;value&gt;/acegilogin.jsp&lt;/value&gt;&lt;/property&gt;<br />  &lt;property name="forceHttps"&gt;&lt;value&gt;false&lt;/value&gt;&lt;/property&gt;<br />&lt;/bean&gt;</font>
				<br />
		</p>
		<p>
				<br />
				<br />
				<font face="Verdana" size="2">其中acegilogin.jsp是登陆页面，一个最简单的登录页面如下：<br /><br /></font>
				<font face="Verdana" size="2">&lt;%@ taglib prefix='c' uri='http://java.sun.com/jstl/core' %&gt;<br />&lt;%@ page import="net.sf.acegisecurity.ui.AbstractProcessingFilter" %&gt;<br />&lt;%@ page import="net.sf.acegisecurity.AuthenticationException" %&gt;<br />&lt;html&gt;<br />  &lt;head&gt;<br />    &lt;title&gt;Login&lt;/title&gt;<br />  &lt;/head&gt;<br /><br />  &lt;body&gt;<br />    &lt;h1&gt;Login&lt;/h1&gt;<br />    &lt;form action="&lt;c:url value='j_acegi_security_check'/&gt;" method="POST"&gt;<br />      &lt;table&gt;<br />        &lt;tr&gt;&lt;td&gt;User:&lt;/td&gt;&lt;td&gt;&lt;input type='text' name='j_username'&gt;&lt;/td&gt;&lt;/tr&gt;<br />        &lt;tr&gt;&lt;td&gt;Password:&lt;/td&gt;&lt;td&gt;&lt;input type='password' name='j_password'&gt;&lt;/td&gt;&lt;/tr&gt;<br />        &lt;tr&gt;&lt;td colspan='2'&gt;&lt;input name="submit" type="submit"&gt;&lt;/td&gt;&lt;/tr&gt;<br />        &lt;tr&gt;&lt;td colspan='2'&gt;&lt;input name="reset" type="reset"&gt;&lt;/td&gt;&lt;/tr&gt;<br />      &lt;/table&gt;<br />    &lt;/form&gt;<br />  &lt;/body&gt;<br />&lt;/html&gt;</font>
				<br />
		</p>
		<p>
				<br />
				<br />
				<font face="Verdana" size="2">7) 添加filterInvocationInterceptor:<br /><br /></font>
				<font face="Verdana" size="2">&lt;bean id="filterInvocationInterceptor" <br />class="net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor"&gt;<br />  &lt;property name="authenticationManager"&gt;<br />    &lt;ref bean="authenticationManager"/&gt;<br />  &lt;/property&gt;<br />  &lt;property name="accessDecisionManager"&gt;<br />    &lt;ref bean="accessDecisionManager"/&gt;<br />  &lt;/property&gt;<br />  &lt;property name="objectDefinitionSource"&gt;<br />    &lt;value&gt;<br />      CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON<br />      \A/sec/administrator.*\Z=ROLE_SUPERVISOR<br />      \A/sec/user.*\Z=ROLE_TELLER<br />    &lt;/value&gt;<br />  &lt;/property&gt;<br />&lt;/bean&gt;</font>
				<br />
		</p>
		<p>
				<br />
				<br />
				<font face="Verdana" size="2">这里请注意，要objectDefinitionSource中定义哪些页面需要权限访问，需要根据自己的应用需求进行修改，我上面给出<br />的定义的意思是这样的：<br />a. CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON意思是在比较请求路径时全部转换为小写<br />b. \A/sec/administrator.*\Z=ROLE_SUPERVISOR意思是只有权限为ROLE_SUPERVISOR才能访问/sec/administrator*的页面<br />c. \A/sec/user.*\Z=ROLE_TELLER意思是只有权限为ROLE_TELLER的用户才能访问/sec/user*的页面<br /><br />8) 添加securityEnforcementFilter:<br /><br /></font>
				<font face="Verdana" size="2">&lt;bean id="securityEnforcementFilter" class="net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter"&gt;<br />  &lt;property name="filterSecurityInterceptor"&gt;<br />    &lt;ref bean="filterInvocationInterceptor"/&gt;<br />  &lt;/property&gt;<br />  &lt;property name="authenticationEntryPoint"&gt;<br />    &lt;ref bean="authenticationProcessingFilterEntryPoint"/&gt;<br />  &lt;/property&gt;<br />&lt;/bean&gt;</font>
				<br />
		</p>
		<p>
				<br />
				<br />
				<font face="Verdana" size="2">9) 添加authenticationProcessingFilter:<br /><br /></font>
				<font face="Verdana" size="2">&lt;bean id="authenticationProcessingFilter" <br />class="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter"&gt;<br />  &lt;property name="authenticationManager"&gt;<br />    &lt;ref bean="authenticationManager"/&gt;<br />  &lt;/property&gt;<br />  &lt;property name="authenticationFailureUrl"&gt;<br />    &lt;value&gt;/loginerror.jsp&lt;/value&gt;<br />  &lt;/property&gt;<br />  &lt;property name="defaultTargetUrl"&gt;<br />    &lt;value&gt;/&lt;/value&gt;<br />  &lt;/property&gt;<br />  &lt;property name="filterProcessesUrl"&gt;<br />    &lt;value&gt;/j_acegi_security_check&lt;/value&gt;<br />  &lt;/property&gt;<br />&lt;/bean&gt;</font>
				<br />
		</p>
		<p>
				<br />
				<font face="Verdana" size="2">其中authenticationFailureUrl是认证失败的页面。<br /><br />10) 如果需要一些页面通过安全通道的话，添加下面的配置:<br /><br /></font>
				<font face="Verdana" size="2">&lt;bean id="channelProcessingFilter" class="net.sf.acegisecurity.securechannel.ChannelProcessingFilter"&gt;<br />  &lt;property name="channelDecisionManager"&gt;<br />    &lt;ref bean="channelDecisionManager"/&gt;<br />  &lt;/property&gt;<br />  &lt;property name="filterInvocationDefinitionSource"&gt;<br />    &lt;value&gt;<br />      CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON<br />      \A/sec/administrator.*\Z=REQUIRES_SECURE_CHANNEL<br />      \A/acegilogin.jsp.*\Z=REQUIRES_SECURE_CHANNEL<br />      \A/j_acegi_security_check.*\Z=REQUIRES_SECURE_CHANNEL<br />      \A.*\Z=REQUIRES_INSECURE_CHANNEL<br />    &lt;/value&gt;<br />  &lt;/property&gt;<br />&lt;/bean&gt;<br /><br />&lt;bean id="channelDecisionManager" class="net.sf.acegisecurity.securechannel.ChannelDecisionManagerImpl"&gt;<br />  &lt;property name="channelProcessors"&gt;<br />    &lt;list&gt;<br />      &lt;ref bean="secureChannelProcessor"/&gt;<br />      &lt;ref bean="insecureChannelProcessor"/&gt;<br />    &lt;/list&gt;<br />  &lt;/property&gt;<br />&lt;/bean&gt;<br />&lt;bean id="secureChannelProcessor" class="net.sf.acegisecurity.securechannel.SecureChannelProcessor"/&gt;<br />&lt;bean id="insecureChannelProcessor" class="net.sf.acegisecurity.securechannel.InsecureChannelProcessor"/&gt;</font>
				<br />
		</p>
		<p>
				<br />
				<br />
				<font face="Verdana" size="2">[缺少了什么？]<br />Acegi目前提供了两种"secure object"，分别对页面和方法进行安全认证管理，我这里介绍的只是利用<br />FilterSecurityInterceptor对访问页面的权限控制，除此之外，Acegi还提供了另外一个Interceptor――<br />MethodSecurityInterceptor，它结合runAsManager可实现对对象中的方法的权限控制，使用方法可参看Acegi自带的文档<br />和contact范例。<br /><br />[最后要说的]<br />本来以为只是说明如何使用Acegi而已，应该非常简单，但真正写起来才发现想要条理清楚的理顺所有需要的bean还是很<br />困难的，但愿我没有遗漏太多东西，如果我的文章有什么遗漏或错误的话，还请参看Acegi自带的quick-start范例，但请<br />注意，这个范例是不能直接拿来用的。<br />分析和学习Spring中的jpetstore用户管理 <br />  存在用户的系统，必然需要用户的登录和认证，今天就通过分析Spring中自带的jpetstore的例子来学习一下如何实现在Spring构架的系统中用户登录。<br />1、首先从注册用户开始，先看看jpetstore-servlet.xml中关于注册用户的bean定义，从定义命名中就可以看出下面这段就是注册用户的：<br />  </font>
				<br />
				<br />
				<font face="Verdana" size="2">&lt;bean name="/shop/newAccount.do" class="org.springframework.samples.jpetstore.web.spring.AccountFormController"&gt;<br />    &lt;property name="petStore"&gt;&lt;ref bean="petStore"/&gt;&lt;/property&gt;<br />    &lt;property name="validator"&gt;&lt;ref bean="accountValidator"/&gt;&lt;/property&gt;<br />    &lt;property name="successView"&gt;&lt;value&gt;index&lt;/value&gt;&lt;/property&gt;<br />  &lt;/bean&gt;</font>
				<br />
		</p>
		<p>
				<br />
				<font face="Verdana" size="2">1). formView呢？从AccountFormController的构造函数中得到，原来为EditAccountForm；  <br />2). EditoAccountForm.jsp中显得非常乱，其实没有多少难理解的地方，最主要的是这个form既是添加新用户的，又是编辑用户信息的，所以显得有点乱糟糟的。<br />2、添加好了新用户，接下来看看如何登录，在jpetstore-servlet中发现这两个相关bean定义，如下：<br />  </font>
				<br />
				<br />
				<font face="Verdana" size="2">&lt;bean name="/shop/signon.do" class="org.springframework.samples.jpetstore.web.spring.SignonController"&gt;<br />    &lt;property name="petStore"&gt;&lt;ref bean="petStore"/&gt;&lt;/property&gt;<br />  &lt;/bean&gt;<br />  &lt;bean name="/shop/signonForm.do" class="org.springframework.web.servlet.mvc.ParameterizableViewController"&gt;<br />    &lt;property name="viewName"&gt;&lt;value&gt;SignonForm&lt;/value&gt;&lt;/property&gt;<br />&lt;/bean&gt;</font>
				<br />
		</p>
		<p>
				<br />
				<font face="Verdana" size="2">1). 第二个bean是在运行时用户输入用户名和密码的form，叫做SignonForm，对于这个 ParameterizableViewController，用文档里的话说这是最简单的Controller，其作用就是在运行中指向 Controller而不是直接指向jsp文件，仅此而已。<br />2). SignonForm.jsp，里面就是一个简单的form，其action就是第一个bean，即/shop/signon.do，最需要注意的是 signonForwardAction，其主要作用是forward到需要输入用户名和密码的那个页面上去，这个变量哪里来的呢？看看下面：<br />  </font>
				<br />
				<br />
				<font face="Verdana" size="2">&lt;bean id="secureHandlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"&gt;<br />    &lt;property name="interceptors"&gt;<br />      &lt;list&gt;<br />        &lt;ref bean="signonInterceptor"/&gt;<br />      &lt;/list&gt;<br />    &lt;/property&gt;<br />    &lt;property name="urlMap"&gt;<br />      &lt;map&gt;<br />        &lt;entry key="/shop/editAccount.do"&gt;&lt;ref local="secure_editAccount"/&gt;&lt;/entry&gt;<br />        &lt;entry key="/shop/listOrders.do"&gt;&lt;ref local="secure_listOrders"/&gt;&lt;/entry&gt;<br />        &lt;entry key="/shop/newOrder.do"&gt;&lt;ref local="secure_newOrder"/&gt;&lt;/entry&gt;<br />        &lt;entry key="/shop/viewOrder.do"&gt;&lt;ref local="secure_viewOrder"/&gt;&lt;/entry&gt;<br />      &lt;/map&gt;<br />    &lt;/property&gt;<br />  &lt;/bean&gt;</font>
				<br />
		</p>
		<p>
				<br />
				<font face="Verdana" size="2">  原来，上面的signonInterceptor实现了preHandle，因此在请求上面的map页面时，首先要经过这个Interceptor，看看 SignonInterceptor的源码，原来在其中为signon.jsp赋予一个signonForwardAction对象，呵呵，总算明白了。<br />3). 接下来去学习一下SignonController，其主体部分中可以看出，首先取出用户输入的username和password，然后到数据库中验证 有没有这个用户，如果没有这个用户，返回各错误页面；如果成功，首先生成一个UserSession对象，在request的session加入这个 userSession，注意这部分代码中给出了PagedListHolder分页的简单使用方法，关于分页显示，以后再学习吧。<br />3、登录成功后，就可以根据不同的用户设施不同的行为了，取得用户信息，无非就是从session取出userSession即可。<br /></font>
		</p>
<img src ="http://www.blogjava.net/Benjamin/aggbug/97403.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Benjamin/" target="_blank">萧秋水</a> 2007-02-02 08:51 <a href="http://www.blogjava.net/Benjamin/archive/2007/02/02/97403.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CCTV春节内部晚会</title><link>http://www.blogjava.net/Benjamin/archive/2006/12/14/87733.html</link><dc:creator>萧秋水</dc:creator><author>萧秋水</author><pubDate>Thu, 14 Dec 2006 08:03:00 GMT</pubDate><guid>http://www.blogjava.net/Benjamin/archive/2006/12/14/87733.html</guid><wfw:comment>http://www.blogjava.net/Benjamin/comments/87733.html</wfw:comment><comments>http://www.blogjava.net/Benjamin/archive/2006/12/14/87733.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Benjamin/comments/commentRss/87733.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Benjamin/services/trackbacks/87733.html</trackback:ping><description><![CDATA[
		<object>
				<param name="movie" value="http://www.6rooms.com/player.swf?vid=9t_yAwIohGEAea/ESuygjw" />
				<embed src="http://www.6rooms.com/player.swf?vid=9t_yAwIohGEAea/ESuygjw" width="500" height="400" type="application/x-shockwave-flash" />
		</object>
<img src ="http://www.blogjava.net/Benjamin/aggbug/87733.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Benjamin/" target="_blank">萧秋水</a> 2006-12-14 16:03 <a href="http://www.blogjava.net/Benjamin/archive/2006/12/14/87733.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>冯小刚的《跪族》</title><link>http://www.blogjava.net/Benjamin/archive/2006/12/13/87474.html</link><dc:creator>萧秋水</dc:creator><author>萧秋水</author><pubDate>Wed, 13 Dec 2006 06:10:00 GMT</pubDate><guid>http://www.blogjava.net/Benjamin/archive/2006/12/13/87474.html</guid><wfw:comment>http://www.blogjava.net/Benjamin/comments/87474.html</wfw:comment><comments>http://www.blogjava.net/Benjamin/archive/2006/12/13/87474.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Benjamin/comments/commentRss/87474.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Benjamin/services/trackbacks/87474.html</trackback:ping><description><![CDATA[
		<object>
				<param name="movie" value="http://www.6rooms.com/player.swf?vid=M5iaglRQ3EqYKf0wslZyKA" />
				<embed src="http://www.6rooms.com/player.swf?vid=M5iaglRQ3EqYKf0wslZyKA" width="500" height="400" type="application/x-shockwave-flash" />
		</object>
<img src ="http://www.blogjava.net/Benjamin/aggbug/87474.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Benjamin/" target="_blank">萧秋水</a> 2006-12-13 14:10 <a href="http://www.blogjava.net/Benjamin/archive/2006/12/13/87474.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>