﻿<?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-Sealyu-随笔分类-Seam</title><link>http://www.blogjava.net/sealyu/category/37289.html</link><description>--- The devil's in the Details</description><language>zh-cn</language><lastBuildDate>Thu, 10 Jun 2010 17:02:59 GMT</lastBuildDate><pubDate>Thu, 10 Jun 2010 17:02:59 GMT</pubDate><ttl>60</ttl><item><title>Setting the conversation-timeout in Seam, why it really does work</title><link>http://www.blogjava.net/sealyu/archive/2010/04/20/318792.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Mon, 19 Apr 2010 16:36:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2010/04/20/318792.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/318792.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2010/04/20/318792.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/318792.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/318792.html</trackback:ping><description><![CDATA[<p>Conversation timeout seems to be a commonly misunderstood Seam
concept. I often see postings on the Seam forums claiming that the
conversation-timeout doesn&#8217;t work!  Well, actually it does, you simply
have to understand the semantics.</p>
<p>Configuring the conversation-timeout period can be accomplished
through the following in your components.xml:</p>
<pre>&lt;core:manager conversation-timeout="900000" /&gt;</pre>
<p>At first glance most developers relate conversation-timeout to
session timeout, where any conversation will simply timeout after the
configured conversation timeout period.  As you will quickly notice
during testing, this is not the case. To execute a quick experiment, try
the following configuration in the components.xml of the seam-booking
example:</p>
<pre>&lt;core:manager conversation-timeout="60000" /&gt;</pre>
<p>Because the conversation-timeout is set in milliseconds, the above
configuration sets the conversation-timeout to 1 minute.  Now in the
web.xml set the session timeout to 5 minutes:</p>
<pre>&lt;session-config&gt;<br />
&lt;session-timeout&gt;5&lt;/session-timeout&gt;<br />
&lt;/session-config&gt;</pre>
<p>Now in the destroy method of the HotelBookingAction add the following
line:</p>
<pre>...<br />
@Destroy @Remove<br />
public void destroy() {<br />
log.info("Destroying HotelBookingAction...");<br />
}<br />
...</pre>
<p>This will log our message when the conversation ends and the
HotelBookingAction is destroyed.  Now deploy the seam-booking example to
your local JBoss instance and start up a conversation.  This can be
accomplished by logging in, navigating to the hotels listing, and
selecting a hotel for booking.  At this point, wait for the 1 minute
period&#8230;   nothing happens.  Now wait for another 4 minutes, the message
is displayed.  The conversation timed out along with the session.</p>
<p><strong>Foreground vs. Background Conversations</strong></p>
<p>So why didn&#8217;t our conversation timeout as configured?  This is
because the conversation-timeout only affects background conversations.
The foreground conversation will only timeout when the session times
out.  Foreground, background, what?  The foreground conversation is the
conversation that the user last interacted with.  A background
conversation is any other conversation in the user&#8217;s session.  Thus, in
our previous scenario the foreground conversation timed out with the
session as expected.</p>
<p>Now lets try another approach.  Perform the same steps as before to
proceed to the booking screen.  Now open a new window and perform the
same steps.  We now have a foreground conversation and a background
conversation in progress.  Again, wait 1 minute.   Nothing happened.
If you wait an additional 4 minutes, both conversations will timeout.
So what is going on here, I thought we had a background conversation?
We did, Seam simply checks the conversation timeout on each request.
Thus, if I interact with the foreground conversation after 1 minute, the
background conversation times out.  Try it, perform the same steps,
wait 1 minute and then click on the window of the foreground
conversation and you will see the log message.</p>
<p>This is very desirable behavior.  Essentially when a user leaves his
or her desk for a period of time and comes back, if the session is still
active it would be desirable to maintain the state the user was
previously in.  This is the foreground conversation state.  All other
background conversation state is left to timeout after the configured
conversation-timeout period which reduces overall memory consumption.
This enables a developer to think less about memory usage and cleaning
up state and more about developing business logic.  That&#8217;s why we&#8217;re
here right?</p>
<p><strong>Letting the user choose</strong></p>
<p>So you may be asking at this point why the conversation-timeout
doesn&#8217;t use polling.  As we said, you must interact with the foreground
conversation to cause the background conversations to timeout after the
conversation-timeout period.  Imagine that the user had many windows
open and leaves his or her desk.  Based on which window the user clicks
on when they return, that becomes the foreground conversation timing out
any other background conversations.  This gives the user a chance to
resume whichever conversation he or she chooses, not the one the
developer chooses.</p>
<img src ="http://www.blogjava.net/sealyu/aggbug/318792.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2010-04-20 00:36 <a href="http://www.blogjava.net/sealyu/archive/2010/04/20/318792.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>javascript CDATA的意义 </title><link>http://www.blogjava.net/sealyu/archive/2009/12/07/304961.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Mon, 07 Dec 2009 02:04:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/12/07/304961.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/304961.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/12/07/304961.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/304961.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/304961.html</trackback:ping><description><![CDATA[<p>CDATA 内部的所有东西都会被解析器忽略。</p>
<p>假如文本中包含了大量的 "&lt;" 和 "&amp;" 字符 - 就像编程代码中经常出现的情况一样 - 那么这个 XML 元素就可以被定义为一个 CDATA 部分。</p>
<p>CDATA 区段开始于 "&lt;![CDATA["，结束于 "]]&gt;"：</p>
<p><font color="#000000" size="2">&lt;script type="text/javascript"&gt;<br />
&lt;![CDATA[<br />
function compare(a,b)<br />
{<br />
if (a &lt; b)<br />
&nbsp;&nbsp; {alert("a小于b");}<br />
else if (a&gt;b)<br />
&nbsp;&nbsp; {alert("a大于b");}<br />
else<br />
&nbsp;&nbsp; {alert("a等于b");}<br />
}<br />
]]&gt;<br />
&lt;/script&gt;</font></p>
<p>在上面的例子中，在 CDATA 区段中的所有东西都会被解析器忽略。</p>
<p><br />
<strong>关于 CDATA 区段的注释:</strong></p>
<p>CDATA 区段不能包含字符串 "]]&gt;"，所以，CDATA 区段的嵌套是不被允许的。</p>
<p>同时也需要确保在 "]]&gt;" 字符串中没有空格或折行。</p>
<p><strong>为什么要使用CDATA:</strong></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
XHTML的第二个改变是使用CDATA段。XML中的CDATA段用于声明不应被解析为标签的文本（XHTML也是如此），这样就可以使用特殊字符，如
小于（&lt;）、大于（&gt;）、和号（&amp;）和双引号（"），而不必使用它们的字符实体。考虑下面的代码：</p>
<p><font size="2">&lt;script type="text/javascript"&gt;<br />
function compare(a,b)<br />
{<br />
if (a &lt; b)<br />
&nbsp;&nbsp; {alert("a小于b");}<br />
else if (a&gt;b)<br />
&nbsp;&nbsp; {alert("a大于b");}<br />
else<br />
&nbsp;&nbsp; {alert("a等于b");}<br />
}<br />
&lt;/script&gt;</font></p>
<p>这个函数相当简单，它比较数字a和b，然后显示消息说明它们的关系。但是，在XHTML中，这段代码是无效的，因为它使用了三个特殊符号，即小于、
大于和双引号。要修正这个问题，必须分别用这三个字符的XML实体&amp;lt;、&amp;gt;和&amp;quot;替换它们：</p>
<p><font size="2">&lt;script type="text/javascript"&gt;<br />
function compare(a,b)<br />
{<br />
if (a &amp;lt;b)<br />
&nbsp;&nbsp; {alert(&amp;quot;a小于b&amp;quot;);}&nbsp;&nbsp; <br />
else if (a&amp;gt;b)<br />
&nbsp;&nbsp; {alert(&amp;quot;a大于b&amp;quot;);}<br />
else<br />
&nbsp;&nbsp; {alert(&amp;quot;a等于b&amp;quot;);}<br />
}<br />
&lt;/script&gt;</font></p>
<p>这段代码存在两个问题。首先，开发者不习惯用XML实体编写代码。这使代码很难读懂。其次，在JavaScript中，这种代码实际上将视为有语法
错，因为解释程序不知道XML实体的意思。用CDATA段即可以以常规形式（即易读的语法）编写JavaScript代码。正式加入CDATA段的方法如
下：</p>
<p><font size="2">&lt;script type="text/javascript"&gt;<br />
&lt;![CDATA[<br />
function compare(a,b)<br />
{<br />
if (a &lt; b)<br />
&nbsp;&nbsp; {alert("a小于b");}<br />
else if (a&gt;b)<br />
&nbsp;&nbsp; {alert("a大于b");}<br />
else<br />
&nbsp;&nbsp; {alert("a等于b");}<br />
}<br />
]]&gt;<br />
&lt;/script&gt;</font></p>
<p>虽然这是正式方式，但还要记住，大多数浏览器都不完全支持XHTML，这就带来主要问题，即这在JavaScript中是个语法错误，因为大多数浏览器还不认识CDATA段。</p>
<p><font size="2">&lt;script type="text/javascript"&gt;<br />
<font style="background-color: rgb(192, 192, 192);"><font style="background-color: rgb(192, 192, 192);">//&lt;![CDATA[</font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
function compare(a,b)<br />
{<br />
if (a &lt; b)<br />
&nbsp;&nbsp; {alert("a小于b");}<br />
else if (a&gt;b)<br />
&nbsp;&nbsp; {alert("a大于b");}<br />
else<br />
&nbsp;&nbsp; {alert("a等于b");}<br />
}<br />
<font style="background-color: rgb(192, 192, 192);">//]]&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><br />
&lt;/script&gt;</font></p>
<p>当前使用的解决方案模仿了&#8220;对旧浏览器隐藏&#8221;代码的方法。使用单行的JavaScript注释"//"，可在不影响代码语法的情况下嵌入CDATA段：</p>
<p>现在，这段代码在不支持XHTML的浏览器中也可运行。</p>
<p>但是，为避免CDATA的问题，最好还是用外部文件引入JavaScript代码。</p>
<img src ="http://www.blogjava.net/sealyu/aggbug/304961.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-12-07 10:04 <a href="http://www.blogjava.net/sealyu/archive/2009/12/07/304961.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>richfaces 的脚本冲突问题（prototype.js）</title><link>http://www.blogjava.net/sealyu/archive/2009/10/28/300003.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Wed, 28 Oct 2009 00:11:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/10/28/300003.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/300003.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/10/28/300003.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/300003.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/300003.html</trackback:ping><description><![CDATA[在页面中使用了richfaces和prototype，结果在IE下一直报错，后来发现richfaces的文档中已经标注了此问题：<br />
<div>
<div>
<div>
<div>
<h2><a id="d0e1572">1.74.&nbsp;Why does Java Script conflict?</a></h2>
</div>
</div>
</div>
<p><a id="d0e1572">Richfaces 3.1.3 uses 1.6.0 version of prototype.js script instead of 1.5.1
that's been used for earlier versions. There are 2 prototype versions
included (the first included implicitly as a dependency of toggle
panel components and the second one included explicitly as a link).
Versions conflict is the cause of the problem.</a></p>
<p><a id="d0e1572">RichFaces 3.1.3 is bundled with the same ones as Prototype 1.6.0,
Scriptaculous 1.8.0</a></p>
<p>
<a id="d0e1572">                              <strong>Example in web.xml::</strong>
</a></p>
<pre xmlns="" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="XML"><br />
<a id="d0e1572">...</a><a id="d0e1572"><br />
<br />
&lt;context-param&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;param-name&gt;org.richfaces.ExcludeScripts&lt;/param-name&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;param-value&gt;Prototype,Scriptaculous&lt;/param-value&gt;<br />
<br />
&lt;/context-param&gt;<br />
<br />
...<br />
<br />
</a></pre>
<p><a id="d0e1572">RichFaces components use Prototype very hard. In particular, some patches
has been removed that are already included into 1.6.0. Adding feature
with exclusion makes it possible to use Prototype with version less
than 1.6.0. This will break some of the components.</a></p>
</div>
<br />
<br />
<img src ="http://www.blogjava.net/sealyu/aggbug/300003.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-10-28 08:11 <a href="http://www.blogjava.net/sealyu/archive/2009/10/28/300003.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Seam扩展事务消息</title><link>http://www.blogjava.net/sealyu/archive/2009/10/23/299454.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Fri, 23 Oct 2009 02:40:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/10/23/299454.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/299454.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/10/23/299454.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/299454.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/299454.html</trackback:ping><description><![CDATA[<p>
当事务成功之后（调用 <tt>persist()</tt>、<tt>update()</tt> 或 <tt>remove()</tt> 成功后），Home对象会发出一个 <tt>org.jboss.seam.afterTransactionSuccess</tt> 事件。
通过监听这一事件，我们可以在底层实体改变后，刷新查询。
如果我们只需要在特定的实体保存、修改或删除后刷新特定查询，我们可以监视 <tt>org.jboss.seam.afterTransactionSuccess.&lt;name&gt;</tt> 事件（<tt>&lt;name&gt;</tt> 是实体的名字）。
</p>
<p>
当一个操作成功时，Home对象可以自动地显示Faces信息，我们可以再一次通过配置来定制信息。
</p>
<pre>&lt;factory name="person"<br />
value="#{personHome.instance}"/&gt;<br />
<br />
&lt;framework:entity-home name="personHome"<br />
entity-class="eg.Person"<br />
new-instance="#{newPerson}"&gt;<br />
&lt;framework:created-message&gt;New person #{person.firstName} #{person.lastName} created&lt;/framework:created-message&gt;<br />
&lt;framework:deleted-message&gt;Person #{person.firstName} #{person.lastName} deleted&lt;/framework:deleted-message&gt;<br />
&lt;framework:updated-message&gt;Person #{person.firstName} #{person.lastName} updated&lt;/framework:updated-message&gt;<br />
&lt;/framework:entity-home&gt;<br />
<br />
&lt;component name="newPerson"<br />
class="eg.Person"&gt;<br />
&lt;property name="nationality"&gt;#{country}&lt;/property&gt;<br />
&lt;/component&gt;</pre>
<p>
或者扩展：
</p>
<pre>@Name("personHome")<br />
public class PersonHome extends EntityHome&lt;Person&gt; {<br />
<br />
@In Country country;<br />
<br />
@Factory("person")<br />
public Person initPerson() { return getInstance(); }<br />
<br />
protected Person createInstance() {<br />
return new Person(country);<br />
}<br />
<br />
protected String getCreatedMessage() { return "New person #{person.firstName} #{person.lastName} created"; }<br />
protected String getUpdatedMessage() { return "Person #{person.firstName} #{person.lastName} updated"; }<br />
protected String getDeletedMessage() { return "Person #{person.firstName} #{person.lastName} deleted"; }<br />
<br />
}</pre>
<p>
但是指定信息最好的方法是把信息置于Seam所知的resource bundle中（在默认情况下，这个bundle叫做 <tt>messages</tt> ）。
</p>
<pre>Person_created=New person #{person.firstName} #{person.lastName} created<br />
Person_deleted=Person #{person.firstName} #{person.lastName} deleted<br />
Person_updated=Person #{person.firstName} #{person.lastName} updated</pre>
<p>
这样方便进行国际化，从表现层的角度考虑也保持了代码和配置的整洁。
</p>
<p>
最后一步是使用 <tt>&lt;s:validateAll&gt;</tt> 和 <tt>&lt;s:decorate&gt;</tt> 向页面中添加验证功能，我会把这个留给你们自己去实现。
</p>
<img src ="http://www.blogjava.net/sealyu/aggbug/299454.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-10-23 10:40 <a href="http://www.blogjava.net/sealyu/archive/2009/10/23/299454.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>解决Safari中Richfaces某些组件不兼容的问题</title><link>http://www.blogjava.net/sealyu/archive/2009/09/22/295950.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Tue, 22 Sep 2009 01:56:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/09/22/295950.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/295950.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/09/22/295950.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/295950.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/295950.html</trackback:ping><description><![CDATA[在项目中使用safari测试richfaces生成的页面时，发现在一个文本框中输入html标签，整个页面就会崩溃，不显示任何信息，也无错误信息。<br />
感觉无从查起，只能借助Google。<br />
才发现原来Safari下很多Richfaces的组件都会出现问题，解决方法反而很简单：<br />
在你的xhtml页面（或者你用jsp或其他模板技术）的页首位置，加这行：<br />
<pre><span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;f:view</span> <span style="color: #000066;">contentType</span>=<span style="color: #ff0000;">"text/html"</span> <span style="font-weight: bold; color: black;">/&gt;</span></span><br />
<br />
问题解决。</pre>
<br />
<br />
<img src ="http://www.blogjava.net/sealyu/aggbug/295950.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-09-22 09:56 <a href="http://www.blogjava.net/sealyu/archive/2009/09/22/295950.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Seam中简单的checkbox操作</title><link>http://www.blogjava.net/sealyu/archive/2009/09/02/293563.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Wed, 02 Sep 2009 03:26:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/09/02/293563.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/293563.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/09/02/293563.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/293563.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/293563.html</trackback:ping><description><![CDATA[有一种情况是我们平时程序开发中经常遇到的，根据一个checkbox的值，动态的显示隐藏一个区域，<br />
在使用Seam和Richfaces开发的时候，一个简单的a4j:support 和 reRender 并不能解决问题。试验了一番，解决了这个问题，例子代码：<br />
<br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080;">&nbsp;1</span>&nbsp;<span style="color: #000000;">&lt;</span><span style="color: #000000;">h:selectBooleanCheckbox&nbsp;value</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">#{beanA.propertyA}</span><span style="color: #000000;">"</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;2</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;styleClass</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">check</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;onclick</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">showHideHistorySelector()</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;id</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">adminView</span><span style="color: #000000;">"</span><span style="color: #000000;">/&gt;</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;3</span>&nbsp;<span style="color: #000000;">&lt;</span><span style="color: #000000;">s:div&nbsp;id</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">historySelectorRegion</span><span style="color: #000000;">"</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;4</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">h:panelGrid&nbsp;columns</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">3</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;rendered</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">#{beanA.propertyA}</span><span style="color: #000000;">"</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">Content&nbsp;here<img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span style="color: #008000;"><br />
</span><span style="color: #008080;">&nbsp;6</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">h:panelGrid</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;7</span>&nbsp;<span style="color: #000000;">&lt;/</span><span style="color: #000000;">s:div</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;8</span>&nbsp;<span style="color: #000000;">&lt;</span><span style="color: #000000;">a4j:jsFunction&nbsp;name</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">showHideHistorySelector</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;status</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">waitingMask</span><span style="color: #000000;">"</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;9</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;reRender</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">historySelectorRegion</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;ajaxSingle</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">true</span><span style="color: #000000;">"</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">10</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;process</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">adminView</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;action</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">#</span><span style="color: #000000;">"</span><span style="color: #000000;">/&gt;</span></div>
<br />
通过使用a4j:jsFunction的process属性来控制就可以解决问题。<br />
<img src ="http://www.blogjava.net/sealyu/aggbug/293563.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-09-02 11:26 <a href="http://www.blogjava.net/sealyu/archive/2009/09/02/293563.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Seam中在java文件中使用资源文件</title><link>http://www.blogjava.net/sealyu/archive/2009/09/01/293425.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Tue, 01 Sep 2009 03:41:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/09/01/293425.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/293425.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/09/01/293425.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/293425.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/293425.html</trackback:ping><description><![CDATA[在java 中如果想从国际化资源文件中读取文本，可以通过注入seam的一个组件：<br />
@In(value="org.jboss.seam.international.messages")<br />
&nbsp;&nbsp;&nbsp; private Map&lt;String, String&gt; messages;<br />
<br />
在使用时，只需要像下面这样：<br />
String abc = messages.get("person.name.required");<br />
<img src ="http://www.blogjava.net/sealyu/aggbug/293425.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-09-01 11:41 <a href="http://www.blogjava.net/sealyu/archive/2009/09/01/293425.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Seam 项目部署在 tomcat 中(转)</title><link>http://www.blogjava.net/sealyu/archive/2009/08/26/292632.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Wed, 26 Aug 2009 04:36:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/08/26/292632.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/292632.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/08/26/292632.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/292632.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/292632.html</trackback:ping><description><![CDATA[<span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';">&nbsp;JBoss&nbsp;Tools&nbsp;<font face="宋体">生成的&nbsp;</font><font face="Times New Roman">Seam&nbsp;</font><font face="宋体">项目（新建项目时，服务器选择&nbsp;</font><font face="Times New Roman">tomcat</font><font face="宋体">），会生成一些必要的文件，如：连接数据库的数据源文件，如：</font><font face="Times New Roman">project-ds.xml&nbsp;</font><font face="宋体">（但它只能在&nbsp;</font><font face="Times New Roman">Jboss&nbsp;as&nbsp;</font><font face="宋体">的环境中运行，不适用于&nbsp;</font><font face="Times New Roman">tomcat</font><font face="宋体">），要想很我们的项目（</font><font face="Times New Roman">war</font><font face="宋体">）运行于&nbsp;</font><font face="Times New Roman">tomcat&nbsp;</font><font face="宋体">中的，我们得对它自动生成的文件做一些必要的修改。</font></span>
<p><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一、<span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';">修改数据库的连接方式</span></span></p>
<p><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1、采用数据源的形式<br />
</span></span><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';">在&nbsp;<font face="Times New Roman">tomcat&nbsp;</font><font face="宋体">中配置数据源方式如下:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font></span></span></span><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';">在生成的项目同级目录中找此文件：&nbsp;<font face="Times New Roman">context.xml&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font></span><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';">Servers/Tomcat&nbsp;<font face="宋体">。。。</font><font face="Times New Roman">/context.xml&nbsp;&nbsp;</font><font face="宋体">作如下配置：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font></span><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';">在标签&nbsp;<font face="Times New Roman">&lt;Context&gt;&nbsp;</font><font face="宋体">中间加入:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New';">&lt;Resource&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New';">name="</span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New'; text-decoration: underline;">jdbc</span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New';">/demo"&nbsp;</span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New'; text-decoration: underline;">auth</span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New';">="Container"&nbsp;</span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New';">type="</span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New'; text-decoration: underline;">javax</span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New';">.</span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New'; text-decoration: underline;">sql</span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New';">.DataSource"&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New';">maxActive="30" </span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New';">maxIdle="5" </span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New';">maxWait="10000" </span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New'; text-decoration: underline;">username</span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New';">="root"&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></font></span></span></span></span><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><font face="宋体"><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New';">password="</span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New'; text-decoration: underline;">admin</span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New';">"&nbsp;</span></font></span></span></span></span><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><font face="宋体"><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New';">driverClassName="</span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New'; text-decoration: underline;">com</span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New';">.</span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New'; text-decoration: underline;">mysql</span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New';">.</span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New'; text-decoration: underline;">jdbc</span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New';">.Driver"&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New';"><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New'; text-decoration: underline;">url</span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New';">="jdbc:mysql://</span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New'; text-decoration: underline;">localhost</span><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New';">:3306/demo?useUnicode=true&amp;amp;characterEncoding=UTF-8"&gt;</span></span></font></span></span></span></span></p>
<p><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><font face="宋体"><span style="font-size: 10.5pt; color: #3f5fbf; font-family: 'Courier New';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Resource&gt;</span>&nbsp;</font></span></span></span></span><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></p>
<p><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2、<span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';">使用非数据源的形式<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';">在文件：<font face="Times New Roman">persistence.xml&nbsp;</font><font face="宋体">中添加</font><font face="Times New Roman">hibernate&nbsp;</font><font face="宋体">的连接数据库的方式，如下：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-size: 10.5pt; color: #008080; font-family: 'Courier New';">&lt;</span><span style="font-size: 10.5pt; color: #3f7f7f; font-family: 'Courier New';">property</span>&nbsp;<span style="font-size: 10.5pt; color: #7f007f; font-family: 'Courier New';">name</span><span style="font-size: 10.5pt; color: #000000; font-family: 'Courier New';">=</span><span style="font-size: 10.5pt; color: #2a00ff; font-style: italic; font-family: 'Courier New';">"hibernate.connection.username"</span>&nbsp;<span style="font-size: 10.5pt; color: #7f007f; font-family: 'Courier New';">value</span><span style="font-size: 10.5pt; color: #000000; font-family: 'Courier New';">=</span><span style="font-size: 10.5pt; color: #2a00ff; font-style: italic; font-family: 'Courier New';">"root"</span><span style="font-size: 10.5pt; color: #008080; font-family: 'Courier New';">/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></font></span></span></span></span><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><font face="宋体"><span style="font-size: 10.5pt; color: #008080; font-family: 'Courier New';">&lt;</span><span style="font-size: 10.5pt; color: #3f7f7f; font-family: 'Courier New';">property</span>&nbsp;<span style="font-size: 10.5pt; color: #7f007f; font-family: 'Courier New';">name</span><span style="font-size: 10.5pt; color: #000000; font-family: 'Courier New';">=</span><span style="font-size: 10.5pt; color: #2a00ff; font-style: italic; font-family: 'Courier New';">"hibernate.connection.password"</span>&nbsp;<span style="font-size: 10.5pt; color: #7f007f; font-family: 'Courier New';">value</span><span style="font-size: 10.5pt; color: #000000; font-family: 'Courier New';">=</span><span style="font-size: 10.5pt; color: #2a00ff; font-style: italic; font-family: 'Courier New';">"admin"</span><span style="font-size: 10.5pt; color: #008080; font-family: 'Courier New';">/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 10.5pt; color: #008080; font-family: 'Courier New';">&lt;</span><span style="font-size: 10.5pt; color: #3f7f7f; font-family: 'Courier New';">property</span>&nbsp;<span style="font-size: 10.5pt; color: #7f007f; font-family: 'Courier New';">name</span><span style="font-size: 10.5pt; color: #000000; font-family: 'Courier New';">=</span><span style="font-size: 10.5pt; color: #2a00ff; font-style: italic; font-family: 'Courier New';">"hibernate.connection.driver_class" </span><span style="font-size: 10.5pt; color: #7f007f; font-family: 'Courier New';">value</span><span style="font-size: 10.5pt; color: #000000; font-family: 'Courier New';">=</span><span style="font-size: 10.5pt; color: #2a00ff; font-style: italic; font-family: 'Courier New';">"com.mysql.jdbc.Driver"</span><span style="font-size: 10.5pt; color: #008080; font-family: 'Courier New';">/&gt;<br />
</span><span style="font-size: 10.5pt; color: #008080; font-family: 'Courier New';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;</span><span style="font-size: 10.5pt; color: #3f7f7f; font-family: 'Courier New';">property</span>&nbsp;<span style="font-size: 10.5pt; color: #7f007f; font-family: 'Courier New';">name</span><span style="font-size: 10.5pt; color: #000000; font-family: 'Courier New';">=</span><span style="font-size: 10.5pt; color: #2a00ff; font-style: italic; font-family: 'Courier New';">"hibernate.connection.url"</span><span style="font-size: 10.5pt; font-family: 'Courier New';">&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></font></span></span></span></span><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><font face="宋体"><span style="font-size: 10.5pt; color: #7f007f; font-family: 'Courier New';">value</span><span style="font-size: 10.5pt; color: #000000; font-family: 'Courier New';">=</span><span style="font-size: 10.5pt; color: #2a00ff; font-style: italic; font-family: 'Courier New';">"jdbc:mysql://localhost:3306/</span><span style="font-size: 10.5pt; color: #2a00ff; font-style: italic; font-family: '宋体';">demo</span><span style="font-size: 10.5pt; color: #2a00ff; font-style: italic; font-family: 'Courier New';">?useUnicode=true&amp;characterEncoding=UTF-8"</span><span style="font-size: 10.5pt; color: #008080; font-family: 'Courier New';">/&gt;</span></font></span></span></span></span></p>
<p><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;二、<span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';">修改&nbsp;<font face="Times New Roman">JPA&nbsp;</font><font face="宋体">配置文件&nbsp;</font><font face="Times New Roman">persistence.xml</font></span></span></span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';">1、</span><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';">如果数据的连接方式采用数据源的形式，则只需修改里面数据源的名称，如：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #008080; font-family: 'Courier New';">&lt;</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #3f7f7f; font-family: 'Courier New';">jta-data-source</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #008080; font-family: 'Courier New';">&gt;</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #008080; font-family: '宋体';">java:comp/env/jdbc/demo</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #008080; font-family: 'Courier New';">&lt;/</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #3f7f7f; font-family: 'Courier New';">jta-data-source</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #008080; font-family: 'Courier New';">&gt;</span></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2、如果采用<font face="Times New Roman">hibernate&nbsp;</font><font face="宋体">的连接方式，则把此行删了。</font></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3、<span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';">删除里面的此行配置：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #008080; font-family: 'Courier New';">&lt;</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #3f7f7f; font-family: 'Courier New';">property</span>&nbsp;<span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #7f007f; font-family: 'Courier New';">name</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #000000; font-family: 'Courier New';">=</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #2a00ff; font-style: italic; font-family: 'Courier New';">"hibernate.transaction.manager_lookup_class"</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; font-family: 'Courier New';">&nbsp;<br />
</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #7f007f; font-family: 'Courier New';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #000000; font-family: 'Courier New';">=</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #2a00ff; font-style: italic; font-family: 'Courier New';">"org.hibernate.transaction.JBossTransactionManagerLookup"</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #008080; font-family: 'Courier New';">/&gt;</span></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4、修改事务的策略方式为 <em><font color="#2a00ff" face="Courier New">RESOURCE_LOCAL</font></em> ：&nbsp;</span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #008080; font-family: 'Courier New';">&lt;</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #3f7f7f; font-family: 'Courier New';">persistence-unit</span>&nbsp;<span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #7f007f; font-family: 'Courier New';">name</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #000000; font-family: 'Courier New';">=</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #2a00ff; font-style: italic; font-family: 'Courier New';">"demo"</span>&nbsp;<span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #7f007f; font-family: 'Courier New';">transaction-type</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #000000; font-family: 'Courier New';">=</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #2a00ff; font-style: italic; font-family: 'Courier New';">"RESOURCE_LOCAL"</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #008080; font-family: 'Courier New';">&gt;</span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;三、<span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';">配置&nbsp;<font face="Times New Roman">Seam&nbsp;</font><font face="宋体">的事务管理器<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';">在&nbsp;<font face="Times New Roman">component.xml&nbsp;</font><font face="宋体">文件加入：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #008080; font-family: 'Courier New';">&lt;</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #3f7f7f; font-family: 'Courier New';">transaction:entity-transaction</span>&nbsp;<span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #7f007f; font-family: 'Courier New';">entity-manager</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #000000; font-family: 'Courier New';">=</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #2a00ff; font-style: italic; font-family: 'Courier New';">"#{entityManager}"</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #008080; font-family: 'Courier New';">/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #000000; font-family: '宋体';">默认生成的此文件是不含有&nbsp;<font face="Courier New"><span style="color: #000000;">transaction&nbsp;</span></font><font face="宋体"><span style="color: #000000;">的命名空间，需要手动在</span></font></span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #000000; font-family: '宋体';">此文件加入它的命名空间：</span></span></font></span></font></span></p>
<p><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; font-family: '宋体';"><font face="宋体"><font face="宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #7f007f; font-family: 'Courier New';">xmlns:transaction</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #000000; font-family: 'Courier New';">=</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #2a00ff; font-style: italic; font-family: 'Courier New';"><a href="http://jboss.com/products/seam/transaction">http://jboss.com/products/seam/transaction</a><br />
</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #2a00ff; font-style: italic; font-family: 'Courier New';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://jboss.com/products/seam/transaction">http://jboss.com/products/seam/transaction</a>&nbsp;<br />
</span><span style="background: #ffffff none repeat scroll 0% 0%; font-size: 10.5pt; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: #2a00ff; font-style: italic; font-family: 'Courier New';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://jboss.com/products/seam/transaction-2.1.xsd">http://jboss.com/products/seam/transaction-2.1.xsd</a></span></font></font></span></p>
<p><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;四、<span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体';">为此项目加入必要的依赖包&nbsp;。。。。。。</span></span></p>
<img src ="http://www.blogjava.net/sealyu/aggbug/292632.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-08-26 12:36 <a href="http://www.blogjava.net/sealyu/archive/2009/08/26/292632.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>rich:tree中drag和drop后reRender对应的tree</title><link>http://www.blogjava.net/sealyu/archive/2009/08/13/291006.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Thu, 13 Aug 2009 07:05:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/08/13/291006.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/291006.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/08/13/291006.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/291006.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/291006.html</trackback:ping><description><![CDATA[如果使用ajax方式拖拽rich:tree中的节点，<br />
在DropEvent对应的listener的方法中可以调用AjaxContext重新reRender：<br />
public void processDrop(DropEvent dropEvent){<br />
。。。<br />
。//此处处理逻辑<br />
UITreeNode destNode = (UITreeNode)dropEvent.getSource();<br />
AjaxContext ac = AjaxContext.getCurrentInstance();<br />
// Add destination tree to reRender<br />
&nbsp;ac.addComponentToAjaxRender(destNode.getUITree());<br />
<br />
另外，如果要在拖拽后reRender其他的节点，要用到oncomplete属性，使用一个jsfunction来reRender。单纯的reRender不起作用，我猜原因可能是listener并不是按照一个ajax请求的方式来的，所以单纯的ajax reRender也不起作用。<br />
<br />
<br />
<img src ="http://www.blogjava.net/sealyu/aggbug/291006.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-08-13 15:05 <a href="http://www.blogjava.net/sealyu/archive/2009/08/13/291006.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SEAM的PAGE和CONVERSATION context</title><link>http://www.blogjava.net/sealyu/archive/2009/08/13/291001.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Thu, 13 Aug 2009 06:53:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/08/13/291001.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/291001.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/08/13/291001.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/291001.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/291001.html</trackback:ping><description><![CDATA[在SEAM中,如果要在几个页面中保持状态, 需要使用CONVERSATION scope,<br />
如果在一个页面中保持状态, 优先使用PAGE context,这样可以提高效率.<br />
<br />
<img src ="http://www.blogjava.net/sealyu/aggbug/291001.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-08-13 14:53 <a href="http://www.blogjava.net/sealyu/archive/2009/08/13/291001.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>rich:tree 的 adviseNodeOpened 和 adviseNodeSelected属性</title><link>http://www.blogjava.net/sealyu/archive/2009/08/13/291000.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Thu, 13 Aug 2009 06:51:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/08/13/291000.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/291000.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/08/13/291000.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/291000.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/291000.html</trackback:ping><description><![CDATA[在rich:tree中如果想要在页面中初始化tree的展开和选中状态或者在页面更改后返回时保持之前的状态，<br />
可以设置tree的adviseNodeOpened 和 adviseNodeSelected属性。<br />
<table xmlns:javaee="http://java.sun.com/xml/ns/javaee" xmlns:fo="http://www.w3.org/1999/XSL/Format" cellpadding="3" cellspacing="0" width="100%">
    <tbody>
        <tr valign="top">
            <td>adviseNodeOpened</td>
            <td>false</td>
            <td>false</td>
            <td>
            <code>javax.el.MethodExpression</code>
            <br />
            (<em>signature must match </em>
            <code>java.lang.Boolean adviseNodeOpened(org.richfaces.component.UITree)</code>)
            </td>
            <td>MethodBinding pointing at a method accepting an
            org.richfaces.component.UITree with return of java.lang.Boolean type.
            If returned value is: java.lang.Boolean. TRUE, a particular treeNode is
            expanded; java.lang.Boolean.FALSE, a particular treeNode is collapsed;
            null, a particular treeNode saves the current state</td>
        </tr>
        <tr valign="top">
            <td>adviseNodeSelected</td>
            <td>false</td>
            <td>false</td>
            <td>
            <code>javax.el.MethodExpression</code>
            <br />
            (<em>signature must match </em>
            <code>java.lang.Boolean adviseNodeSelected(org.richfaces.component.UITree)</code>)
            </td>
            <td>MethodBinding pointing at a method accepting an
            org.richfaces.component.UITree with return of java.lang.Boolean type.
            If returned value is: java.lang.Boolean. TRUE, a particular treeNode is
            selected; java.lang.Boolean.FALSE, a particular treeNode is unselected;
            null, a particular treeNode saves the current state</td>
        </tr>
    </tbody>
</table>
<br />
<br />
<img src ="http://www.blogjava.net/sealyu/aggbug/291000.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-08-13 14:51 <a href="http://www.blogjava.net/sealyu/archive/2009/08/13/291000.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Concurrent calls to conversational components</title><link>http://www.blogjava.net/sealyu/archive/2009/07/20/287417.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Mon, 20 Jul 2009 02:17:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/07/20/287417.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/287417.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/07/20/287417.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/287417.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/287417.html</trackback:ping><description><![CDATA[<p>
<a id="d0e6410">        A general discussion of concurrent calls to Seam components can be
found in </a><a href="http://docs.jboss.com/seam/2.1.1.GA/reference/en-US/html/concepts.html#concurrency" title="4.1.10.&nbsp;Concurrency model">Section&nbsp;4.1.10, &#8220;Concurrency model&#8221;</a>. Here we will discuss
the most common situation in which you will encounter concurrency
— accessing conversational components from AJAX requests.
We're going to discuss the options that a Ajax client library should
provide to control events originating at the client — and we'll
look at the options RichFaces gives you.
</p>
<p>
Conversational components don't allow real concurrent access therefore
Seam queues each request to process them serially.  This allows each
request to be executed in a deterministic fashion. However, a simple
queue isn't that great — firstly, if a method is, for some
reason, taking a very long time to complete, running it over and over
again whenever the client generates a request is bad idea (potential
for Denial of Service attacks), and, secondly, AJAX is often to used
to provide a quick status update to the user, so continuing to run the
action after a long time isn't useful.
</p>
<p>
Therefore, when you are working inside a long running conversation,
Seam queues the action event for a period of time (the concurrent
request timeout); if it can't process the event in time, it creates a
temporary conversation and prints out a message to the user to let them
know what's going on.  It's therefore very important not to flood the
server with AJAX events!
</p>
<p>
We can set a sensible default for the concurrent request timeout (in
ms) in components.xml:
</p>
<pre xmlns="" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="XML"><br />
&lt;core:manager&nbsp;concurrent-request-timeout="500"&nbsp;/&gt;<br />
<br />
</pre>
<p>
We can also fine tune the concurrent request timeout on a page-by-page
basis:
</p>
<pre xmlns="" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="XML"><br />
&lt;page&nbsp;view-id="/book.xhtml"&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;conversation-required="true"&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;login-required="true"<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;concurrent-request-timeout="2000"&nbsp;/&gt;<br />
<br />
</pre>
<p>
So far we've discussed AJAX requests which appear serial to the user -
the client tells the server that an event has occur, and then rerenders
part of the page based on the result.  This approach is great when the
AJAX request is lightweight (the methods called are simple e.g.
calculating the sum of a column of numbers).  But what if we need to do
a complex computation thats going to take a minute?
</p>
<p>
For heavy computation we should use a poll based approach — the
client sends an AJAX request to the server, which causes action to be
executed asynchronously on the server (the response to the client is
immediate) and the client then polls the server for updates.  This is
good approach when you have a long-running action for which it is
important that every action executes (you don't want some to timeout).
</p>
<div>
<div>
<div>
<div>
<h3><a id="d0e6433">7.11.1.&nbsp;How should we design our conversational AJAX application?</a></h3>
</div>
</div>
</div>
<p>
<a id="d0e6433">          Well first, you need to decide whether you want to use the simpler
"serial" request or whether you want to use a polling approach.
</a></p>
<p>
<a id="d0e6433">          If you go for a "serial" requests, then you need to estimate how long
your request will take to complete - is it much shorter than the
concurrent request timeout? If not, you probably want to alter the
concurrent request timeout for this page (as discussed above). You
probably want a queue on the client side to prevent flooding the
server with requests.  If the event occurs often (e.g. a keypress,
onblur of input fields) and immediate update of the client is not a
priority you should set a request delay on the client side. When
working out your request delay, factor in that the event may also be
queued on the server side.
</a></p>
<p>
<a id="d0e6433">          Finally, the client library may provide an option to abort unfinished
duplicate requests in favor of the most recent.
</a></p>
<p>
<a id="d0e6433">          Using a poll-style design requires less fine-tuning.  You just mark your
action method <code>@Asynchronous</code> and decide on a polling
interval:
</a></p>
<pre xmlns="" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="JAVA"><br />
}</pre>
</div>
<div>
<div>
<div>
<div>
<h3><a id="d0e6449">7.11.2.&nbsp;Dealing with errors</a></h3>
</div>
</div>
</div>
<p>
<a id="d0e6449">          However carefully you design your application to queue concurrent
requests to your conversational component, there is a risk that the
server will become overloaded and be unable to process all the
requests before the request will have to wait longer than the
<code>concurrent-request-timeout</code>. In this case Seam will
throw a <code>ConcurrentRequestTimeoutException</code> which can
be handled in <code>pages.xml</code>. We recommend sending an
HTTP 503 error:
</a></p>
<pre xmlns="" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="XML"><br />
<a id="d0e6449">&nbsp;&nbsp;&nbsp;</a><a id="d0e6449">&lt;</a><a id="d0e6449">exception</a><a id="d0e6449">&nbsp;</a><a id="d0e6449">class</a><a id="d0e6449">=</a><a id="d0e6449">"org.jboss.seam.ConcurrentRequestTimeoutException"</a><a id="d0e6449">&nbsp;</a><a id="d0e6449">logLevel</a><a id="d0e6449">=</a><a id="d0e6449">"trace"</a><a id="d0e6449">&gt;</a><a id="d0e6449"><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;http-error&nbsp;error-code="503"&nbsp;/&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&lt;/exception&gt;<br />
<br />
</a></pre>
<div xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="note">
<h2><a id="d0e6449">503 Service Unavailable (HTTP/1.1 RFC)</a></h2>
<p>
<a id="d0e6449">            The server is currently unable to handle the request due to a
temporary overloading or maintenance of the server. The implication
is that this is a temporary condition which will be alleviated after
some delay.
</a></p>
</div>
<p>
<a id="d0e6449">          Alternatively you could redirect to an error page:
</a></p>
<pre xmlns="" xmlns:rf="java:org.jboss.highlight.XhtmlRendererFactory" class="XML"><br />
<a id="d0e6449">&lt;</a><a id="d0e6449">exception</a><a id="d0e6449">&nbsp;</a><a id="d0e6449">class</a><a id="d0e6449">=</a><a id="d0e6449">"org.jboss.seam.ConcurrentRequestTimeoutException"</a><a id="d0e6449">&nbsp;</a><a id="d0e6449">logLevel</a><a id="d0e6449">=</a><a id="d0e6449">"trace"</a><a id="d0e6449">&gt;</a><a id="d0e6449"><br />
<br />
&nbsp;&nbsp;&nbsp;&lt;end-conversation/&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&lt;redirect&nbsp;view-id="/error.xhtml"&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;message&gt;The&nbsp;server&nbsp;is&nbsp;too&nbsp;busy&nbsp;to&nbsp;process&nbsp;your&nbsp;request,&nbsp;please&nbsp;try&nbsp;again&nbsp;later&lt;/message&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&lt;/redirect&gt;<br />
<br />
&lt;/exception&gt;<br />
<br />
</a></pre>
<p>
<a id="d0e6449">           ICEfaces, RichFaces Ajax and Seam Remoting can all handle HTTP error
codes. Seam Remoting will pop up a dialog box showing the HTTP error
and ICEfaces will indicate the error in it's connection status
component. RichFaces Ajax provides the most complete support for
handling HTTP errors by providing a user definable callback. For
example, to show the error message to the user:
</a></p>
<pre><a id="d0e6449">&lt;script type="text/javascript"&gt;<br />
A4J.AJAX.onError = function(req,status,message) { <br />
alert("message");    <br />
};<br />
&lt;/script&gt;</a></pre>
</div>
<div>
<div>
<div>
<div>
<h3><a id="d0e6478">7.11.3.&nbsp;RichFaces Ajax</a></h3>
</div>
</div>
</div>
<p>
<a id="d0e6478">           RichFaces Ajax is the AJAX library most commonly used with Seam, and
provides all the controls discussed above:
</a></p>
<div>
<ul>
    <li>
    <p>
    <a id="d0e6478">              <code>eventsQueue</code> — provide a queue in which
    events are placed.  All events are queued and requests are sent to
    the server serially.  This is useful if the request can to the
    server can take some time to execute (e.g. heavy computation,
    retrieving information from a slow source) as the server isn't
    flooded.
    </a></p>
    </li>
    <li>
    <p>
    <a id="d0e6478">              <code>ignoreDupResponses</code> — ignore the response
    produced by the request if a more recent 'similar' request is
    already in the queue. ignoreDupResponses="true" does <span><em>not
    cancel</em></span> the the processing of the request on the server
    side — just prevents unnecessary updates on the client side.
    </a></p>
    <p>
    <a id="d0e6478">              This option should be used with care with Seam's conversations as
    it allows multiple concurrent requests to be made.
    </a></p>
    </li>
    <li>
    <p>
    <a id="d0e6478">              <code>requestDelay</code> — defines the time (in ms.)
    that the request will be remain on the queue. If the request has
    not been processed by after this time the request will be sent
    (regardless of whether a response has been received) or discarded
    (if there is a more recent similar event on the queue).
    </a></p>
    <p>
    <a id="d0e6478">              This option should be used with care with Seam's conversations as
    it allows multiple concurrent requests to be made.  You need to be
    sure that the delay you set (in combination with the concurrent
    request timeout) is longer than the action will take to execute.
    </a></p>
    </li>
    <li>
    <p>
    <a id="d0e6478">              <code>&lt;a:poll reRender="total" interval="1000" /&gt;</code> —
    Polls the server, and rerenders an area as needed
    </a></p>
    </li>
</ul>
</div>
</div>
<img src ="http://www.blogjava.net/sealyu/aggbug/287417.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-07-20 10:17 <a href="http://www.blogjava.net/sealyu/archive/2009/07/20/287417.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>又一个有点变态的Seam错误： Property ‘xxx’ not readable on type java.lang.Boolean </title><link>http://www.blogjava.net/sealyu/archive/2009/07/20/287397.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Mon, 20 Jul 2009 01:24:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/07/20/287397.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/287397.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/07/20/287397.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/287397.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/287397.html</trackback:ping><description><![CDATA[今天又碰到一个Seam的错误，感觉使用Seam开发的过程就是在不停的找Bug。<br />
错误如下：<br />
在使用rich:inplaceSelect做一个布尔型的选择框时，由于客户需要，在特定情况下需要一个默认值，也就是rich:inplaceSelect的defaultLabel，这时就需要除了true和false外再有一个null的值，所以需要将后台session bean中的对应属性由原始类型boolean改为Boolean，在改完之后，重新运行程序报错：<br />
Property &#8216;xxx&#8217; not readable on type java.lang.Boolean<br />
分析了一下，找不出什么可能的原因，最后在一片帖子中发现了对应的信息：<br />
原来JSF将原始类型boolean的get方法默认为is....(),而将封装类型Boolean的get方法默认为get...().<br />
<br />
Ok,在后台将对应那个的方法修改，问题解决。<br />
<img src ="http://www.blogjava.net/sealyu/aggbug/287397.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-07-20 09:24 <a href="http://www.blogjava.net/sealyu/archive/2009/07/20/287397.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Seam错误：org.jboss.seam.InstantiationException: Could not instantiate Seam component</title><link>http://www.blogjava.net/sealyu/archive/2009/07/17/287082.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Fri, 17 Jul 2009 01:53:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/07/17/287082.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/287082.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/07/17/287082.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/287082.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/287082.html</trackback:ping><description><![CDATA[今天一个问题让我困扰了很久，新建一个session bean后，执行程序一直报错：<br />
org.jboss.seam.InstantiationException: Could not instantiate Seam component: xxxAction<br />
找了好久，终于发现了错误原因，<br />
原来是对应的@Stateful的session bean对应的接口没有标注：@Local<br />
The devil's in the Details！果然如此啊<br />
<img src ="http://www.blogjava.net/sealyu/aggbug/287082.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-07-17 09:53 <a href="http://www.blogjava.net/sealyu/archive/2009/07/17/287082.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在rich:inplaceSelect 中使用布尔型的selectItem时碰到的问题</title><link>http://www.blogjava.net/sealyu/archive/2009/07/10/286288.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Fri, 10 Jul 2009 09:13:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/07/10/286288.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/286288.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/07/10/286288.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/286288.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/286288.html</trackback:ping><description><![CDATA[作者： sealyu&nbsp;&nbsp; 日期：2009-07-10<br />
<br />
我们都知道，在&lt;h:selectOneMenu&gt;中使用布尔型selectItem时，itemValue为"true"/"false".例如：<br />
<font size="2">&lt;</font>h:selectOneMenu<font size="2">&nbsp; value="#{controller.booleanPropertyX}"&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;f:selectItem itemLabel="#{messages['xxxxx']}" itemValue="true"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;f:selectItem itemLabel="#{messages['xxxxx']}" itemValue="false"/&gt;<br />
&lt;/</font>h:selectOneMenu<font size="2">&gt;</font><br />
这样是没有问题的。<br />
但是如果你使用&lt;rich:inplaceSelect&gt;来实现选择功能的时候，"true"/"false"就不起作用了，例如：<br />
<font size="2">&lt;rich:inplaceSelect minSelectWidth="80" editClass="inlineSelectEdit"<br />
&nbsp;&nbsp;&nbsp; defaultLabel="-Select-" immediate="true"<br />
&nbsp;&nbsp;&nbsp; value="#{controller.booleanPropertyX}"&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;f:selectItem itemLabel="#{messages['xxxxx']}" itemValue="true"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;f:selectItem itemLabel="#{messages['xxxxx']}" itemValue="false"/&gt;<br />
&lt;/rich:inplaceSelect&gt;</font><br />
这时候即使sfsb中的值<font size="2">booleanPropertyX是"true"/"false"，也不会有selectItem被选中，而且如果你选择一个selectItem，还会报错:IllegalArgumentException.说明selectItem的itemValue跟</font><font size="2">#{controller.booleanPropertyX}的值是不匹配的。<br />
后来我将</font>"true"/"false"改为"0"/"1", 还是不起作用。<br />
<br />
Finally，终于试出了正确的方法：使用"#{true}"/"#{false}". 正确的使用方法：<br />
<font size="2">&lt;rich:inplaceSelect minSelectWidth="80" editClass="inlineSelectEdit"<br />
&nbsp;&nbsp;&nbsp; defaultLabel="-Select-" immediate="true"<br />
&nbsp;&nbsp;&nbsp; value="#{controller.booleanPropertyX}"&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;f:selectItem itemLabel="#{messages['xxxxx']}" itemValue="#{true}"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;f:selectItem itemLabel="#{messages['xxxxx']}" itemValue="#{false}"/&gt;<br />
&lt;/rich:inplaceSelect&gt;</font><br />
<br />
也就是说：<br />
（1）。如果你使用<font size="2">&lt;</font>h:selectOneMenu&gt;，那么你的f:selectItem的itemValue应该使用："true"/"false"<br />
（2）。如果你使用<font size="2">&lt;rich:inplaceSelect&gt;，那么你的</font>f:selectItem的itemValue应该使用："#{true}"/"#{false}"<br />
<br />
原因暂时还没研究出来，但是结果就是这样的了。<br />
<img src ="http://www.blogjava.net/sealyu/aggbug/286288.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-07-10 17:13 <a href="http://www.blogjava.net/sealyu/archive/2009/07/10/286288.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JBoss中的TransactionTimeOut的设置</title><link>http://www.blogjava.net/sealyu/archive/2009/05/18/271239.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Mon, 18 May 2009 02:01:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/05/18/271239.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/271239.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/05/18/271239.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/271239.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/271239.html</trackback:ping><description><![CDATA[这两天在作seam的时候不时遇到&#8220;org.jboss.util.NestedSQLException: Transaction is not active&#8221;的错误信息，后来到jboss的wiki上发现了问题的原因和解决方法：<br />
<h2> How do I set the Transaction Timeout?</h2>
<p>Transaction timeout (unit is always seconds) can be configured in various ways:</p>
<p>This argument is the same no matter if you are using JBossTM(&lt;=4.0.5) or JBossJTA-Arjuna(&gt;=4.2).</p>
<ul>
    <li type="ul">
    <p>Globally:
    You can change this behavior globally by modifying the
    TransactionManagerService in /conf/jboss-service.xml (or
    /deploy/jta-service.xml for 4.0.3)</p>
    </li>
</ul>
<p><strong>Version &lt;= 4.0.5</strong></p>
<p>This part is the same for either JBossTM or JBossJTA and is the same for ejb2 and ejb3</p>
<ul>
    <li type="ul">
    <p>Per-method basis: Modifying the <span style="font-family: courier new,courier;">&lt;transaction-timeout&gt;</span>
    element inside the &lt;method&gt; element of a session or entity bean.
    This is located in the META-INF/jboss.xml deployment descriptor of a
    session bean. When the transaction timeout is specified at the method
    level, it overrides the default timeout. Further information about this
    element can be found in jboss-x.x.x/docs/dtd/jboss_4_0.dtd. Example
    taken from the testsuite:</p>
    </li>
</ul>
<ul>
    <li type="ul">
    <p>Using
    BMT: Calling
    javax.transaction.UserTransaction.setTransactionTimeout(int seconds).
    Please, be aware that this only applies to transactions started after
    this invocation on the same thread. Example:</p>
    </li>
</ul>
<pre><code jive-java="">@TransactionTimeout(1500)<br />
</code></pre>
<br />
<br />
<img src ="http://www.blogjava.net/sealyu/aggbug/271239.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-05-18 10:01 <a href="http://www.blogjava.net/sealyu/archive/2009/05/18/271239.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Seam 记住登录前url的方法</title><link>http://www.blogjava.net/sealyu/archive/2009/05/13/270343.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Wed, 13 May 2009 01:36:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/05/13/270343.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/270343.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/05/13/270343.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/270343.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/270343.html</trackback:ping><description><![CDATA[<p>seam有个一个内置的component，叫做redirect。它具有获取当前view的能力当得到登陆授权后，可以直接获得登录前的地址进行访问。</p>
<p>在component.xml里添加：</p>
<p>&lt;event type="org.jboss.seam.security.notLoggedIn"&gt;<br />
&lt;action execute="#{redirect.captureCurrentView}"/&gt;<br />
&lt;/event&gt;<br />
&lt;event type="org.jboss.seam.security.postAuthenticate"&gt;<br />
&lt;action execute="#{redirect.returnToCapturedView}"/&gt;<br />
&lt;/event&gt;</p>
<img src ="http://www.blogjava.net/sealyu/aggbug/270343.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-05-13 09:36 <a href="http://www.blogjava.net/sealyu/archive/2009/05/13/270343.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Seam错误：deleted entity passed to persist</title><link>http://www.blogjava.net/sealyu/archive/2009/05/08/269520.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Fri, 08 May 2009 00:59:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/05/08/269520.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/269520.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/05/08/269520.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/269520.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/269520.html</trackback:ping><description><![CDATA[在使用Seam的EntityHome.remove()方法时报错：&nbsp; deleted entity passed to persist:[com.xxx.xxx.Person#&lt;null&gt;]<br />
单纯看错误信息，还以为是对象没有传进去。但调试之后发现personHome里面的对象是正确的。<br />
后来测试了几次发现是因为所要删除的对象隶属于另外一个对象，那么单纯删除此对象时，会报这个错误，因为此时的约束关系还未解除。<br />
例如：<br />
我要删除一个Person实体，而这个实体是属于一个组织Department的，<br />
那么我应该在删除之前先执行： personHome.getInstance().getDepartment.getAllPersons().remove(personHome.getInstance()),<br />
然后再执行personHome.remove().<br />
<img src ="http://www.blogjava.net/sealyu/aggbug/269520.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-05-08 08:59 <a href="http://www.blogjava.net/sealyu/archive/2009/05/08/269520.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>提高JSF／SEAM程序的效率（转）</title><link>http://www.blogjava.net/sealyu/archive/2009/05/07/269329.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Thu, 07 May 2009 01:16:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/05/07/269329.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/269329.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/05/07/269329.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/269329.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/269329.html</trackback:ping><description><![CDATA[原文：http://www.jsfcentral.com/articles/speed_up_your_jsf_app_1.html<br />
<br />
<strong>Speed up your Data-Driven JSF/Seam Application by Two Orders of Magnitude - Part 1</strong><br />
by Dan Allen<br />
05 Feb 2009 03:00 EST<br />
<br />
<span>
<p>In the first of
this two-part article, Dan Allen discusses some common performance
problems you may encounter when using JSF components, Seam components,
and the EL. You'll learn about the set of best practices for
eliminating them that led to an improvement of two orders of magnitude
in the performance of his application. </p>
</span><hr align="center" width="100%" />
<span>
<p>
JavaServer Faces (JSF) has a reputation for having poor performance.
Some claim that this "runtime tax" is simply the cost of using a
component-based abstraction layer. After focused research, I have
determined that by following a handful of best practices, you can get
your JSF data tables to perform almost as well as hand-crafted HTML
while still being able to retain the benefits of developing with an
event-driven programming model. I begin by identifying some performance
problems that occur when using JSF UI components, Seam components, and
the EL carelessly, and then present, through a series of four lessons,
ways to eliminate these problems one-by-one until you have observed a
remarkable, two orders of magnitude improvement.
</p>
<p>All the test results reported in this article were gathered on a
Lenovo R60 with 2.5GB RAM, Dual Core T2300 @ 1.66Ghz processor running
Ubuntu Linux 7.10. The application was built using Seam 2.0.3.CR1, Sun
JSF 1.2_04-b16-p02, and RichFaces 3.2.2.GA. It was deployed to JBoss
4.2.2.GA running on Sun JVM 1.6.0_03. The timing results are shown in
six progressive phases. Each result shows the total request time and
the time to render a data table with 50 records. All metrics were
captured using the FireBug extension for Firefox.
</p>
<h2>Introduction</h2>
<p>Developing a data management application is just a matter of getting
data up on the screen in tabular format, correct? Oh, right, and being
able to filter the data. Ah, and also allowing the data to be changed.
Unfortunately, once those challenges are behind us, we tend to wash our
hands of the application and move on. But the principle goal of most
web applications is to enable users to perform their work more
efficiently than they did before we introduced our "solution." In fact,
none of those fancy features you add have any value at all if you can't
improve the user's productivity. That's why, before you step away, you
have to make sure that you have addressed the issue of performance.
</p>
<p>My colleagues and I recently completed the first stage of an open
source data management application based on JSF, Seam, and RichFaces in
which we addressed this very concern. The application, named <a target="_blank" http:=""  www.edas2. com="">EDAS2</a>, was developed for a group of scientists for managing water quality data (stored in the <a target="_blank" http:=""  www.epa. gov="" storet=""  wqx. html="">WQX</a>
database schema). Now, you have to understand that these scientists,
they like their data. Hordes of data. And they like to view it all at
once. So much, in fact, that it tends to cause the browser to crash.
Naturally, we needed to condition the scientists to some degree that
browsers have limits. But regardless, we were going to be dealing with
large data sets. Our goal was to make sure that working with those data
sets was not painful.
</p>
<p>This article documents the bottlenecks that we discovered and a set
of best practices for eliminating them. But we went beyond merely
removing obstacles in performance. We tuned the application to the
point where paginating, sorting, and filtering the data is actually
faster than any desktop application our scientists had ever used. Find
that hard to believe? Read on.
</p>
<h2>About the EDAS2 application</h2>
<p>The intent of the EDAS2 application is to house and analyze
water-quality measurement results. The results are taken from a
location, known as a monitoring location, during a given visit, known
as an activity. There are various types of results, depending on what
is being measured. In this article, we will be focusing on the benthic
measurement result, which in layman's terms is a sampling of mud with
bugs in it. That data is recorded on site and later entered into the
database and analyzed using the EDAS2 interface.
</p>
<p>There isn't anything revolutionary about the interface of the EDAS2
application. Rather, the emphasis is on efficiency. We want to provide
the experience of the MS Access database-which our scientists are
currently using to manage this data-in a web application.
</p>
<p>The application has two types of views. The first is a list view,
which displays a paginated table of records for the currently selected
parent entity, such as monitoring location, activity, or result. You
will learn shortly that what makes this interface efficient is that it
offers in-place editing of each row (it also has a floating popup
dialog for detailed editing of the row).
</p>
<h2>The editable data table</h2>
<p>The key feature of this application is that the data rendered in
each table can be modified in place. To implement this functionality,
we decided against using an off-the-shelf grid editor from a JSF
component library. Instead, we took the RichFaces step-wise approach by
building a composite, Ajax-enabled component using the partial page
rendering technology that the Ajax4jsf core provides.
</p>
<p>Ajax4jsf provides a set of tag libraries that can tie a JSF
generated event to the rerendering of one or more regions of the
user-interface. Those regions are identified by their JSF client IDs.
When the JSF event is sent to the server, instead of the JSF servlet
returning an entire page response, it returns only fragments of the
HTML. Ajax4jsf then cuts out the old branches from the live view and
stitches in the replacements returned from the server. The result is
that the user observes the page updating without any noticeable
refresh, in real-time, so to speak. And Ajax4jsf's declarative approach
let's us fine-tune this behavior.
</p>
<p>
Figure 1 provides a view of the editable data table with one of the rows in edit mode.
</p>
<p>
<a name="figure 1">&nbsp;
</a><img alt="Figure 1. The data table demonstrating its single-line editing capabilities." src="http://www.jsfcentral.com/articles/images/speed-up-your-jsf-app/fig01.png" align="" border="0" /><br />
<span>
Figure 1. The data table demonstrating its single-line editing capabilities.</span><br />
</p>
<p>When the page is first rendered, all rows have an edit and delete
button. Clicking on an edit button puts the corresponding row in edit
mode, at which point the outputs in the selected row become inputs.
From edit mode, the user can make changes to the visible data and
either save or cancel the update, which returns the table to read-only
mode.
</p>
<p>The strategy we use to deliver this row-level editing functionality
is to have two UI components in each column of a standard JSF data
table: one output component (e.g., &lt;h:outputText&gt;) and one input
component (e.g., &lt;h:inputText&gt;). We then use the JSF rendered
attribute on each component to control which one is displayed.
</p>
<h2>A backend supported by Seam</h2>
<p>To support our editable data table, we put together a small
hierarchy of classes that are instantiated as Seam components to manage
the query (filtering, pagination) and the editing process (select row
for editing, update, delete, cancel). We chose to put the components in
Seam's conversation scope. The conversation scope is a slice of the
HTTP session that is managed by Seam and associated with a sequence of
pages through the use of a special request token (known as the
conversation id). The conversation provides the developer the
convenience of using the HTTP session without the memory leakage
concerns, since the conversation has a much shorter lifetime and is
kept isolated from other parallel conversations in the same session.
</p>
<p>
We chose to leverage the conversation for three reasons:
</p>
<ul>
    <li>to reduce the number of times the database needs to be queried</li>
    <li>to ensure the record remains managed by the persistence context while being edited</li>
    <li>to maintain the search criteria and pagination offset </li>
</ul>
<p>Using the conversation has the added bonus of making previously
viewed result pages load faster since the records are already sitting
in the persistence context (i.e., the first-level cache).
</p>
<p>Given all the benefits the conversations provide, you may be
wondering where the performance problem is. Let's take at look at where
things began to go wrong and what we did about it. <br />
</p>
<p><span><span>
<h2>The performance roadblock</h2>
<p>
Development was going smoothly until my colleague noticed something
peculiar about the performance. Five or ten records on the page took a
reasonable amount of time to render, but when that number went up to 50
or 100 records, the performance of the page plummeted. It turns out
that the degradation was linear, but the slope was very steep. The page
with 100 records was taking over 15 seconds to render. Obviously, that
just wasn't going to fly. And so our optimization work began. Could we
find the bottleneck and how low could we go?
</p>
<p>As we optimized, we first looked at the most basic page and
established a performance baseline. Then we added additional components
to the page and tried to identify which ones were contributing to the
major slowdown. As it turns out, in a Seam application, the first area
to place your focus is on page actions, which are methods that execute
before the page begins to render.
</p>
<h2>Page actions and component initialization</h2>
<p>When a page is taking 15 seconds to render, there is likely a single
culprit that is chewing up a bulk of that time. To establish a
baseline, and to make sure I was focusing on the right problem, I first
stripped everything from the page and requested it. The response took a
couple of seconds to come back. This had me puzzled for a moment. I
soon realized that that a Seam page action was registered with the page
(i.e., view ID). A page action is a method-binding expression that is
assigned to a JSF view ID (or a group of view IDs if a wildcard is
used) in a Seam page descriptor and is evaluated by Seam just before
the view ID is rendered by the JSF view handler. Here's the expression
that was registered with the view ID of the results page.
</p>
<code>
&lt;action execute="#{benthicMsmntEditor.prepareResults}" /&gt;
</code>
<p>The page action is there to eagerly fetch the results that are to be
displayed on the page. However, the query in that method was executing
in about a tenth of a second. So that wasn't the problem. After
studying the code a bit longer, I recognized that the problem was not
in the page action method, but rather the @Create method of the
component being invoked. The @Create method is a synonym to the
standard @PostConstruct method in Java EE and marks a method to be
evaluated immediately after a component is instantiated.
</p>
<p>Inside the @Create method was a handful of queries that retrieved
more than 10,000 records of reference data. This data is used by select
menus in various forms on the page, but those forms are all being
conditionally rendered. So basically, we were charging the user a toll
to enter the page with a chance that that reference data would never be
referenced. That brings us to lesson #1.
</p>
<p>
<strong>Lesson #1:</strong><em> Don't make the user pay an upfront fee to view a page. Defer logic where possible. </em>
</p>
<p>Since the forms are rendered conditionally, and some via Ajax, the
reference data can be retrieved at the same time the forms are
activated. If you must display a form unconditionally, think about the
most efficient way to prepare the data (perhaps using a cache). It's
also preferable to use Ajax-based autocomplete rather than select menus
with a large list of options, since making this switch can drastically
reduce the speed of the initial rendering of the form. The user will
likely be more patient when working on the field with autocomplete, and
you can even keep the number of options delivered to a minimum as the
user types.
</p>
<p>With the toll skimmed off the top, we could get back to the
performance of the elements on the page. Bringing back the page
piece-by-piece, I determined that the next big time hog was in fact the
data table. Again, I stripped out elements in the data table until I
pinned down what was causing the problem. As it turns out, it was the
expressions in the rendered attributes that I was using to hide or show
various components in the table.
</p>
<h2>The cost of conditional rendering</h2>
<p>In each row there are 6 "editable" columns, each containing an
output and an input component and 4 icons for controlling editing
(edit, delete, approve, cancel). In total, there are 16 uses of the
rendered attribute appearing in each row. (Initially I had a couple
columns with multiple input components, which I realized I needed to
group within a panel group [i.e., &lt;h:panelGroup&gt;] so that the
rendered attribute was only applied once).
</p>
<p>As you know, logic that occurs in a single row is multiplied by the
number of rows in the table. In a table with 100 rows, there are 1600
uses of the rendered attribute! But wait, there's even more! The
rendered attribute is a nasty beast in JSF because it's often evaluated
multiple times as the UI component tree is assembled. In fact, during
the render response phase, it's resolved 3 or 4 times <em>per component</em>
in a data table. What that means is that for our data table, the
conditional rendering logic we are using is executed 5200 times for 100
rows! Whatever that logic is better be darn efficient or else it will
have a huge impact on performance.
</p>
<div>Warning: After hearing the bad news about how
the rendered expression is abused by JSF, you might be inclined to use
the &lt;c:if&gt; tag from Facelets. This tag emulates the behavior of
the equivalently named tag from the JSTL tag library. You have to be
careful with this tag, though, because it's not a true JSF component.
It's processed by the Facelets compiler prior to building the UI
component tree and can thus exclude a region of the markup from
contributing to the UI component tree for that view. The benefit of
this tag is that it can reduce the size of the component tree when you
know that certain parts of the page aren't needed. However, the
conditional rendering that you expect to happen on a postback does not,
because at that point, the tree is already built and Facelets does not
reprocess the &lt;c:if&gt; statements.
</div>
<p>As it turns out, we were not being very efficient. Let's take a look
at one of the columns of the data table in the
/BenthicMeasurementList.xhtml view template:
</p>
<code>
&lt;h:column&gt;
&lt;f:facet name="header"&gt;Taxonomic Unit&lt;/f:facet&gt;
&lt;h:outputText
value="#{_item.taxon.name}"
rendered="#{!benthicMsmntEditor.editing(_item)}"/&gt;
&lt;h:selectOneMenu id="taxonomicUnit"
rendered="#{benthicMsmntEditor.editing(_item)}"
defaultLabel="No value set" value="#{_item.taxon}"&gt;
&lt;s:selectItems value="#{taxonValues}" var="_taxon"
label="#{_taxon.name}" noSelectionLabel="No value set"/&gt;
&lt;s:convertEntity/&gt;
&lt;/h:selectOneMenu&gt;
&lt;/h:column&gt;
</code>
<p>As you can see here, I am calling the editing() method on a Seam
component named benthicMsmntEditor to test whether the current row is
in edit mode. We can pass the iteration variable, _item, to the method
because Seam integrates with the JBoss EL, which introduces
parameterized method calls to the Unified EL. The editing() method
performs an identity check between the row data and the selected row.
</p>
<code>
public boolean editing(T itemInRow) {
return itemInEditMode == itemInRow;
}
</code>
<p>Here we are only allowing one row to be in edit mode at a time, but
this logic could easily be enhanced to support editing multiple rows
simultaneously.
</p>
<p>So where's the bottleneck? Initially, you may be inclined to point
the finger at the EL or Java reflection. I did some testing and
determined that the EL is surprisingly fast and Java reflection is
equally optimized. And if you are inclined to believe that the slowness
is caused by the parameterized method call, I'll inform you that
comparing the current item using an EL operator to the item in edit
mode retrieved using the JavaBean style accessor yields the same timing
results:
</p>
<p>
<code>rendered="#{_item == benthicMsmntEditor.itemInEditMode}"</code>
</p>
<p>The culprit is that the editing() method resides on a Seam component
and each method call to a Seam component passes through a stack of
interceptors, unless otherwise skipped by the presence of the
@BypassInterceptors annotation at the component or method level. <br />
</p>
<p style="background-color: highlight;"><span><span>
<p>
When you call an intercepted method once, you would never notice the
impact of the interceptors. However, when you call the method 5200
times, the time spent in the interceptors adds up. How much of a
difference does it make and what other options do we have?
</p>
<p>To determine the impact, I timed both the rendering of the entire
page and the rendering of the data table region, as described in the
introduction. The data table region consists of the data table and the
pagination controls and summary information for the table. A test of 4
requests on 50 rows (2600 calls) produced these timing results:
</p>
Stage 1 timing results (50 rows)
<table>
    <tbody>
        <tr>
            <th>Request</th>
            <th>Elapsed time of request (ms)</th>
            <th>Time to render table (ms)</th>
        </tr>
        <tr>
            <td>1</td>
            <td>6330</td>
            <td>6090</td>
        </tr>
        <tr>
            <td>2</td>
            <td>6340</td>
            <td>6096</td>
        </tr>
        <tr>
            <td>3</td>
            <td>6400</td>
            <td>5883</td>
        </tr>
        <tr>
            <td>4</td>
            <td>6100</td>
            <td>5850</td>
        </tr>
        <tr>
            <td>avg</td>
            <td>6292.4</td>
            <td>5979.8</td>
        </tr>
    </tbody>
</table>
<p>Not many people are going to stick around for a page that takes 6
seconds to render (in the best case scenario), and that doubles for 100
rows. The trick is to outject the selected row so that the comparison
can be done without having to invoke a Seam component. Outjection is a
mechanism in Seam that takes the value of a JavaBean property on a
component and assigns it directly to the name of a variable in the
specified scope (such as the conversion scope). You outject a property
by annotating it with the @Out annotation, as shown here:
</p>
<p>
<code>@Out(required = false) private T itemInEditMode;</code>
</p>
<p>(For readers with Seam experience, there is a reason why you cannot
simply add @BypassInterceptors to the editing() method, which I will
provide in a moment.)
</p>
<p>Now we can check if the row is in edit mode by comparing the
iteration variable in the data table to the outjected property using
the following EL expression in the view:
</p>
<code>"#{item == itemInEditMode}"</code>
<page>
<p>
Here's how things improve after making this change:
</p>
Stage 2 timing results (50 rows)
<table>
    <tbody>
        <tr>
            <th>Request</th>
            <th>Elapsed time of request (ms)</th>
            <th>Time to render table (ms)</th>
        </tr>
        <tr>
            <td>1</td>
            <td>904</td>
            <td>663</td>
        </tr>
        <tr>
            <td>2</td>
            <td>807</td>
            <td>608</td>
        </tr>
        <tr>
            <td>3</td>
            <td>813</td>
            <td>569</td>
        </tr>
        <tr>
            <td>4</td>
            <td>823</td>
            <td>592</td>
        </tr>
        <tr>
            <td>avg</td>
            <td>836.8</td>
            <td>608</td>
        </tr>
    </tbody>
</table>
<p>Less than one second is certainly a nice place to be. We can do
better, but let's first focus on the 5 second discrepancy because it is
a cause of concern regarding Seam's performance.
</p>
<p>The truth is, interceptors come with a cost. Again, this cost only
adds up when you are pounding the component, like the rendered
attribute does. Unfortunately, that is more of a limitation (and a fact
of life) in the way that the data table component in JSF was designed.
On the other hand, that is why Seam provides the @BypassInterceptors
annotation. This annotation is intended to be used on methods that read
the state of a component, as opposed to a method with behavior. After
all, Seam is a stateful framework and espouses using objects as they
were intended, to have behavior <em>and</em> state.
</p>
<p>
So why not just add @BypassInterceptors to the editing() method to
reduce the overhead of invoking it? Theoretically that would work. The
only problem is that Seam relies on interceptors to restore the state
of conversation-scoped components, at least in Seam 2.0. In Seam 2.1,
this behavior is disabled by default, so you could just add
@BypassInterceptors to the method. However, if you plan to use stateful
session beans (SFSBs) in your application or run the application in a
cluster, you will need to enable the behavior I am about to describe,
so it's important to understand why interceptors on conversation-scoped
components are important.
</p>
<h2>Seam's managed entity interceptor</h2>
<p>Seam 2.0 uses an interceptor that aids with maintaining the object
identity of persistent objects (managed entities) across passivation of
a SFSB, or when components jump nodes in a cluster. This interceptor
has good intentions, but can have bad consequences. At the end of a
method call on a conversation-scoped component, the interceptor
transfers the values of all fields holding references to entity
instances directly into the conversation context, and then nullifies
the values of those fields. It reverses the process at the beginning of
the next call. The consequence is that without interceptors, your
conversation-scoped object is missing state. Eeek! What's worse is that
the performance of the interceptor is naturally challenged if your
component happens to be storing large data sets, because it takes time
for the interceptor to perform its work. It's an unfortunate sacrifice
in order to achieve transparent replication.
</p>
<p>Rather than worrying about whether to use this interceptor, or
locking the design of your application into its absence, it's best just
to avoid the need to disable interceptors. Besides, there are still
other interceptors that may need to be enabled on a component's methods
(its all or nothing when you disable them) and working with outjected
data is the fastest approach anyway. You can feel comfortable calling
methods on Seam components in other areas of your page, but you should
avoid doing so inside of a data table, which brings us to our second
lesson.
</p>
<p>
<strong>Lesson #2</strong>: <em>Don't call intercepted methods inside a data table (or in excess)</em>
</p>
<p>The question is, have we done all that we can do to optimize? Not
even close. There is another important lesson to learn, and this one
has to do with the EL, or more specifically, the EL resolver mechanism.
</p>
<h2>Resolving variables efficiently</h2>
<p>In JSF, the view is bound to server-side components using a syntax
known as the Unified Expression Language (EL). The root of an EL string
(e.g., #{itemInEditMode}) is presumed to be a variable in one of the
available web application scopes, or the name of a component that must
be created (such as a JSF managed bean or Seam component). The name
resolution is handled by the EL resolver chain, which is a collection
of objects that know how to locate or create objects that map to a
name. All resolvers in the chain are consulted until the end of the
chain is reached or a value is found. This lookup happens a tremendous
number of times while rendering a JSF view, especially while rendering
a data table. Thus, it's a potential source of performance problems. <br />
</p>
<p><span><span><span>
<p>
As the EL resolver chain seeks out a variable, it becomes increasingly
more aggressive. The standard EL resolver looks in the familiar places:
the request, session, and application scope. It then turns the task
over to the Seam resolver, which is where things start to slow down.
Seam has lots of different places to look to resolve a variable: a
component, a factory, a Seam namespace, a Seam context, and the list
goes on. Thus, not finding a variable comes at a high cost.
</p>
<p>So the solution is simply to avoid referencing a missing variable,
right? Well, what happens when a null value for a variable is
meaningful in your application, as is the case of our editable data
grid. A null value for the itemInEditMode variable means the row is not
in edit mode. Unfortunately, the EL resolver chain doesn't know that a
null value means something, and will keep working through its crib
sheet until it has tried all possible combinations. Thus, we need to
find some way to tell Seam exactly where to look rather than allowing
Seam to send out its search party, so to speak. </p>
<p>
Again, taking advantage of the flexibility afforded to us by the JBoss
EL, we can reach directly into the conversation context to look for the
row in edit mode:
</p>
<p>
<code>rendered="#{_item == conversationContext.get('itemInEditMode')}"</code>
</p>
<p>
Here's the reward we get for telling Seam exactly where to look:
</p>
Stage 3 timing results (50 rows)
<table>
    <tbody>
        <tr>
            <th>Request</th>
            <th>Elapsed time of request (ms)</th>
            <th>Time to render table (ms)</th>
        </tr>
        <tr>
            <td>1</td>
            <td>491</td>
            <td>207</td>
        </tr>
        <tr>
            <td>2</td>
            <td>495</td>
            <td>224</td>
        </tr>
        <tr>
            <td>3</td>
            <td>493</td>
            <td>201</td>
        </tr>
        <tr>
            <td>4</td>
            <td>444</td>
            <td>211</td>
        </tr>
        <tr>
            <td>avg</td>
            <td>480.8</td>
            <td>210.8</td>
        </tr>
    </tbody>
</table>
<page>
<p>We roughly doubled our performance and now have 100 rows coming in
under a second, with an order of magnitude improvement over the first
run. But there is still a slight bottleneck. The variable _item is
stored in request scope by the data table and is resolved quickly, but
the variable conversationContext is a pseudo-variable that Seam
interprets after looking in all the usual places for a real variable
named conversationContext. Not only that, conversationContext is an
imported context variable, the qualified name being
org.jboss.seam.context.conversationContext. It turns out that
referencing a context variable in an imported namespace has a
measurable cost associated with it. A better choice would be to pull
the result of this lookup somewhere closer so that Seam doesn't have to
keep searching for it. We can set that up using an alias (an
event-scoped factory) in the Seam component descriptor named
conversationScope (to match requestScope, sessionScope, and
applicationScope provided by the standard EL resolver):
</p>
<p>
<code>&lt;factory name="conversationScope" value="#{conversationContext}"/&gt;</code>
</p>
<p>
We now reference this name in our rendered logic:
</p>
<p>
<code>rendered="#{_item == conversationScope.get('itemInEditMode')}"</code>
</p>
<p>
Here's how the timing results improve:
</p>
Stage 4 timing results (50 rows)
<table>
    <tbody>
        <tr>
            <th>Request</th>
            <th>Elapsed time of request (ms)</th>
            <th>Time to render table (ms)</th>
        </tr>
        <tr>
            <td>1</td>
            <td>399</td>
            <td>161</td>
        </tr>
        <tr>
            <td>2</td>
            <td>373</td>
            <td>150</td>
        </tr>
        <tr>
            <td>3</td>
            <td>458</td>
            <td>207</td>
        </tr>
        <tr>
            <td>4</td>
            <td>560</td>
            <td>163</td>
        </tr>
        <tr>
            <td>avg</td>
            <td>447.5</td>
            <td>170.25</td>
        </tr>
    </tbody>
</table>
<p>Those are the kinds of numbers we want to see! Just as I mentioned
at the start of this article, there was likely a single culprit that
was squandering a majority of the rendering time. It turns out to have
been the logic in the rendered attribute of components within a data
table. But really any logic inside of a data table has to be optimized
because it's going to be compounded by the number of rows being
rendered. For instance, you might be conditionally rendering columns
based on the user's preferences. That brings us to the third lesson.
</p>
<p>
<strong>Lesson #3:</strong> <em>Be extremely frugal with the logic you use within a data table</em>
</p>
<p>Incidentally, I thought about using an action listener to toggle the
rendered state on components in a row when the user clicks on the edit
button, since that's the "object-oriented" way of doing things.
Unfortunately, the design of the data table is extremely naive and does
not support this usage pattern. A data table doesn't have any concept
of rows, only columns. The rows are introduced dynamically based on the
data fed to the table (they are not represented in the state of the
component tree). Thus, if you change the rendered attribute on a
component in one of the rows, you end up affecting every row in the
table. The dynamic nature of the data table leads to many other
problems in JSF, including the "ghost click" which I discuss in my
book, <a target="_blank" http:=""  mojavelinux. com="" seaminaction="">Seam in Action</a>
</p>
<p>
If you are committed to squeezing as much performance as possible out
of your page, then there is one more way you can optimize the speed of
the rendered logic: don't use it. I'm not suggesting that we throw out
the editable grid functionality. If you think about it, that logic only
needs to be performed once the user has selected a row. Before that
time, you know that you only need to display the table in read-only
mode (and you know which controls to provide in that case). Thus, the
best thing to do is split the table into two, one that has the rendered
logic in the columns and one that does not, then toggle the rendering
of the entire table. That way, the person just browsing the data does
not have to pay the tax of checking for the row selected for editing.
While this does increase the amount of code to maintain, it introduces
the possibility of having different columns displayed when the user is
editing than when they are just viewing (or even having the table look
different in some way). You can move common code into templates to
prevent duplication. Of course, the performance is now going to
increase noticeably.
</p>
Stage 5 timing results (50 rows)
<table>
    <tbody>
        <tr>
            <th>Request</th>
            <th>Elapsed time of request (ms)</th>
            <th>Time to render table (ms)</th>
        </tr>
        <tr>
            <td>1</td>
            <td>537</td>
            <td>174</td>
        </tr>
        <tr>
            <td>2</td>
            <td>355</td>
            <td>127</td>
        </tr>
        <tr>
            <td>3</td>
            <td>372</td>
            <td>127</td>
        </tr>
        <tr>
            <td>4</td>
            <td>374</td>
            <td>127</td>
        </tr>
        <tr>
            <td>avg</td>
            <td>409.5</td>
            <td>138.8</td>
        </tr>
    </tbody>
</table>
<p>You are probably feeling pretty happy with the progress so far.
Where to next? In each of the performance results, I have provided two
columns of data for a reason: to emphasize that we are paying yet
another tax to render the remainder of the page. That is the focus of
the next round of optimizations. Obviously, the size of this tax is
going to depend on what else you have on your screen and won't
necessarily amount to the ~270ms appearing in these test results.
Regardless, the amount of this tax now exceeds the cost of the product
and we need to do something about it. That's where Ajax comes in.
</p>
<h2>Cutting costs with Ajax</h2>
<p>The bottleneck in any decently performing web application is the
process of the browser requesting and ultimately rendering a new page.
What makes the process worse is that it happens synchronously, forcing
the user to wait until it finishes. It's extremely disruptive and it
makes the application feel slow. A far better approach is to have the
browser only replace the portions of the page that need to be changed
and to insert those changes into the page when they arrive (i.e.,
partial page rendering), which doesn't interrupt what the user is
currently doing (or at least keeps the disruption localized).
</p>
<p>The exchange just described is achieved using Ajax. Fortunately, the
RichFaces component library for JSF makes adding Ajax interactions to a
page extremely straightforward. In the next part of this article,
you'll learn to use RichFaces' partial-page rendering to only update
the data table when the user change its state, such as to select a row
for editing or paginating the table, thus eliminating the tax that
comes with rerendering the entire page. Once this change is made, the
two orders of magnitude performance boost will be realized. <br />
</p>
<p><br />
</p>
<p><strong>Speed up your Data-Driven JSF/Seam Application by Two Orders of Magnitude &#8211; Part 2</strong><br />
by Dan Allen<br />
27 Mar 2009 01:30 EDT</p>
<p><span>
<p>In the second
installment of this two-part article, Dan Allen continues his
discussion of some common performance problems you may encounter when
using JSF components, Seam components, and the EL. You'll learn about
the set of best practices for eliminating them that led to an
improvement of two orders of magnitude in the performance of his
application.</p>
</span></p>
<hr align="center" width="100%" />
<span>
<p>
In the first part of this article, I began briefing you on
optimizations I made to maximize the responsiveness of a JSF
application that I developed out in the field. I cited performance
problems caused by casually accessing components from a JSF view, then
presented a set of best practices to eliminate this unnecessary
overhead. Despite the progress made by the end of the first part, you
had not yet witnessed the two orders of magnitude in performance
improvement that was promised. </p>
<p> In this part, the additional gains will be achieved by
leveraging partial page rendering-provided by the RichFaces JSF
component library and by slimming the response. Partial page rendering
cuts out the overhead of rerendering the entire page after each user
interaction, which turns out to be the real bottleneck in most
traditional web applications, and instead redraws only the areas of the
page that have changed. Naturally, you want the replacement HTML source
to be as condensed as possible. These optimizations allow the
responsiveness of a web application to measure up to its desktop
counterpart. </p>
<h2>Tapping into Ajax</h2>
<p> When the user performs an
operation on the screen, such as selecting a row for editing or
paginating a result set, we only want to rerender the area of the page
that is affected. Using the data-driven application presented in the
first part, that means redrawing the data table and its pagination
controls. (Note that it's possible with Ajax4jsf to rerender a single
row, when applicable, but I have found it to be more trouble than it's
worth). </p>
<p>
Putting numbers aside, using Ajax is going to make the application feel
far more responsive because the browser does not have to bootstrap a
whole new page and all the assets that come along with it. <a href="http://developer.yahoo.com/performance/rules.html">Research</a>
has shown that creating HTTP connections is more costly than rendering
large pages. Partial page rendering accounts for these findings by
treating the static areas of the page and its associated assets as
completed work, and focusing solely on retrieving updates. This section
will support my recommendation that you should always consider using
Ajax in your application, as it truly does eliminate a lot of overhead.
</p>
<h2>Accessible Ajax with Ajax4jsf</h2>
<p>Turning regular JSF postbacks into Ajax requests is pretty simple
with Ajax4jsf. However, if used inappropriately, you won't get all the
performance gains you are looking for. We'll get to that in a second.
First, begin by changing your &lt;h:commandLink&gt; and
&lt;h:commandButton&gt; components to the ones from Ajax4jsf:
&lt;a:commandLink&gt; and &lt;a:commandButton&gt;. Next, select what
you want to rerender. You reference the areas of the page to update
using a comma-separated list of the regions' component IDs in the
reRender attribute of the command component. If you are paginating, you
need to rerender the whole table and the pagination controls
(dataTableContainer). If you are transitioning into edit mode, there's
no need to requery or update the pagination, so you only have to
rerender the table itself. Here's the code for the pagination controls:
</p>
<code>&lt;a:commandLink id="previous" action="#{benthicMsmntEditor.previous}"
rendered="#{benthicMsmntEditor.previousAvailable}"
reRender="dataTableContainer"
ajaxSingle="true"&gt;
&lt;h:graphicImage value="/img/previous.png" alt="Previous" title="Previous"/&gt;
&lt;/a:commandLink&gt;
&lt;a:commandLink id="next" action="#{benthicMsmntEditor.next}"
rendered="#{benthicMsmntEditor.nextAvailable}"
reRender="dataTableContainer"
ajaxSingle="true"&gt;
&lt;h:graphicImage value="/img/next.png" alt="Next" title="Next"/&gt;
&lt;/a:commandLink&gt;
</code>
<p>
The code for the edit control buttons in each row is similar. Here's how the edit button is defined:
<code>&lt;a:commandLink id="edit" action="#{benthicMsmntEditor.editItem}"
rendered="#{_item != conversationScope.get('itemInEditMode')}"
reRender="dataTable" ajaxSingle="true"&gt;
&lt;h:graphicImage value="/img/edit.png" alt="Edit" title="Edit"/&gt;
&lt;/a:commandLink&gt;
</code></p>
<p>What's important about using an Ajax request is to keep it simple.
You don't want to perform a lot of processing on the server because
then the users aren't going to get the "instant" feedback they are
expecting. You can drastically reduce the portion of the component tree
that is processed by JSF by using either the &lt;;a:region&gt; tag or
the ajaxSingle attribute on an Ajax4jsf component. Let's focus on
ajaxSingle.
</p>
<h2>Keeping the Ajax call brief</h2>
<p>By default, JSF processes the whole component tree on a postback
because it doesn't know where events may originate or which input
fields within the submitted form contain new data. What the ajaxSingle
attribute does is tell JSF to advance directly to the component that
was activated, process events from that component, and re-encode it as
if it were the only component on the page. The result is a drastic
speed increase in the processing, independent of the size of the
component tree. In fact, the only time you would forgo using ajaxSingle
is when you need to capture input data from a form (a classic form
submit). </p>
<p>
When deciding whether or not to use this attribute, ask yourself if you
are capturing form data or whether JSF is simply using the form submit
to perform server-side work (a contrived form submit). In JSF, it's
most often the latter.
</p>
<p> Note: Interestingly enough, ajaxSingle is also a drop-in
replacement for immediate, which is excellent since immediate is so
poorly understood. When ajaxSingle is placed on a command component
(such as a button), the form data is not processed, and hence no
validation/conversion failures can occur, thus eliminating the need for
immediate. </p>
<p> Having shifted all interactions to the Ajax bridge, it's
now time to look at the performance gains. Of course, when using Ajax,
the tax of rendering the portions of the page outside of the data table
is gone. The performance on the server is also no longer a primary
concern. Now what matters is the size of the response. Unfortunately,
giving timing results here would be arbitrary because it's highly
dependent on the speed of the network (and I'm testing against my own
box). We have to focus on what we can control. </p>
<h2>Trimming down the response</h2>
<p>
So what affects response size? The answer is, every character in the
view. Every character that you type that is encoded into the response,
as well as the markup that the JSF components generate, affects the
size of the response. That includes:
</p>
<ul>
    <li>Component IDs</li>
    <li>View IDs</li>
    <li>The path of images, external JavaScript files, and CSS</li>
    <li>The application context path</li>
    <li>Embedded JavaScript</li>
    <li>Inline styles and names of style classes</li>
    <li>Erroneous markup that is encoded into the response</li>
</ul>
<p>
As you can see, there's lots of room for improvement in this category.
I want to focus on component IDs first, since they are the biggest
culprit. <br />
</p>
<p><span><span><span><span>
<h2>Resources</h2>
<ul>
    <li><a target="_blank" href="http://code.google.com/p/seaminaction/source/browse/#svn/demos/articles/edas2-perflab">Code samples for this article (browse)</a></li>
    <li><a target="_blank" href="http://seaminaction.googlecode.com/svn/demos/articles/edas2-perflab">Code samples from this article (SVN checkout)</a></li>
    <li><a target="_blank" href="http://developer.yahoo.com/performance/rules.html">Best Practices for Speeding Up Your Web
    Site</a></li>
    <li><a target="_blank" href="http://www.ibm.com/developerworks/java/library/j-richfaces/index.html">An introduction to RichFaces</a></li>
    <li><a target="_blank" href="http://docs.jboss.org/jbossas/guides/webguide/r2/en/html/ch07.html">JBoss virtual host configuration</a></li>
    <li><a target="_blank" href="http://www.edas2.com/">EDAS2 Homepage</a></li>
    <li><a target="_blank" href="http://seamframework.org/">Seam</a></li>
    <li><a target="_blank" href="http://www.jboss.org/jbossrichfaces">RichFaces</a></li>
    <li><a target="_blank" href="http://in.relation.to/">Seam, Hibernate, RichFaces, and JBoss
    Tools blog</a></li>
</ul>
</span><hr align="center" width="100%" />
<span>
Dan Allen is a Senior Software Engineer at Red Hat and author of Seam
in Action. He has over eight years of development experience using
technologies that include Java frameworks (Seam, JSF, EJB3, Hibernate,
Spring, Struts), testing frameworks (JUnit, TestNG), JavaScript and
DOM scripting, CSS and page layouts, Maven 2, Ant, Groovy, and many
others.
<p xmlns:jsfcentral="http://www.jsfcentral.com" xmlns:dc="http://purl.org/dc/elements/1.1/">
After graduating from Cornell University with a degree in Materials
Science and Engineering in 2000, Dan became captivated by the world
of free and open source software, which gave him his debut in
software development. He soon discovered the combination of Linux and
the Java EE platform to be the ideal blend on which to build his
professional career, with his interests equally divided between the
two platforms.
</p>
<p xmlns:jsfcentral="http://www.jsfcentral.com" xmlns:dc="http://purl.org/dc/elements/1.1/">
Dan is a member of the Seam project, a dedicated open source
advocate, and a Java blogger. He lives with his extremely supportive
wife in Laurel, MD. You can keep up with Dan's development
experiences by subscribing to his blog at
<a href="http://mojavelinux.com/">Mojavelinux</a></p>
</span></span></span></span></p>
<p><br />
</p>
</span></page>
</span></span></span></p>
</page>
</span></span></p>
</span></span></p>
</span><br />
<img src ="http://www.blogjava.net/sealyu/aggbug/269329.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-05-07 09:16 <a href="http://www.blogjava.net/sealyu/archive/2009/05/07/269329.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>浅谈Seam 中的取数据的问题和@Factory的使用</title><link>http://www.blogjava.net/sealyu/archive/2009/05/06/269248.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Wed, 06 May 2009 07:30:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/05/06/269248.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/269248.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/05/06/269248.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/269248.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/269248.html</trackback:ping><description><![CDATA[<br />
作者： sealyu&nbsp;&nbsp; 日期：2009-05-06<br />
<br />
在Seam中，如果要提供一个集合属性传到页面，那么可以有两种选择：<br />
（1).在SFSB中建一个集合属性，并建立一个方法用来取得对应的数据。例如我们有一个SFSB（TestAction.java）：<br />
＠Stateful&nbsp; <br />
@Name("testPerson")<br />
public class TestAction extends TestActionLocal implements Serializable{<br />
&nbsp; protected List&lt;Person&gt; personList;<br />
&nbsp; public List&lt;Person&gt; getPersonList(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //得到对应数据<br />
&nbsp; }<br />
}<br />
每次在前台页面调用的时候可以直接使用：<br />
&lt;rich:dataTable value="#{testPerson.personList}" id="xxx"/&gt;.<br />
<br />
但是这种方法有种缺点，因为将对应的值赋值给一个JSF组件，所以在刷新一个页面的时候经常需要调用很多次取数据的函数，即使你作判断（例如：当值不为空的时候不再重新取值），这个函数还是会执行很多次，可能会造成效率的问题。<br />
但是这种方法的好处是总是可以取得最新的数据。在你经常通过传递参数来取得数据列表的时候，这种方法比较好。<br />
（2).使用＠Factory. <br />
＠Factory有两种，在它的javadoc里面是这么说的：<br />
&nbsp;* Marks a method as a factory method for a context variable.<br />
&nbsp;* A factory method is called whenever no value is bound to<br />
&nbsp;* the named context variable, and is expected to initialize<br />
&nbsp;* the value of the context variable. There are two kinds of <br />
&nbsp;* factory methods. Factory methods with void return type are <br />
&nbsp;* responsible for outjecting a value to the context variable. <br />
&nbsp;* Factory methods which return a value do not need to <br />
&nbsp;* explicitly ouject the value, since Seam will bind the<br />
&nbsp;* returned value to the specified scope.<br />
<br />
<strong>第一种工厂方法:</strong><br />
这种工厂方法没有返回值，但是你需要将得到的数据注出到context里面，大多数情况下你可以直接使用＠DataModel，例如：<br />
＠Stateful&nbsp; <br />
@Name("testPerson")<br />
public class TestAction extends TestActionLocal implements Serializable{<br />
&nbsp; @DataModel<br />
&nbsp; protected List&lt;Person&gt; personList;<br />
&nbsp; @Factory(value="personList", autoCreate=true)<br />
&nbsp; public void getPersonList(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //得到对应数据<br />
&nbsp;&nbsp;&nbsp;&nbsp; this.personList=mgr.createQuery....<br />
&nbsp; }<br />
}<br />
<br />
<strong>第二种工厂方法：</strong><br />
这种工厂方法有返回值，seam会根据scope的值将数据绑定到对应的上下文中。使用这种方法，你不用显式的注出。例如：<br />
<br />
＠Stateful&nbsp; <br />
@Name("testPerson")<br />
public class TestAction extends TestActionLocal implements Serializable{<br />
&nbsp; protected List&lt;Person&gt; personList;<br />
&nbsp; @Factory(value="personList", autoCreate=true)<br />
&nbsp; public List&lt;Person&gt; getPersonList(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //得到对应数据<br />
&nbsp;&nbsp;&nbsp;&nbsp; this.personList=mgr.createQuery....<br />
&nbsp;&nbsp;&nbsp;&nbsp; return personList;<br />
&nbsp; }<br />
}<br />
<br />
不管使用哪种方法，你都可以在页面中直接访问这个factory的值：<br />
&lt;rich:dataTable value="#{personList}" id="xxx"/&gt;<br />
<br />
使用＠Factory的好处是不用重复的去取值，但是同时也有一个缺点：<br />
&nbsp; 使用@Factory的时候，只有在context中没有这个@Factory所对应的绑定值的时候，seam才会重新执行工厂方法来取得这个值。所以如果你想要在CRUD一个实体之后更新列表的话，你可以监听org.jboss.seam.afterTransactionSuccess.XXEntity事件来更新这个＠Factory的值。暂时没找到强制清空并刷新＠Factory的方法，seam好像现在并没有提供这个方法，所以我现在是直接清空＠Factory所对应的list的值来达到刷新的目的。<br />
<br />
<br />
<img src ="http://www.blogjava.net/sealyu/aggbug/269248.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-05-06 15:30 <a href="http://www.blogjava.net/sealyu/archive/2009/05/06/269248.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在xhtml中使用空格</title><link>http://www.blogjava.net/sealyu/archive/2009/04/29/268052.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Wed, 29 Apr 2009 02:21:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/04/29/268052.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/268052.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/04/29/268052.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/268052.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/268052.html</trackback:ping><description><![CDATA[在xhtml页面中加入空格不能使用"&amp;nbsp;" 要使用&nbsp;
<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 src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: #000000">&amp;</span><span style="color: #000000">#</span><span style="color: #000000">160</span><span style="color: #000000">;</span></div><img src ="http://www.blogjava.net/sealyu/aggbug/268052.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-04-29 10:21 <a href="http://www.blogjava.net/sealyu/archive/2009/04/29/268052.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>h:panelGrid 属性详解(转)</title><link>http://www.blogjava.net/sealyu/archive/2009/04/24/267269.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Fri, 24 Apr 2009 00:34:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/04/24/267269.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/267269.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/04/24/267269.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/267269.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/267269.html</trackback:ping><description><![CDATA[一.页面布局:<br />
&lt;h:panelGrid &gt;样式表基本概念:<br />
单元格样式:&nbsp; columnClasses="columnClasses1, columnClass2,..."&nbsp; &lt;==&gt;&nbsp;
&lt;td class="columnClasses1"&gt;....&lt;td class="columnClasses2"&gt;<br />
行样式:&nbsp; rowClasses="rowClasses1, rowClasses2"&nbsp; &lt;==&gt;&nbsp; &lt;tr class="rowClasses1"&gt;....&lt;tr class="rowClasses2"&gt;<br />
样式:&nbsp; styleClass=""&nbsp; ==&nbsp; &lt;table class=""&gt;<br />
注:&nbsp; 无法实现多个表头单元.<br />
<br />
panelGrid 标签学习 <br />
这个标签可以用来作简单的组件排版，它会使用HTML表格标签来绘制表格，并将组件置于其中，主要指定columns属性，例如设定为 2： <br />
&lt;h:panelGrid columns="2"&gt; <br />
&lt;h:outputText value="Username"/&gt; <br />
&lt;h:inputText id="name" value="#{userBean.name}"/&gt; <br />
&lt;h:outputText value="Password"/&gt; <br />
&lt;h:inputText id="password" value="#{userBean.password}"/&gt; <br />
&lt;h:commandButton value="submit" action="login"/&gt; <br />
&lt;h:commandButton value="reset" type="reset"/&gt; <br />
&lt;/h:panelGrid&gt; <br />
则自动将组件分作 2 个 column来排列，排列出来的样子如下： <br />
<br />
<br />
&lt;h:panelGrid&gt;的本体间只能包括JSF组件，如果想要放入非JSF组件，例如简单的样版（template）文字，则要使用 &lt;f:verbatim&gt;包括住，例如： <br />
&lt;h:panelGrid columns="2"&gt; <br />
&lt;f:verbatim&gt;Username&lt;/f:verbatim&gt; <br />
&lt;h:inputText id="name" value="#{userBean.name}"/&gt; <br />
&lt;f:verbatim&gt;Password&lt;/f:verbatim&gt; <br />
&lt;h:inputText id="password" value="#{userBean.password}"/&gt; <br />
&lt;h:commandButton value="submit" action="login"/&gt; <br />
&lt;h:commandButton value="reset" type="reset"/&gt; <br />
&lt;/h:panelGrid&gt; <br />
<br />
<br />
<br />
&lt;h:panelGroup&gt; <br />
这个组件用来将数个JSF组件包装起来，使其看来像是一个组件，例如： <br />
&lt;h:panelGrid columns="2"&gt; <br />
&lt;h:outputText value="Username"/&gt; <br />
&lt;h:inputText id="name" value="#{userBean.name}"/&gt; <br />
&lt;h:outputText value="Password"/&gt; <br />
&lt;h:inputText id="password" value="#{userBean.password}"/&gt; <br />
&lt;h:panelGroup&gt; <br />
&lt;h:commandButton value="submit" action="login"/&gt; <br />
&lt;h:commandButton value="reset" type="reset"/&gt; <br />
&lt;/h:panelGroup&gt; <br />
&lt;/h:panelGrid&gt; <br />
在&lt;h:panelGroup&gt;中包括了两个&lt;h:commandButton&gt;，这使得&lt; h:panelGrid&gt;在处理时，将那两个&lt;h:commandButton&gt;看作是一个组件来看待，其完成的版面配置如下所示： <br />
<br />
<br />
下面转载与http://blog.csdn.net/liyong1115/archive/2008/02/27/2125029.aspx <br />
一、初识panelGrid和与之相关的设计元素 <br />
<br />
panelGrid相当于HTML的表格，在设计中与之相关的组件有panelGrop，与之相配合的CSS <br />
<br />
设计元素有styleClass、headerClass、footerClass、rowClasses、columnClasses。这些元 <br />
<br />
素的有机组合，可以设计出不同的输出画面。 <br />
<br />
在HTML网页设计中，表格有&lt;table&gt;&lt;tr&gt;&lt;td&gt;等标记符号，也可以在标记符号内嵌入CSS控 <br />
<br />
制语句来控制输出的表现形式。JSF中的panelGrid虽然与HTML表格相对应，但是二者在设计时 <br />
<br />
还是有很大差异的。例如我们假设有一个HTML的表如下： <br />
<br />
&lt;table&gt; <br />
&lt;tr&gt; <br />
&lt;td&gt;...&lt;/td&gt; <br />
&lt;td&gt;...&lt;/td&gt; <br />
&lt;/tr&gt; <br />
<br />
&lt;tr&gt; <br />
&lt;td&gt;...&lt;/td&gt; <br />
&lt;td&gt;...&lt;/td&gt; <br />
&lt;/tr&gt; <br />
&lt;/table&gt; <br />
<br />
则panelGrid与之对应的标记是： <br />
<br />
&lt;h:panelGrid column="2"&gt; <br />
... <br />
... <br />
... <br />
... <br />
<br />
&lt;/h:panelGrid&gt; <br />
<br />
它只有外壳标记，没有行控制和列控制标记。 <br />
<br />
熟悉HTML编程的道人一眼就看出，只有外壳标记，你该怎样控制行或列的输出样式呢？别 <br />
<br />
急，JSF设计者已经想到了，他们设计出 <br />
<br />
了styleClass、headerClass、footerClass、rowClasses、columnClasses这些设计元素来控 <br />
<br />
制行与列的输出样式，其中 <br />
styleClass是格式表格总的外观的，如表格的长与宽、外边框样式、表格的背景样式等。 <br />
headerClass、footerClass分别是控制表的header和footer的。 <br />
rowClasses和columnClasses分别是控制表格的行与列样式的。 <br />
<br />
还是举个例子说一下，我们有下例： <br />
<br />
&lt;h:panelGrid columns="1" cellpadding="5" <br />
styleClass="styleClazz" <br />
headerClass="headerClazz" <br />
footerClass="footerClazz" <br />
rowClasses="row1,row2" <br />
columnClasses="column1" <br />
&gt; <br />
<br />
&lt;f:facet &gt; <br />
&lt;h:outputText value="您好，朋友！"/&gt; <br />
&lt;/f:facet&gt; <br />
<br />
&lt;h:outputText value="您好，朋友！"/&gt; <br />
&lt;h:outputText value="您好，朋友！"/&gt; <br />
&lt;h:outputText value="您好，朋友！"/&gt; <br />
&lt;h:outputText value="您好，朋友！"/&gt; <br />
&lt;h:outputText value="您好，朋友！"/&gt; <br />
&lt;h:outputText value="您好，朋友！"/&gt; <br />
<br />
&lt;f:facet &gt; <br />
&lt;h:outputText value="您好，朋友！"/&gt; <br />
&lt;/f:facet&gt; <br />
&lt;/h:panelGrid&gt; <br />
<br />
这就是一个表格，columns="1"，规定这个表只有一列，cellpadding="5"说明了边框外线 <br />
<br />
与内线的距离是5个像素。这个表由一个头部、一个尾部和中间表身三部分组成。headerClass <br />
<br />
是格式头部样式的，footerClass是格式尾部样式的，rowClasses和columnClasses是格式行与 <br />
<br />
列样式的。 rowClasses="row1,row2"规定了表格的行与行交替使用row1和row2样式类来格式 <br />
<br />
输出样式，同样，列也是，并且还可以用3个、4个或更多个row3、row4...来依序交替格式输 <br />
<br />
出样式。 <br />
<br />
对应的样式类可以像以下这样编写在css文件中： <br />
<br />
<br />
/*styleClass处于父类的地位,headerClazz,rowClasses等的字体设置取em时, <br />
其在屏幕上显示的大小会参照该类字体的大小设置而放大或缩小*/ <br />
<br />
.styleClazz{ <br />
font-size:1em; <br />
color:blue; <br />
border-style:solid; <br />
border-color:red; <br />
border-width: 1px; <br />
} <br />
<br />
.headerClazz{ <br />
background-color:#3F536B; <br />
font-family:宋体; <br />
font-size:1.5em; <br />
color:white; <br />
text-align:center; <br />
} <br />
<br />
.footerClazz{ <br />
background-color:#3F536B; <br />
font-family:宋体; <br />
font-size:1.5em; <br />
color:white; <br />
text-align:center; <br />
} <br />
<br />
/* 当行样式与列样式都用时,则行样式服从于列样式 <br />
边框的颜色需要在columnClasses中定义, <br />
在rowClasses中定义不起作用 <br />
*/ <br />
<br />
.row1{ <br />
background-color:#FFFFFF; <br />
} <br />
<br />
.row2{ <br />
background-color:#C9D3E0; <br />
} <br />
<br />
.column1{ <br />
border-style:solid; <br />
border-color:red; <br />
border-width: 1px; <br />
} <br />
<br />
.column2{ <br />
} <br />
<br />
<br />
你可以用CSS在JSP中的语法将其编写在JSP文件中。 <br />
<br />
二、panelGrid如何来格式成具有拆分合并样式的表 <br />
<br />
这要用到panelGroup，它的作用是将封装在内的元件作为一个元件来看待，如果panelGroup <br />
<br />
中封装了一个panelGrid，则被封装的表放在其他表中就相当于一个子表。通过panelGroup来封 <br />
<br />
装各UI组件的办法，可以实现表格的拆分目的。 <br />
<br />
&lt;h:panelGroup&gt; <br />
&lt;h:panelGrid&gt; <br />
... <br />
&lt;/h:panelGrid&gt; <br />
&lt;/h:panelGroup&gt; <br />
<br />
或者： <br />
<br />
&lt;h:panelGroup&gt; <br />
&lt;h:outputText value="您好，朋友！"/&gt; <br />
&lt;h:outputText value="您好，朋友！"/&gt; <br />
&lt;/h:panelGroup&gt; <br />
<br />
它们在容器中相当于一个显示元件(好像本来是一个人住一间房，现在是更多的人住一间房)。 <br />
<br />
三、如何在panelGrid中实现设计元素对齐 <br />
<br />
panelGrid是通过CSS语言来格式输出样式的，在CSS语言中可用vertial-align:...;来格 <br />
<br />
式输出元素纵向对齐，使用text-align:...;来实现输出元素横向对齐。其中text-align有点 <br />
<br />
迷糊人，因为从字面看它应该是针对文本的，其实它对其他元素也起作用。 <br />
<br />
在对齐的设计中有个居中对齐的问题容易绕人。在HTML中可用&lt;center&gt;...&lt;/center&gt;来实 <br />
<br />
现被封装的视图元素居中，但在CSS中好像没有类似语句。其实还是有的，只不过绕了一个弯 <br />
<br />
。你想啊，说到居中，那究竟是在多宽的范围内居中？是我这个元素在封装我的容器中居中， <br />
<br />
还是被我封装的元素在我这个容器中居中？这个问题CSS与HTML处理语义是不样的。 <br />
<br />
在HTML中表格居中是： <br />
&lt;table align="center"&gt; <br />
... <br />
&lt;/table&gt; <br />
<br />
表格在这里的居中是指这个表格&#8220;我&#8221;在封装我的容器&lt;body&gt;中居中，具体表现为在屏幕上居 <br />
<br />
中，但是您不能通过 <br />
<br />
&lt;h:panelGrid align="center"&gt; <br />
... <br />
&lt;/h:panelGrid&gt; <br />
<br />
来实现panelGrid在&lt;body&gt;中居中。因为panelGrid标记根本不支持这个语句。还是要通过CSS <br />
<br />
来实现。下面这个使用CSS语句描述居中的语义与HTML使用align="center"语义不同。 <br />
<br />
&lt;h:panelGrid style="text-align:center"&gt; <br />
&lt;h:outputText value="您好，朋友！"/&gt; <br />
&lt;/h:panelGrid&gt; <br />
<br />
这个语句说的是me这个对象在panelGrid 中居中，而不是指表格在&lt;body&gt;(屏幕)中居中。我 <br />
<br />
要在屏幕中居中怎么办？有两种办法，一种是通过在&lt;body&gt;中加入格式说明，第二种办法是在 <br />
<br />
panelGrid的外面再套一个panelGrid。即： <br />
<br />
<br />
&lt;h:panelGrid style="text-align:center;width=979px;"&gt; <br />
<br />
&lt;h:panelGroup&gt; <br />
&lt;h:panelGrid style="text-align:center"&gt; <br />
&lt;h:outputText value="您好，朋友！您好，朋友！"/&gt; <br />
&lt;h:outputText value="您好，朋友！"/&gt; <br />
&lt;h:outputText value="您好，朋友！"/&gt; <br />
&lt;/h:panelGrid&gt; <br />
&lt;/h:panelGroup&gt; <br />
<br />
&lt;/h:panelGrid&gt; <br />
<br />
这样就实现了被封装的panelGrid B 在 A 中居中，注意，这里的width=979px;是必须的，它 <br />
<br />
规定了居中是在多宽的范围内居中！数字多少可以调整，但是你不能不写这个约定，否则，被 <br />
<br />
封装在里面的panelGrid还是不会在屏幕上居中。 <br />
<br />
还有一点注意，里面panelGrid B 的text-align继承外面panelGrid A 中的text-align属 <br />
<br />
性的约定，即里面的panelGrid不写style="text-align:center"，对象me们也会在里 <br />
<br />
面panelGrid中居中。但是里面的panelGrid不继承外面的width，像上面，里面panelGrid的显 <br />
<br />
示宽度与最长的me1有关，而不是外面panelGrid A的宽度979px。 <br />
<br />
四、其他 <br />
■当屏幕的显式格式是1024 X 768 时，最外面的panelGrid宽度取979px是屏幕最大化时 <br />
<br />
底部滚动条由出现到不出现的临界值，如超过979则滚动条就会出现。 <br />
■可以按照是对&lt;table&gt;&lt;tr&gt;还是对&lt;td&gt;起作用的CSS类，进行封装。如写在style语句中 <br />
<br />
，则形如下： <br />
<br />
&lt;h:panelGrid style="width:240px;vertial-align:top;text-align:center;"&gt; <br />
... <br />
&lt;/h:panelGrid&gt; <br />
<br />
<br />
&lt;h:panelGrid id="Grid" border="1" columns="2"
rowClasses="rowClasses" cellspacing="cellspacing"
cellpadding="cellpadding" columnClasses="columnClasses"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;h:outputText value="item1"&gt;&lt;/h:outputText&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;h:panelGroup layout="block" &gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;h:outputText value="item4-panelGroup"&gt;&lt;/h:outputText&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/h:panelGroup&gt;<br />
&lt;/h:panelGrid&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;h:outputLink&nbsp; styleClass="newlink" &gt;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;h:outputText&nbsp;&nbsp; escape="false" value=" &lt;STRONG&gt; 默认论坛版面 &lt;/STRONG&gt; " /&gt;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/h:outputLink&gt;<br />
<br />
&lt;a href="" class="newlink"&gt; &lt;STRONG&gt; 默认论坛版面 &lt;/STRONG&gt; &lt;/a&gt;<br />
<br />
&lt;table id="j_id_jsp_1725709284_1:Grid" border="1" cellpadding="cellpadding" cellspacing="cellspacing"&gt;<br />
&lt;tbody&gt;<br />
&lt;tr class="rowClasses"&gt;<br />
&lt;td class="columnClasses"&gt;item1&lt;/td&gt;<br />
&lt;/tr&gt;<br />
&lt;tr class="rowClasses"&gt;<br />
&lt;td class="columnClasses"&gt;item4-panelGroup&lt;/td&gt;<br />
&lt;/tr&gt;<br />
&lt;/tbody&gt;<br />
&lt;/table&gt;
<img src ="http://www.blogjava.net/sealyu/aggbug/267269.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-04-24 08:34 <a href="http://www.blogjava.net/sealyu/archive/2009/04/24/267269.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Seam安全策略（转）</title><link>http://www.blogjava.net/sealyu/archive/2009/04/23/267164.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Thu, 23 Apr 2009 07:36:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/04/23/267164.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/267164.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/04/23/267164.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/267164.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/267164.html</trackback:ping><description><![CDATA[<h2>原帖地址：http://odyssi.blogspot.com/2008/01/intro-to-jboss-seam-security-part-1.html</h2>
<h3>
<a href="http://odyssi.blogspot.com/2008/01/intro-to-jboss-seam-security-part-1.html">Intro to JBoss Seam Security, Part 1 - Authentication</a>
</h3>
<div>
<p>Recently, I <a href="http://odyssi.blogspot.com/2008/01/jboss-seam-j2ee-development-framework.html">mentioned</a> how I had just started working with the <a href="http://www.jboss.com/products/seam">JBoss Seam application framework</a>.
The more I have worked with it, the more impressed I have become at how
it makes things that are typically difficult using standard Java EE
much simpler and more streamlined. One of the areas in which Seam
really shines is security. While Java EE defines <a href="http://java.sun.com/javase/6/docs/technotes/guides/security/jaas/JAASRefGuide.html">JAAS</a>
for use in securing applications, it is left up to the developer to
ingrain this security down to each facet of the application. With Seam,
it is easy to define security constraints at all levels of an
application, simply through using annotations. In addition, the
complexity of authenticating users with JAAS is reduced through Seam's <a href="http://docs.jboss.com/seam/2.0.1.CR1/reference/en/html/security.html#d0e6900">authenticator</a> mechanism.  This article will give an introduction to Seam authentication, and show how to write your own custom authenticator.<br />
<br />
Seam's
authenticator construct hides the complexity of managing a JAAS
configuration, and allows you to implement authentication how you see
fit. Perhaps your organization relies on a simple username/password
combination for authenticating user accounts in LDAP. Maybe you use a
SecureID token, and the accounts are stored in a SQL database. By
writing your own authenticator class, or making use of publicly
available ones, you can control the way authentication is done in your
organization.<br />
<br />
To get started with your own authenticator, you must first declare it in the <span style="font-size: 85%;"><span style="font-family: courier new;">components.xml</span></span>
file. This file manages much of the configuration for Seam. To add your
authenticator, you simply define the class and method that will be used
for authentication. For example:<br />
<br />
</p>
<div>
<div>
<div><a href="http://odyssi.blogspot.com/2008/01/intro-to-jboss-seam-security-part-1.html#" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><a href="http://odyssi.blogspot.com/2008/01/intro-to-jboss-seam-security-part-1.html#" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a><a href="http://odyssi.blogspot.com/2008/01/intro-to-jboss-seam-security-part-1.html#" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div>
</div>
<ol start="1">
    <li>&lt;components&nbsp;xmlns="http://jboss.com/products/seam/components"&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xmlns:core="http://jboss.com/products/seam/core"&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xmlns:security="http://jboss.com/products/seam/security"&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xsi:schemaLocation=&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"http://jboss.com/products/seam/components&nbsp;http://jboss.com/products/seam/components-2.0.xsd&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http://jboss.com/products/seam/security&nbsp;http://jboss.com/products/seam/security-2.0.xsd"&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>&lt;security:identity&nbsp;method="#{authenticator.authenticate}"&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>&lt;/components&gt;&nbsp;&nbsp;</li>
</ol>
</div>
<br />
<br />
You'll notice the #{} syntax used here.  This is JBoss' expression language pointing to a class with the instance name of <span style="font-size: 85%;"><span style="font-family: courier new;">authenticator</span></span>, where the <span style="font-size: 85%;"><span style="font-family: courier new;">authenticate</span></span>
method will be used to login a user. Now that we have declared an
authenticator to Seam, we're ready to implement it. Our example will be
quite simple. If the user enters a username of <span style="font-size: 85%;"><span style="font-family: courier new;">admin</span></span>, with a password of <span style="font-size: 85%;"><span style="font-family: courier new;">password</span></span>, they will be authenticated successfully.  In addition, we will assign them to the role of <span style="font-size: 85%;"><span style="font-family: courier new;">admin</span></span>,
so that they can perform some sort of administrative function within
our application. The implementation of our authenticator would look
like this:<br />
<br />
<div>
<div>
<div><a href="http://odyssi.blogspot.com/2008/01/intro-to-jboss-seam-security-part-1.html#" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><a href="http://odyssi.blogspot.com/2008/01/intro-to-jboss-seam-security-part-1.html#" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a><a href="http://odyssi.blogspot.com/2008/01/intro-to-jboss-seam-security-part-1.html#" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div>
</div>
<ol start="1">
    <li>@Name("authenticator")&nbsp;&nbsp;</li>
    <li>public&nbsp;class&nbsp;Authenticator&nbsp;{&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>private&nbsp;static&nbsp;final&nbsp;String&nbsp;valid_user&nbsp;=&nbsp;"admin";&nbsp;&nbsp;</li>
    <li>private&nbsp;static&nbsp;final&nbsp;String&nbsp;valid_password&nbsp;=&nbsp;"password";&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>public&nbsp;boolean&nbsp;authenticate()&nbsp;{&nbsp;&nbsp;</li>
    <li>String&nbsp;username&nbsp;=&nbsp;Identity.instance().getUsername();&nbsp;&nbsp;</li>
    <li>String&nbsp;password&nbsp;=&nbsp;Identity.instance().getPassword();&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>if((username.equals(valid_user))&nbsp;&amp;&amp;&nbsp;(password.equals(valid_password)))&nbsp;{&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;true;&nbsp;&nbsp;</li>
    <li>}&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>return&nbsp;false;&nbsp;&nbsp;</li>
    <li>}&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>}&nbsp;&nbsp;</li>
</ol>
</div>
Our
example is rather trivial. However, it gives a slight glimpse into how
Seam authentication works. The first thing that you should notice is
the <span style="font-size: 85%;"><span style="font-family: courier new;">@Name</span></span>
annotation. This annotation prompts Seam to create a bean with the name
specified in the annotation. In this case, the name is <span style="font-size: 85%;"><span style="font-family: courier new;">authenticator</span></span>, which is how we arrive at the value specified in our <span style="font-size: 85%;"><span style="font-family: courier new;">components.xml</span></span> file.  Our <span style="font-size: 85%;"><span style="font-family: courier new;">authenticate </span></span>method will return <span style="font-size: 85%;"><span style="font-family: courier new;">true </span></span>if authentication was successful, and <span style="font-size: 85%;"><span style="font-family: courier new;">false </span></span>otherwise.<br />
<br />
So how does the authenticate method get the username and password?  This is done via the Identity class.  The standard <span style="font-size: 85%;"><a style="font-family: courier new;" href="http://docs.jboss.com/seam/2.0.1.CR1/api/org/jboss/seam/security/Identity.html">Identity</a></span>
class that comes with Seam is quite extensive, but basically provides
support for a username/password combination. It is possible to subclass
<span style="font-size: 85%;"><span style="font-family: courier new;">Identity</span></span>,
however, to support whatever authentication mechanisms you may need.
You could implement code to support getting a SecureID token value from
a user, or a SPNEGO ticket. All that is needed to make use of the <span style="font-size: 85%;"><span style="font-family: courier new;">Identity </span></span>subclass is to add the following annotations to your implementation:<br />
<br />
<div>
<div>
<div><a href="http://odyssi.blogspot.com/2008/01/intro-to-jboss-seam-security-part-1.html#" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><a href="http://odyssi.blogspot.com/2008/01/intro-to-jboss-seam-security-part-1.html#" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a><a href="http://odyssi.blogspot.com/2008/01/intro-to-jboss-seam-security-part-1.html#" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div>
</div>
<ol start="1">
    <li>@Name("org.jboss.seam.security.identity")&nbsp;&nbsp;</li>
    <li>@Scope(SESSION)&nbsp;&nbsp;</li>
    <li>@Install(precedence&nbsp;=&nbsp;APPLICATION)&nbsp;&nbsp;</li>
    <li>@BypassInterceptors&nbsp;&nbsp;</li>
    <li>@Startup&nbsp;&nbsp;</li>
    <li>public&nbsp;class&nbsp;MyCustomIdentity&nbsp;extends&nbsp;Identity&nbsp;&nbsp;</li>
    <li>{&nbsp;...&nbsp;}&nbsp;&nbsp;</li>
</ol>
</div>
<br />
Your custom <span style="font-size: 85%;"><span style="font-family: courier new;">Identity </span></span>subclass is now ready for use.<br />
<br />
Now
that we have our authentication classes in place, we are ready to
create our login form. This is trivial to create using Seam,
particularly because of Seam's use of the JBoss expression language in
forms. Our login form fragment would look like the following:<br />
<br />
<div>
<div>
<div><a href="http://odyssi.blogspot.com/2008/01/intro-to-jboss-seam-security-part-1.html#" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><a href="http://odyssi.blogspot.com/2008/01/intro-to-jboss-seam-security-part-1.html#" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a><a href="http://odyssi.blogspot.com/2008/01/intro-to-jboss-seam-security-part-1.html#" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div>
</div>
<ol start="1">
    <li>&lt;div&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&lt;h:outputlabel&nbsp;for="name"&nbsp;value="Username"&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&lt;h:inputtext&nbsp;id="name"&nbsp;value="#{identity.username}"&gt;&nbsp;&nbsp;</li>
    <li>&lt;/div&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>&lt;div&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&lt;h:outputlabel&nbsp;for="password"&nbsp;value="Password"&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&lt;h:inputsecret&nbsp;id="password"&nbsp;value="#{identity.password}"&gt;&nbsp;&nbsp;</li>
    <li>&lt;/div&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>&lt;div&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&lt;h:commandbutton&nbsp;value="Login"&nbsp;action="#{identity.login}"&gt;&nbsp;&nbsp;</li>
    <li>&lt;/div&gt;&nbsp;&nbsp;</li>
</ol>
</div>
<br />
<br />
That's
all there is to it. You are now ready to authenticate users via your
own custom login form and authenticator. While this is an introduction
to the simplified form of authentication in Seam, it should give you a
good foundation to learn and explore on your own.<br />
<br />
Next time, we will look at how authentication is used throughout an application, not just at the entry point.
</div>
<p post-footer-line-1=""><span>
Posted by
WhoAmI?
</span>
<span>
at
<a href="http://odyssi.blogspot.com/2008/01/intro-to-jboss-seam-security-part-1.html" title="permanent link">11:59 AM</a>
</span>
<span>
<span>
<a href="http://www.blogger.com/email-post.g?blogID=2823669911800907659&amp;postID=1475825363767554714" title="Email Post">
&nbsp;
</a>
</span>
<span blog-admin="" pid-277683962="">
<a href="http://www.blogger.com/post-edit.g?blogID=2823669911800907659&amp;postID=1475825363767554714" title="Edit Post">
<img alt="" class="icon-action" src="http://www.blogger.com/img/icon18_edit_allbkg.gif" height="18" width="18" />
</a>
</span>
</span>
</p>
<img src ="http://www.blogjava.net/sealyu/aggbug/267164.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-04-23 15:36 <a href="http://www.blogjava.net/sealyu/archive/2009/04/23/267164.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Seam中配置事务管理器（Configuring a Seam transaction manager）</title><link>http://www.blogjava.net/sealyu/archive/2009/04/20/266600.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Mon, 20 Apr 2009 12:10:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/04/20/266600.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/266600.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/04/20/266600.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/266600.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/266600.html</trackback:ping><description><![CDATA[原帖地址：http://www.redhat.com/docs/en-US/JBoss_Enterprise_Application_Platform/4.3.0.cp04_fp01/html/Seam_Reference_Guide/ch10s02s02.html<br />
<br />
<h3 id="d0e8114">Configuring a Seam transaction manager</h3>
<div>
Seam provides a transaction management abstraction for beginning,
committing, rolling back, and synchronizing with a transaction. By
default Seam uses a JTA transaction component that integrates with
Container Managed and programmatic EJB transactions. If you are working
in a Java EE 5 environment, you should install the EJB synchronization
component in <code>components.xml</code>:
</div>
<pre xml="">&lt;transaction:ejb-transaction /&gt;<br />
</pre>
<div> However, if you are working in a non EE 5
container, Seam will try auto detect the transaction synchronization
mechanism to use. However, if Seam is unable to detect the correct
transaction synchronization to use, you may find you need configure one
of the following: </div>
<div>
<ul>
    <li>
    <div>
    JPA RESOURCE_LOCAL transactions with the <code>javax.persistence.EntityTransaction</code> interface. <code>EntityTransaction</code> begins the transaction at the beginning of the apply request values phase.
    </div>
    </li>
    <li>
    <div>
    Hibernate managed transactions with the <code>org.hibernate.Transaction</code> interface. <code>HibernateTransaction</code> begins the transaction at the beginning of the apply request values phase.
    </div>
    </li>
    <li>
    <div>
    Spring managed transactions with the <code>org.springframework.transaction.PlatformTransactionManager</code> interface. The Spring <code>PlatformTransactionManagement</code> manager may begin the transaction at the beginning of the apply request values phase if the <code>userConversationContext</code> attribute is set.
    </div>
    </li>
    <li>
    <div>
    Explicitly disable Seam managed transactions
    </div>
    </li>
</ul>
</div>
<div>
Configure JPA RESOURCE_LOCAL transaction management by adding the following to your components.xml where <code>#{em}</code> is the name of the <code>persistence:managed-persistence-context</code> component. If your managed persistence context is named <code>entityManager</code>, you can opt to leave out the <code>entity-manager</code> attribute. (see <a href="http://www.redhat.com/docs/en-US/JBoss_Enterprise_Application_Platform/4.3.0.cp04_fp01/html/Seam_Reference_Guide/persistence.seam-managed-persistence-contexts.html" title="10.3.&nbsp;Seam-managed persistence contexts">Section&nbsp;10.3, &#8220;Seam-managed persistence contexts&#8221;</a>Seam-managed persistence contexts)
</div>
<pre xml="">&lt;transaction:entity-transaction entity-manager="#{em}"/&gt;<br />
</pre>
<div>
To configure Hibernate managed transactions declare the following in your components.xml where <code>#{hibernateSession}</code> is the name of the project's <code>persistence:managed-hibernate-session</code> component. If your managed hibernate session is named <code>session</code>, you can opt to leave out the <code>session</code> attribute. (see <a href="http://www.redhat.com/docs/en-US/JBoss_Enterprise_Application_Platform/4.3.0.cp04_fp01/html/Seam_Reference_Guide/persistence.seam-managed-persistence-contexts.html" title="10.3.&nbsp;Seam-managed persistence contexts">Section&nbsp;10.3, &#8220;Seam-managed persistence contexts&#8221;</a>Seam-managed persistence contexts)
</div>
<pre xml="">&lt;transaction:hibernate-transaction session="#{hibernateSession}"/&gt;<br />
</pre>
<div>
To explicitly disable Seam managed transactions declare the following in your components.xml:
</div>
<pre xml="">&lt;transaction:no-transaction /&gt;<br />
</pre>
<div>
For configuring Spring managed transactions see <a href="http://www.redhat.com/docs/en-US/JBoss_Enterprise_Application_Platform/4.3.0.cp04_fp01/html/Seam_Reference_Guide/spring-transactions.html" title="24.5.&nbsp;Using Spring PlatformTransactionManagement">Section&nbsp;24.5, &#8220;Using Spring PlatformTransactionManagement&#8221;</a>using Spring PlatformTransactionManagement. .
</div>
<br />
<img src ="http://www.blogjava.net/sealyu/aggbug/266600.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-04-20 20:10 <a href="http://www.blogjava.net/sealyu/archive/2009/04/20/266600.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JSF Validator(转)</title><link>http://www.blogjava.net/sealyu/archive/2009/04/14/265446.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Tue, 14 Apr 2009 02:58:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/04/14/265446.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/265446.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/04/14/265446.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/265446.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/265446.html</trackback:ping><description><![CDATA[<h2>JSF Validator入门基础篇 - JSF Validator的介绍与使用<br />
</h2>
<h2><span id="description">JSF框架提供Validator机制，对用户输入值的合法性进行验证。若用户输入值无效，还提供了错误消息显示功能，以帮助用户能正确输入。</span>
</h2>
<div id="fileContent">
在开始本文之前，建议阅读下面的文章：<br />
<a href="http://www.lifevv.com/tenyo/doc/20070520012424461.html" target="blank"><strong>深入了解JSF</strong></a><br />
<a href="http://www.lifevv.com/tenyo/doc/20070601163823151.html" target="blank"><strong>深入了解JSF（二）：从JSF的Lifecycle看JSF对页面的处理机制和流程</strong></a> <br />
以了解JSF的概念等。<br />
<br />
JSF Validator图：<br />
<img src="http://www.lifevv.com/ShowImage?fid=ff80808216e255d00116f28791620aa4"  alt="" /><br />
<br />
<div id="tf_edit_html_title" class="tf_edit_html_title">JSF Validator特点：</div>
<img src="http://www.lifevv.com/images/richedit/simages/edit_arrow7.gif" border="0"  alt="" /> 输入数据的验证放在服务器端进行。<br />
<img src="http://www.lifevv.com/images/richedit/simages/edit_arrow7.gif" border="0"  alt="" /> 需要验证输入值的组件（输入组件）在JSP里通过JSF标签加以设置，方法简单直观。<br />
<img src="http://www.lifevv.com/images/richedit/simages/edit_arrow7.gif" border="0"  alt="" /> 每个输入组件可以同时绑定多个Validator。<br />
<img src="http://www.lifevv.com/images/richedit/simages/edit_arrow7.gif" border="0"  alt="" /> 验证发生错误时，可以向FacesContext登录错误信息，并且可以通过JSP直接显示。显示风格与位置可以自由设定。<br />
<img src="http://www.lifevv.com/images/richedit/simages/edit_arrow7.gif" border="0"  alt="" /> 验证错误时，JSF的生命周期控制机制自动中止处理流程，跳转到画面描画阶段（Render Response Phase）。<br />
<img src="http://www.lifevv.com/images/richedit/simages/edit_arrow7.gif" border="0"  alt="" /> JSF标准提供对数值（long, double）的最大最小值验证，文字列的最大最小长度验证，以及必须(required)验证等Validator。<br />
<img src="http://www.lifevv.com/images/richedit/simages/edit_arrow7.gif" border="0"  alt="" /> 支持用户自定义Validator。用户自定义Validator的方法有2种，一种是Method Validator，一种是实现javax.faces.validator.Validator接口。本文的后面将对其作详细介绍。<br />
<br />
<br />
<div id="tf_edit_html_title" class="tf_edit_html_title">JSF标准Validator</div>
<h3>validateDoubleRange</h3>
<br />
Validator标签名：f:validateDoubleRange标签。<br />
&nbsp;&nbsp;属性名：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maximum="最大值"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;minimum="最小值" <br />
Validator ID：javax.faces.DoubleRange<br />
Validator 类：javax.faces.validator.DoubleRangeValidator<br />
输入值的范围验证。<br />
输入值必须为Number（数值）类型或者可以转换为Double类型的值<br />
<br />
<h3>validateLongRange</h3>
<br />
Validator标签名：f:validateLongRange<br />
&nbsp;&nbsp;属性名：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maximum="最大值"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;minimum="最小值" <br />
Validator ID：javax.faces.LongRange<br />
Validator 类：javax.faces.validator.LongRangeValidator<br />
输入值的范围验证。<br />
输入值必须为Number（数值）类型或者可以转换为Long类型的值<br />
<br />
<h3>validateLength</h3>
<br />
Validator标签名：f:validateLength<br />
&nbsp;&nbsp;属性名：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maximum="最大值"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;minimum="最小值" <br />
Validator ID：javax.faces.Length<br />
Validator 类：javax.faces.validator.LengthValidator<br />
输入值的长度验证。<br />
输入值必须为String（字符串）或者可以转换为String类型的值<br />
<br />
<br />
JSF required（必须输入） Validator<br />
JSF的几个输入组件还可以使用required属性简单地验证表单元素是否得到输入。<br />
&lt;h:inputHidden required="true/false"&gt;&lt;/h:inputHidden&gt;<br />
&lt;h:inputSecret required=&#8220;true/false&#8221;&gt;&lt;/h:inputSecret&gt;<br />
&lt;h:inputText required=&#8220;true/false&#8221;&gt;&lt;/h:inputText&gt;<br />
&lt;h:inputTextarea required=&#8220;true/false&#8221;&gt;&lt;/h:inputTextarea&gt;<br />
<br />
&lt;h:selectBooleanCheckbox required=&#8220;true/false&#8221;&gt;&lt;/h:selectBooleanCheckbox&gt;<br />
&lt;h:selectManyCheckbox required=&#8220;true/false&#8221;&gt;&lt;/h:selectManyCheckbox&gt;<br />
&lt;h:selectManyListbox required=&#8220;true/false&#8221;&gt;&lt;/h:selectManyListbox&gt;<br />
&lt;h:selectManyMenu required=&#8220;true/false&#8221;&gt;&lt;/h:selectManyMenu&gt;<br />
&lt;h:selectOneListbox required=&#8220;true/false&#8221;&gt;&lt;/h:selectOneListbox&gt;<br />
&lt;h:selectOneMenu required=&#8220;true/false&#8221;&gt;&lt;/h:selectOneMenu&gt;<br />
&lt;h:selectOneRadio required=&#8220;true/false&#8221;&gt;&lt;/h:selectOneRadio&gt;<br />
<br />
<div id="tf_edit_html_title" class="tf_edit_html_title">JSF Validator的使用</div>
各输入组件使用required validator的方法上面已经作了介绍，这里不再重复。<br />
<br />
<h3>使用Method Validator</h3>
<br />
JSF支持Method级别的Validator，这种Validator实现起来比较简单，可以在任何JSF的managed-bean里实现一个类似以下的方法：<br />
<div>
<link rel="stylesheet" href="http://www.lifevv.com/images/code/css/SyntaxHighlighter.css" type="text/css" />
<script language="javascript">
<!--//
function _syboos_pmplat_setUpCode() {
//dp.SyntaxHighlighter.ClipboardSwf = 'js/clipboard.swf';
dp.SyntaxHighlighter.HighlightAll('_syboos_pmplat_code');
}
window.onload=_syboos_pmplat_setUpCode;
//-->
</script>
<div>
<div>
<div><a href="http://www.lifevv.com/tenyo/doc/20071219221119846.html#" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><a href="http://www.lifevv.com/tenyo/doc/20071219221119846.html#" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a><a href="http://www.lifevv.com/tenyo/doc/20071219221119846.html#" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div>
</div>
<ol start="1">
    <li>public&nbsp;void&nbsp;validateXxxx(FacesContext&nbsp;context,&nbsp;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UIComponent&nbsp;component,&nbsp;Object&nbsp;value){&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;text&nbsp;=&nbsp;value.toString();&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;if(!text.equals("xxxx")){&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;ValidatorException(new&nbsp;FacesMessage("some&nbsp;message"));&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li>
    <li>}&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="_syboos_pmplat_code" class="java">public void validateXxxx(FacesContext context,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UIComponent component, Object value){
&nbsp;&nbsp;&nbsp;&nbsp;String text = value.toString();
&nbsp;&nbsp;&nbsp;&nbsp;if(!text.equals("xxxx")){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new ValidatorException(new FacesMessage("some message"));
&nbsp;&nbsp;&nbsp;&nbsp;}
}
</pre>
</div>
<br />
其中，context变量为JSF容器上下文环境，component为
绑定的组件，value为组件的输入值。validateXxxx可以为任意你喜欢的方法名。与预期的输入值不符合的话，可以通过throw一个
ValidatorException。"some message"便是想要显示的错误消息。<br />
<br />
然后在JSP中：<br />
<div>
<div>
<div>
<div><a href="http://www.lifevv.com/tenyo/doc/20071219221119846.html#" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><a href="http://www.lifevv.com/tenyo/doc/20071219221119846.html#" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a><a href="http://www.lifevv.com/tenyo/doc/20071219221119846.html#" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div>
</div>
<ol start="1">
    <li>&lt;h:inputText&nbsp;value="#{mybean.someValue}"&nbsp;validator="#{mybean.validateXxxx}"/&gt;&nbsp;&nbsp;</li>
</ol>
</div>
</div>
<br />
便可。<br />
错误消息的显示稍后再作介绍。<br />
<br />
<br />
<h3>Validator标签的使用</h3>
<br />
Validator标签可以接收参数，所以功能上比较强大，也比较灵活。同时，除了使用JSF标准的Validator标签之外，你还可以自定义Validator标签。关于自定义Validator标签我们将在另外的文章中加以介绍。<br />
Validator标签的使用例：<br />
<div>
<div>
<div>
<div><a href="http://www.lifevv.com/tenyo/doc/20071219221119846.html#" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><a href="http://www.lifevv.com/tenyo/doc/20071219221119846.html#" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a><a href="http://www.lifevv.com/tenyo/doc/20071219221119846.html#" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div>
</div>
<ol start="1">
    <li>&lt;h:inputText&nbsp;id="xxxxValue"&nbsp;value="#{mybean.xxxxValue}"&nbsp;required="true"&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&lt;f:validateDoubleRange&nbsp;maximum="5"&gt;&lt;/f:validateDoubleRange&gt;&nbsp;&nbsp;</li>
    <li>&lt;/h:inputText&gt;&nbsp;&nbsp;</li>
    <li>&lt;h:message&nbsp;for="xxxxValue"&gt;&lt;/h:message&gt;&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="_syboos_pmplat_code" class="java">&lt;h:inputText id="xxxxValue" value="#{mybean.xxxxValue}" required="true"&gt;
&lt;f:validateDoubleRange maximum="5"&gt;&lt;/f:validateDoubleRange&gt;
&lt;/h:inputText&gt;
&lt;h:message for="xxxxValue"&gt;&lt;/h:message&gt;</pre>
</div>
<br />
上
例对id为xxxxValue的输入框组件的输入值做double范围验证，指定范围最大值为5。超过5的情况则显示错误消息，错误消息可以使
用&lt;h:message /&gt;或者&lt;h:messages /&gt;标签显示。有关消息处理的详细介绍请参考：<br />
<a href="http://www.lifevv.com/tenyo/doc/20070530163255229.html" target="blank"><strong>JSF全面理解之消息处理</strong></a> <br />
一文<br />
<br />
<h3>f:validator标签的使用与Validator ID</h3>
<br />
除了以上2种验证方法之外，还可以使用f:validator标签对输入值加以验证。f:validator标签需要指定validatorId属性，Validator Id需要在faces-config.xml配置文件中加以配置。<br />
<br />
<br />
f:validator标签的使用例：<br />
<div>
<div>
<div>
<div><a href="http://www.lifevv.com/tenyo/doc/20071219221119846.html#" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><a href="http://www.lifevv.com/tenyo/doc/20071219221119846.html#" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a><a href="http://www.lifevv.com/tenyo/doc/20071219221119846.html#" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div>
</div>
<ol start="1">
    <li>&lt;h:inputText&nbsp;id="xxxxValue"&nbsp;value="#{mybean.xxxxValue}"&nbsp;required="true"&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&lt;f:validator&nbsp;validatorId="Some&nbsp;Validator&nbsp;ID"&gt;&lt;/f:validator&gt;&nbsp;&nbsp;</li>
    <li>&lt;/h:inputText&gt;&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="_syboos_pmplat_code" class="java">&lt;h:inputText id="xxxxValue" value="#{mybean.xxxxValue}" required="true"&gt;
&nbsp;&nbsp;&lt;f:validator validatorId="Some Validator ID"&gt;&lt;/f:validator&gt;
&lt;/h:inputText&gt;</pre>
</div>
<br />
"Some Validator ID"为具体的Validator ID，我们将在自定义Validator标签一文中对Validator ID做详细介绍。<br />
<br />
JSF框架将调用指定Validator ID所对应的Validator的<br />
public void validate(FacesContext context, UIComponent component, Object value)<br />
方法。<br />
<br />
跟Method Validator一样，不能f:validator标签传入参数。<br />
<br />
本文介绍了JSF Validator的机制，特点，种类，以及使用方法等。我们将在近期其它文章中介绍怎么自定义Validator。<br />
<h1><span id="name">JSF Validator进阶篇 - 自定义JSF Validator</span></h1>
<br />
<h2><span id="description">JSF框架提供Validator机制，对用户输入值的合法性进行验证。若用户输入值无效，还提供了错误消息显示功能，以帮助用户能正确输入。</span>
</h2>
<div id="fileContent">
<br />
在 <a href="http://www.lifevv.com/tenyo/doc/20071219221119846.html" target="blank">JSF Validator入门基础篇 - JSF Validator的介绍与使用</a>&nbsp;&nbsp;一文中我们介绍了JSF Validator的机制，特点，种类，以及使用方法等。<br />
<br />
本文将介绍怎么自定义Validator和Validator标签。<br />
<br />
自定义Validator有2种方法：一种是Method Validator，我们在<a href="http://www.lifevv.com/tenyo/doc/20071219221119846.html" target="blank">JSF Validator入门基础篇 - JSF Validator的介绍与使用</a>&nbsp;&nbsp;一文中已作了介绍，这里不再详述；另一种是通过实现Validator接口，也就是使用自定义的Validator类。<br />
<br />
自定义Validator类与Validator标签有以下几个步骤：<br />
<img src="http://www.lifevv.com/images/richedit/simages/edit_arrow7.gif" border="0"  alt="" />自定义Validator类的实现<br />
<img src="http://www.lifevv.com/images/richedit/simages/edit_arrow7.gif" border="0"  alt="" />faces-config.xml登录<br />
<img src="http://www.lifevv.com/images/richedit/simages/edit_arrow7.gif" border="0"  alt="" />自定义Validator标签类<br />
<img src="http://www.lifevv.com/images/richedit/simages/edit_arrow7.gif" border="0"  alt="" />设置TLD文件<br />
<br />
<br />
<div id="tf_edit_html_title" class="tf_edit_html_title">自定义Validator类的实现</div>
定义一个类，该类实现javax.faces.validator.Validaotr接口：<br />
<br />
<img src="http://www.lifevv.com/images/richedit/simages/edit_list3.gif" border="0"  alt="" />MyValidator.java<br />
<div>
<link rel="stylesheet" href="http://www.lifevv.com/images/code/css/SyntaxHighlighter.css" type="text/css" />
<script language="javascript">
<!--//
function _syboos_pmplat_setUpCode() {
//dp.SyntaxHighlighter.ClipboardSwf = 'js/clipboard.swf';
dp.SyntaxHighlighter.HighlightAll('_syboos_pmplat_code');
}
window.onload=_syboos_pmplat_setUpCode;
//-->
</script>
<div>
<div>
<div><a href="http://www.lifevv.com/tenyo/doc/20071220193759871.html#" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><a href="http://www.lifevv.com/tenyo/doc/20071220193759871.html#" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a><a href="http://www.lifevv.com/tenyo/doc/20071220193759871.html#" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div>
</div>
<ol start="1">
    <li>package&nbsp;com.mypackages;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>import&nbsp;javax.faces.validator.Validaotr;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>public&nbsp;class&nbsp;MyValidator&nbsp;implements&nbsp;Validator&nbsp;{&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;validate(FacesContext&nbsp;context,&nbsp;UIComponent&nbsp;component,&nbsp;Object&nbsp;value)&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws&nbsp;ValidatorException&nbsp;{&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;text&nbsp;=&nbsp;value.toString();&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!text.equals("xxxx")){&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;ValidatorException(new&nbsp;FacesMessage("some&nbsp;message"));&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;...&nbsp;//其它参数设置，方法等（略）&nbsp;&nbsp;</li>
    <li>}&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="_syboos_pmplat_code" class="java">package com.mypackages;
import javax.faces.validator.Validaotr;
public class MyValidator implements Validator {
&nbsp;&nbsp;&nbsp;&nbsp;public void validate(FacesContext context, UIComponent component, Object value)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws ValidatorException {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String text = value.toString();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!text.equals("xxxx")){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new ValidatorException(new FacesMessage("some message"));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;... //其它参数设置，方法等（略）
}
</pre>
</div>
<br />
<br />
<div id="tf_edit_html_title" class="tf_edit_html_title">faces-config.xml登录</div>
自定义Validator类之后，还得向faces-config.xml登录之后才能使用。<br />
<img src="http://www.lifevv.com/images/richedit/simages/edit_list3.gif" border="0"  alt="" />faces-config.xml<br />
<div>
<div>
<div>
<div><a href="http://www.lifevv.com/tenyo/doc/20071220193759871.html#" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><a href="http://www.lifevv.com/tenyo/doc/20071220193759871.html#" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a><a href="http://www.lifevv.com/tenyo/doc/20071220193759871.html#" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div>
</div>
<ol start="1">
    <li>&lt;?xml&nbsp;version="1.0"?&gt;&nbsp;&nbsp;</li>
    <li>&lt;!DOCTYPE&nbsp;faces-config&nbsp;PUBLIC&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;"-//Sun&nbsp;Microsystems,&nbsp;Inc.//DTD&nbsp;JavaServer&nbsp;Faces&nbsp;Config&nbsp;1.0//EN"&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;"http://java.sun.com/dtd/web-facesconfig_1_0.dtd"&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>&lt;faces-config&nbsp;xmlns="http://java.sun.com/JSF/Configuration"&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&lt;validator&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;validator-id&gt;MyValidator&lt;/validator-id&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;validator-class&gt;com.mypackages.MyValidator&lt;/validator-class&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/validator&gt;&nbsp;&nbsp;</li>
    <li>&lt;/faces-config&gt;&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="_syboos_pmplat_code" class="java">&lt;?xml version="1.0"?&gt;
&lt;!DOCTYPE faces-config PUBLIC
&nbsp;&nbsp;"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN"
&nbsp;&nbsp;"http://java.sun.com/dtd/web-facesconfig_1_0.dtd"&gt;
&lt;faces-config xmlns="http://java.sun.com/JSF/Configuration"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;validator&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;validator-id&gt;MyValidator&lt;/validator-id&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;validator-class&gt;com.mypackages.MyValidator&lt;/validator-class&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/validator&gt;
&lt;/faces-config&gt;
</pre>
</div>
<br />
<br />
经过上面2个步骤，就可以使用MyValidator了。<br />
例：<br />
&lt;h:inputText id="xxxxValue" value="#{mybean.xxxxValue}"&gt;<br />
&nbsp;&nbsp;&lt;f:validator validatorId="MyValidator"&gt;&lt;/f:validator&gt;<br />
&lt;/h:inputText&gt;<br />
<br />
<div id="tf_edit_html_title" class="tf_edit_html_title">自定义Validator标签类</div>
上面的MyValidator虽然可以通过f:validator标签加以利用， 但不能向其传入参数，若要向其传入参数，则需要定义自定义Validator标签类。<br />
<img src="http://www.lifevv.com/images/richedit/simages/edit_list3.gif" border="0"  alt="" />MyValidatorTag.java<br />
<div>
<div>
<div>
<div><a href="http://www.lifevv.com/tenyo/doc/20071220193759871.html#" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><a href="http://www.lifevv.com/tenyo/doc/20071220193759871.html#" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a><a href="http://www.lifevv.com/tenyo/doc/20071220193759871.html#" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div>
</div>
<ol start="1">
    <li>package&nbsp;com.mypackages;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>import&nbsp;javax.faces.webapp.ValidatorTag;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>public&nbsp;class&nbsp;MyValidatorTag&nbsp;extends&nbsp;ValidatorTag{&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;String&nbsp;xxxParam;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;MyValidatorTag(){&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setValidatorId("MyValidator");&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;Validator&nbsp;createValidator()&nbsp;throws&nbsp;JspException&nbsp;{&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MyValidator&nbsp;validator&nbsp;=&nbsp;&nbsp;(MyValidator)super.createValidator();&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;validator.setXxxParam(xxxParam);&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;validator;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;String&nbsp;getXxxParam()&nbsp;{&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;xxxParam;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;setXxxParam(String&nbsp;xxxParam)&nbsp;{&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.xxxParam&nbsp;=&nbsp;xxxParam;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li>
    <li>}&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="_syboos_pmplat_code" class="java">package com.mypackages;
import javax.faces.webapp.ValidatorTag;
public class MyValidatorTag extends ValidatorTag{
&nbsp;&nbsp;&nbsp;&nbsp;private String xxxParam;
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;public MyValidatorTag(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setValidatorId("MyValidator");
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;protected Validator createValidator() throws JspException {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MyValidator validator =&nbsp;&nbsp;(MyValidator)super.createValidator();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;validator.setXxxParam(xxxParam);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return validator;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;public String getXxxParam() {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return xxxParam;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;public void setXxxParam(String xxxParam) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.xxxParam = xxxParam;
&nbsp;&nbsp;&nbsp;&nbsp;}
}
</pre>
</div>
<br />
另外，为MyValidator.java加入相应参数及方法实现。<br />
<br />
<div id="tf_edit_html_title" class="tf_edit_html_title">TLD文件</div>
定义好Validator标签类之后，还需要在TLD文件设置，有关TLD这里就不介绍了。请大家参考相关资料。<br />
<br />
<img src="http://www.lifevv.com/images/richedit/simages/edit_list3.gif" border="0"  alt="" />MyValidator.tld<br />
<div>
<div>
<div>
<div><a href="http://www.lifevv.com/tenyo/doc/20071220193759871.html#" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><a href="http://www.lifevv.com/tenyo/doc/20071220193759871.html#" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a><a href="http://www.lifevv.com/tenyo/doc/20071220193759871.html#" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div>
</div>
<ol start="1">
    <li>&lt;?xml&nbsp;version="1.0"&nbsp;encoding="ISO-8859-1"&nbsp;?&gt;&nbsp;&nbsp;</li>
    <li>&lt;!DOCTYPE&nbsp;taglib&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;PUBLIC&nbsp;"-//Sun&nbsp;Microsystems,&nbsp;Inc.//DTD&nbsp;JSP&nbsp;Tag&nbsp;Library&nbsp;1.2//EN"&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd"&gt;&nbsp;&nbsp;</li>
    <li>&lt;taglib&nbsp;xmlns="http://java.sun.com/JSP/TagLibraryDescriptor"&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&lt;tlib-version&gt;1.0&lt;/tlib-version&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&lt;jsp-version&gt;1.2&lt;/jsp-version&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&lt;short-name&gt;myv&lt;/short-name&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&lt;uri&gt;my&nbsp;validator&nbsp;tag&lt;/uri&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&lt;display-name&gt;my&nbsp;validator&nbsp;tag&lt;/display-name&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&lt;tag&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;validateMyData&lt;/name&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;tag-class&gt;com.mypackages.MyValidatorTag&lt;/tag-class&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;attribute&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;xxxParam&lt;/name&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;required&gt;false&lt;/required&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/attribute&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/tag&gt;&nbsp;&nbsp;</li>
    <li>&lt;/taglib&gt;&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="_syboos_pmplat_code" class="java">&lt;?xml version="1.0" encoding="ISO-8859-1" ?&gt;
&lt;!DOCTYPE taglib
&nbsp;&nbsp;PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
&nbsp;&nbsp;"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd"&gt;
&lt;taglib xmlns="http://java.sun.com/JSP/TagLibraryDescriptor"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;tlib-version&gt;1.0&lt;/tlib-version&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;jsp-version&gt;1.2&lt;/jsp-version&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;short-name&gt;myv&lt;/short-name&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;uri&gt;my validator tag&lt;/uri&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;display-name&gt;my validator tag&lt;/display-name&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;tag&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;validateMyData&lt;/name&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;tag-class&gt;com.mypackages.MyValidatorTag&lt;/tag-class&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;attribute&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;xxxParam&lt;/name&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;required&gt;false&lt;/required&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/attribute&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/tag&gt;
&lt;/taglib&gt;
</pre>
</div>
<br />
<br />
<div id="tf_edit_html_title" class="tf_edit_html_title">自定义Validator标签的使用</div>
<img src="http://www.lifevv.com/images/richedit/simages/edit_list3.gif" border="0"  alt="" />web.xml<br />
<div>
<div>
<div>
<div><a href="http://www.lifevv.com/tenyo/doc/20071220193759871.html#" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><a href="http://www.lifevv.com/tenyo/doc/20071220193759871.html#" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a><a href="http://www.lifevv.com/tenyo/doc/20071220193759871.html#" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div>
</div>
<ol start="1">
    <li>&nbsp;&lt;taglib&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&lt;taglib-uri&gt;/WEB-INF/MyValidator.tld&lt;/taglib-uri&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&lt;taglib-location&gt;/WEB-INF/MyValidator.tld&lt;/taglib-location&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&lt;/taglib&gt;&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="_syboos_pmplat_code" class="java"> &lt;taglib&gt;
&nbsp;&nbsp;&lt;taglib-uri&gt;/WEB-INF/MyValidator.tld&lt;/taglib-uri&gt;
&nbsp;&nbsp;&lt;taglib-location&gt;/WEB-INF/MyValidator.tld&lt;/taglib-location&gt;
&lt;/taglib&gt;</pre>
</div>
<br />
<br />
<br />
JSP<br />
<div>
<div>
<div>
<div><a href="http://www.lifevv.com/tenyo/doc/20071220193759871.html#" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><a href="http://www.lifevv.com/tenyo/doc/20071220193759871.html#" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a><a href="http://www.lifevv.com/tenyo/doc/20071220193759871.html#" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div>
</div>
<ol start="1">
    <li>&lt;%@&nbsp;taglib&nbsp;uri="WEB-INF/MyValidator.tld"&nbsp;prefix="myv"&nbsp;%&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>...&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>&lt;h:inputText&nbsp;value="#{mybean.xxxxValue}"&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&lt;myv:validateMyData&nbsp;xxxParam="Some&nbsp;Parameter"/&gt;&nbsp;&nbsp;</li>
    <li>&lt;/h:inputText&gt;&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="_syboos_pmplat_code" class="java">&lt;%@ taglib uri="WEB-INF/MyValidator.tld" prefix="myv" %&gt;
...
&lt;h:inputText value="#{mybean.xxxxValue}"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;myv:validateMyData xxxParam="Some Parameter"/&gt;
&lt;/h:inputText&gt;</pre>
</div>
</div>
<br />
</div>
<img src ="http://www.blogjava.net/sealyu/aggbug/265446.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-04-14 10:58 <a href="http://www.blogjava.net/sealyu/archive/2009/04/14/265446.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EntityManager:seam新手必读（转）</title><link>http://www.blogjava.net/sealyu/archive/2009/04/13/265298.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Mon, 13 Apr 2009 07:34:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/04/13/265298.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/265298.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/04/13/265298.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/265298.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/265298.html</trackback:ping><description><![CDATA[ 原帖地址：http://blog.csdn.net/bq_cui/archive/2007/03/21/1536706.aspx<br />
<br />
开始学习seam的时候，有两个问题：我会用Spring和Hibernate，但一点也不懂Seam 和EJB3的 EntityManager。我用了一些时间学习seam，但EntityManager 一直困扰我。<span><br />
&nbsp;&nbsp;&nbsp; 同时我也有了一些小收获，愿意跟刚刚开始学习seam的朋友分享以下。别紧张，我不敢确信我写的东西都正确 ;). <br />
&nbsp;&nbsp;&nbsp;
好了，关于EntityManager有何用处？它管理你的entities ;)。 那是一些简单的java对象，通过getters and
setters具备一些属性。这些属性之一是id（一般是Long数据类型），并且这些class必须以@Entity注解(annotated
)。在seam的源码中可以找到一大批这样的例子，例如booking例子。在seam中，一件很重要的事情就是，每个Entity都有一个
@Name 注解(annotation)，这样，它们才能被注入到其他seam部件(component)中。<br />
</span>&nbsp;&nbsp;&nbsp; 假设我们有这样一个entity class，叫做"Entity"。其生命周期内包含以下功能：
<p dir="ltr" style="margin-right: 0px;">增</p>
<p dir="ltr" style="margin-right: 0px;">查</p>
<p dir="ltr" style="margin-right: 0px;">删</p>
<p dir="ltr" style="margin-right: 0px;">改</p>
<p dir="ltr" style="margin-right: 0px;">EntityManager 提供了这些功能。首先，如何把EntityManager 引入我的代码？很简单：</p>
<span>
<div style="border: 0.5pt solid windowtext; padding: 4px 5.4pt; background: #e6e6e6 none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 95%;">
<div><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /><span style="color: #000000;">@PersistenceContext<br />
<img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /></span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;EntityManager&nbsp;em;&nbsp;&nbsp;&nbsp;&nbsp;</span></div>
</div>
<p dir="ltr" style="margin-right: 0px;">&nbsp;&nbsp;&nbsp; 好了，我们看看一个Entity 进程如何产生：</p>
<div style="border: 0.5pt solid windowtext; padding: 4px 5.4pt; background: #e6e6e6 none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 95%;">
<div><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /><span style="color: #000000;">Entity&nbsp;entity&nbsp;</span><span style="color: #000000;">=</span>&nbsp;<span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Entity();&nbsp;&nbsp;&nbsp;&nbsp;</span></div>
</div>
<p dir="ltr" style="margin-right: 0px;">&nbsp;&nbsp;&nbsp; 这很简单。现在，这entity 的状态是<span style="font-weight: bold;">NEW/TRANSIENT 。这意味着一个entity已经存在于你的应用程序中，但并不具有id，也不存在于你的数据库中。<br />
<br />
&nbsp;&nbsp;&nbsp; 由于我们要使它持久化（即它应被写入数据库），我们应把它的状态转换为<span style="font-weight: bold;">MANAGED</span> 。</span></p>
<div style="border: 0.5pt solid windowtext; padding: 4px 5.4pt; background: #e6e6e6 none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 95%;">
<div><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /><span style="color: #000000;">em.persist(entity);&nbsp;&nbsp;&nbsp;&nbsp;</span></div>
</div>
<p>&nbsp;&nbsp;&nbsp; 现在，此entity由EntityManager管理了。EntityManager控制entity写入数据库。这动作无须立刻发生，可能把你的entity放在cache，稍后写入数据库。你可以放心，写动作肯定会发生。<br />
<br />
Ok, what about reading an existing entity from the database? Therefore we use: </p>
<p>好，如何从数据库中读出已存在的entity呢？这样：</p>
<div style="border: 0.5pt solid windowtext; padding: 4px 5.4pt; background: #e6e6e6 none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 95%;">
<div><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /><span style="color: #000000;">Entity&nbsp;entity&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;em.find(Entity.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">,&nbsp;Id);&nbsp;&nbsp;&nbsp;&nbsp;</span></div>
</div>
<p>&nbsp;&nbsp;&nbsp; 每个entity 有一个id（我已经说过，多数情况下是Long数据类型），通过id你可存取entity。这是这里的第二个参数。第一个参数代表你要存取的Entity class的进程。find操作之后，entity的状态也是<span style="font-weight: bold;">MANAGED 。</span></p>
<p>一旦entity数据有所改变，将反映到数据库中。不能确认EntityManager何时会向数据库写入更新的数据。但是这一事件肯定会发生，一般是马上，但不会晚于EntityManager消失<span>;)。你可以控制触发更新数据库：<br />
<br />
<div style="border: 0.5pt solid windowtext; padding: 4px 5.4pt; background: #e6e6e6 none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 95%;">
<div><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /><span style="color: #000000;">em.flush();&nbsp;&nbsp;&nbsp;&nbsp;</span></div>
</div>
<br />
</span>&nbsp;&nbsp;&nbsp;&nbsp; 这将强制EntityManager 立刻将更新写入数据库。请记住，这条语句将影响所有状态为<span style="font-weight: bold;">MANAGED的</span>entitie，而不是当前一个。不过，一般情况下不必这么做。<br />
&nbsp;&nbsp;&nbsp; 如果你想反其道而行之，也就是从数据库载入一个<span>entity （因为别人可能已经修改其数据），这么写：<br />
<div style="border: 0.5pt solid windowtext; padding: 4px 5.4pt; background: #e6e6e6 none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 95%;">
<div><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /><span style="color: #000000;">em.refresh(entity);&nbsp;&nbsp;&nbsp;&nbsp;</span></div>
</div>
<br />
</span><span>&nbsp;&nbsp;&nbsp; 怎样删除一个entity呢？很简单：<br />
<div style="border: 0.5pt solid windowtext; padding: 4px 5.4pt; background: #e6e6e6 none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 95%;">
<div><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /><span style="color: #000000;">em.remove(entity);&nbsp;&nbsp;&nbsp;&nbsp;</span></div>
</div>
<br />
</span>&nbsp;&nbsp;&nbsp; 现在，entity的状态成为<span style="font-weight: bold;">REMOVED，表示其已经被列入删除计划。你可以用</span>flush()语句，让删除动作马上发生，但没必要这么干。<br />
<br />
&nbsp;&nbsp;&nbsp; 现在来点复杂的。当注入EntityManager 的时候，有一个<span style="font-weight: bold;">事务范围持久上下文（</span><span style="font-weight: bold;"> Transaction Scoped Persistence Context</span>）。当entitie处在MANAGED状态时，其处在持久上下文（persistence context ）的&#8220;容器&#8221;中。&#8220;事务范围&#8221;意味什么？首先，什么是&#8220;事务&#8221;？<br />
<br />
&nbsp;&nbsp;&nbsp; EJB3Stateful 和 Stateless beans (依同名标注辨别)的每个方法调用都包装到一个事务内。（顺便说一下，事务一旦发生RuntimeException，即发生会滚，对数据的改变将撤销）。因此，持久上下文（persistence context）将在调用方式之前建立，方式调用结束后移除。然后，持久上下文中管理的所有entity的状态成为<span style="font-weight: bold;"> DETACHED。</span><br />
<br />
&nbsp;&nbsp;&nbsp; 假设在你的bean里头有两个method。第一个是load(), 它调用find函数取出数据库中的一个实体。第二个是finish()，返回一个JSF输出。调用这两个函数中间修改了实体数据。这种修改持久到数据库中吗？回答是：NO。<br />
<br />
&nbsp;&nbsp;&nbsp; load() 函数结束后，EntityManager'的持久上下文结束，它所有管理过的entity状态成为DETACHED。一个后果是，与新entity相反-有一个ID，但他们的状态并不是managed ，对这些detached entities 所作的更新并不影响数据库。如果你想使一个entity 更新数据库，需要将其重新attach到持久上下文。在这个例子中，在<span>finish()方法中增加以下行：<br />
<div style="border: 0.5pt solid windowtext; padding: 4px 5.4pt; background: #e6e6e6 none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 95%;">
<div><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /><span style="color: #000000;">em.merge(entity);&nbsp;&nbsp;&nbsp;&nbsp;</span></div>
</div>
</span><br />
&nbsp;&nbsp;&nbsp; 现在这个entity 已经合并到finish()方法的持久上下文中(记住，每个方法是一个事务，每个事物有自己的持久上下文)，并且状态是又变为managed。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; 这样做是可以的，但有两个缺点：<br />
-需要调用merge(-&gt;多了一些代码)<br />
-调用find()之前，如果某个entity未初始化，而你又要存取它的某些属性，将会得到exception 错误。<br />
<br />
&nbsp;&nbsp;&nbsp; 有一个简单的解决方案：扩展持久上下文的生命期，这样，当调用多个事务/方法时，entity状态始终保持为managed 。因此，我们改变EntityManager的注入方式：<br />
<span>
<div style="border: 0.5pt solid windowtext; padding: 4px 5.4pt; background: #e6e6e6 none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 95%;">
<div><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /><span style="color: #000000;">@PersistenceContext(type</span><span style="color: #000000;">=</span><span style="color: #000000;">PersistenceContextType.EXTENDED<br />
<img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /></span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;EntityManager&nbsp;em;&nbsp;&nbsp;&nbsp; </span></div>
</div>
</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; 现在，managed entities "生活在"一个扩展持久上下文中( <span style="font-weight: bold;">Extended Persistence Context </span>)。<br />
<br />
&nbsp;&nbsp;&nbsp; 你甚至无须呼叫merge()方法，因为eitities从未被DETACHED。你可能会问：普通事务范围（ "normal" (transaction scoped) ）持久上下文的好处是什么？它一直依附于你做的事情（小崔：什么意思？）。扩展上下文需要更多的内存，因为即使你不需要，它也一直存在于内存。并且一旦entities被其他的bean改变（它们有自己的持久上下文），你需要显式地调用refresh()方法（在overviews/list页面）。当你需要普通EntityManager 时它就在那里，因其生命周期短，只能操作即时数据;) <br />
<span>&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 当谈及列表：为取得不止一个实体，而是一个实体集合，使用：<br />
<div style="border: 0.5pt solid windowtext; padding: 4px 5.4pt; background: #e6e6e6 none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 95%;">
<div><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /><span style="color: #000000;">List</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Entity</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;entities&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;em.createQuery(</span><span style="color: #000000;">"</span><span style="color: #000000;">from&nbsp;Entity</span><span style="color: #000000;">"</span><span style="color: #000000;">).getResultList();&nbsp;&nbsp;&nbsp;&nbsp;</span></div>
</div>
</span><br />
&nbsp;&nbsp;&nbsp; 这不是&#8220;真正&#8221;SQL，而是类似sql的东西，称之为<span>EJBQL。你可以用它执行某些条件查询，排序等，如<br />
<div style="border: 0.5pt solid windowtext; padding: 4px 5.4pt; background: #e6e6e6 none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 95%;">
<div><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /><span style="color: #000000;">...</span><span style="color: #000000;">"</span><span style="color: #000000;">from&nbsp;Entity&nbsp;where&nbsp;lastName=</span><span style="color: #000000;">"</span><span style="color: #000000;">.nameToSearchFor.</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;order&nbsp;by&nbsp;firstName</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span></div>
</div>
<br />
</span>&nbsp;&nbsp;&nbsp; 仅使用entity属性名称即可。关于EJBQL 要说的太多了，但对于本篇介绍来说这已足够。<br />
<br />
&nbsp;&nbsp;&nbsp; 好，基本介绍到此为止。希望对你来说，在如何使用EntityManager方面，这一个简单易懂的介绍。<br />
<br />
&nbsp;&nbsp;&nbsp; 我已声明过，不能保证百分百正确。并且肯定有许多英语语法错误(对不起，我是德国人，不要打我PP噢)。欢迎斧正。<br />
<br />
<br />
2007.4.11翻译自：<br />
http://www.jboss.com/index.html?module=bb&amp;op=viewtopic&amp;t=88460</p>
</span>
<img src ="http://www.blogjava.net/sealyu/aggbug/265298.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-04-13 15:34 <a href="http://www.blogjava.net/sealyu/archive/2009/04/13/265298.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SEAM中JSTL标签和ui标签的混合使用(c:forEach vs ui:repeat)</title><link>http://www.blogjava.net/sealyu/archive/2009/04/13/265212.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Mon, 13 Apr 2009 00:52:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/04/13/265212.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/265212.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/04/13/265212.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/265212.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/265212.html</trackback:ping><description><![CDATA[<h1>c:forEach vs ui:repeat in Facelets</h1>
<p>Posted by Roger Keays, 7 June 2007, 12:28 PM
</p>
<p>This is probably one of the most frequently asked questions on the Facelets mailing list. Why doesn't my <font face="Courier New">c:forEach</font>
tag work correctly? Unfortunately, there are may ways to misuse the
jstl tags available in Facelets, so the answer isn't always simple.
Here is an explanation of the differences between <font face="Courier New">c:forEach</font> and <font face="Courier New">ui:repeat</font>, along with some examples which will hopefully save you some headaches.</p>
<h4>TagHandlers vs Components</h4>
<p>The most important thing to understand about the jstl tags in Facelets is that they <em>do not represent components</em>
and never become a part of the component tree once the view has been
built. Rather, they are tags which are actually responsible for <em>building the tree</em> in the first place. Once they have done their job they expire, are no more, cease to be, etc etc.</p>
<p>Here is a table of the semantics of several common tags. I just
discovered, reading the Facelets code, that validators and converters
are classified separately. I had always thought they were just tag
handlers, but I imagine they behave in much the same way.</p>
<table align="center" border="1" cellpadding="2" cellspacing="0">
    <tbody>
        <tr>
            <td style="background-color: #800000;"><font color="#ffffff"><strong>TagHandlers<br />
            </strong></font></td>
            <td style="background-color: #800000;"><font color="#ffffff"><strong>Components<br />
            </strong></font></td>
            <td style="background-color: #800000;" valign="top"><font color="#ffffff"><strong>Other<br />
            </strong></font></td>
        </tr>
        <tr>
            <td>
            <p>c:forEach<br />
            c:choose<br />
            c:set<br />
            c:if<br />
            f:facet<br />
            f:actionListener<br />
            f:valueChangeListener<br />
            ui:include<br />
            ui:decorate<br />
            ui:composition<br />
            any custom tag file</p>
            </td>
            <td>
            <p>ui:repeat<br />
            ui:fragment<br />
            ui:component<br />
            f:view<br />
            f:verbatim<br />
            f:selectItems<br />
            h:inputText<br />
            h:datatable<br />
            any custom UIComponent</p>
            </td>
            <td valign="top">f:validator<br />
            f:converter</td>
        </tr>
    </tbody>
</table>
<p>One of the problems here is that there is no naming convention to
indicate which tags correspond to which constructs. You've just got to
know, or find out.</p>
<h4>When is the view built?</h4>
<p>Now that you understand that tag handlers are only effective when
the tree is built, the next logical question should be well, when is
tree built?</p>
<p>The short answer is that a new view is built for every request which
is not a postback. During a postback, the view is reconstructed from
saved state. Quite confusing, and not very obvious I know, but there
you have it.</p>
<h4>Common laments</h4>
<p>The most common pitfalls are either with the JSF lifecycle, EL evaluation or combining tag handlers with components.</p>
<p><strong>My <font face="Courier New">c:if</font> always evaluates to false</strong></p>
<pre>&lt;h:dataTable values="${numbers}" var="number"&gt;<br />
&lt;h:column&gt;<br />
&lt;c:if test="${number &gt; 5}"&gt;<br />
&lt;h:outputText value="${number}"/&gt;<br />
&lt;/c:if&gt;<br />
&lt;/h:column&gt;<br />
&lt;/h:datatable&gt;</pre>
<p>Yes, the <font face="Courier New">c:if</font> is always evaluating to false! But it is only ever evaluated once - when the tree is built. The <font face="Courier New">h:outputText</font> component never makes it into the tree. Solution: replace the <font face="Courier New">c:if</font> with:</p>
<pre>&lt;ui:fragment rendered="${number &gt; 5}"&gt; ... &lt;/ui:fragment&gt;</pre>
<p>You could also use the rendered attribute on the <font face="Courier New">h:outputText</font> component in this example.</p>
<p><strong>My <font face="Courier New">ui:include</font> fails inside <font face="Courier New">ui:repeat</font></strong></p>
<pre>&lt;ui:repeat value="#{bean.items}" var="item"&gt;<br />
&nbsp;&nbsp; &lt;ui:include src="#{item.src}"/&gt;<br />
&lt;/ui:repeat&gt;</pre>
<p>The EL for the <font face="Courier New">ui:include</font> is evaluated when the view is <em>built</em> and is invalid since it relies on a variable only made available by the <font face="Courier New">ui:repeat</font> during <em>rendering</em>. Use <font face="Courier New">c:forEach</font> in this case.</p>
<p><strong>My recursive tag never stops</strong></p>
<pre>myTag.xhtml:</pre>
<pre>&lt;ul&gt;<br />
&lt;ui:repeat value="${item.children} var="child"&gt;<br />
&lt;li&gt;&lt;eg:myTag item="${child}"/&gt;&lt;/li&gt;<br />
&lt;/ui:repeat&gt;<br />
&lt;/ul&gt;</pre>
<p>The stop condition in this recursion is supposed to be when you run out of children. The problem is that the custom <font face="Courier New">eg:myTag</font> is just a tag handler, like a special version of <font face="Courier New">ui:include</font>. When the view is built, the <font face="Courier New">ui:repeat</font> has no influence on the building process and can't stop the recursion. Use <font face="Courier New">c:forEach</font> here instead of <font face="Courier New">ui:repeat</font>. Or better still, convert your tag file to a real <font face="Courier New">UIComponent</font>.</p>
<p>You might also recognise that the <font face="Courier New">${child}</font> EL expression is meaningless during build time in this example, unless you use <font face="Courier New">c:foreach</font>.</p>
<p><strong>My list doesn't change size after deleting or adding an item</strong></p>
<pre>&lt;h:form&gt;<br />
&lt;c:forEach items="${list}" var="item"&gt;<br />
&lt;h:outputText value="${item.name}"/&gt;&lt;br/&gt;<br />
&lt;/c:forEach&gt;<br />
&lt;h:commandButton value="Create new item" action="..."/&gt;<br />
&lt;h:commandButton value="Delete an item" action="..."/&gt;<br />
&lt;/h:form&gt;</pre>
<p>When your view was built you only had, say, 5 items. If you post
back to this view and add or delete an item, your view still has 5 <font face="Courier New">h:outputText</font> components in it since it was restored from saved state. In this simple case, you should use <font face="Courier New">ui:repeat</font> and your tree will always contain one <font face="Courier New">h:ouputText</font> component which is iterated over with differing values of <font face="Courier New">${item}</font>.</p>
<p>If you rely on using <font face="Courier New">c:forEach</font> to
dynamically include different form components you could run into
difficulty. Always try to think about what the resulting tree looks
like and remember it doesn't change on a postback.</p>
<h4>Suggestions for the future</h4>
<p>Probably the best relief to this problem would be to come up with a
better syntax or naming convention to distinguish between tag handlers
and components. I imagine you could also improve compilation
performance if you did this.</p>
<p>Secondly, we need better terminology. I've used the terms <em>tag handler</em> and <em>component</em> in this blog which isn't too bad. The Facelets' FAQ [1] uses the terms <em>build-time tags</em> and <em>render-time tags</em>
which is a bit misleading because render-time tags (components) are
involved in all phases of the JSF lifecycle, not just the Render View
phase.</p>
<p>Whatever happens, tag handlers are very useful (would you use facelets without <font face="Courier New">ui:decorate</font>?) so let's not get rid of them.</p>
<h4>References</h4>
<p>[1] <a href="http://wiki.java.net/bin/view/Projects/FaceletsFAQ#Why_doesn_t_my_c_if_ui_repeat_ui" target="_blank">http://wiki.java.net/.../FaceletsFAQ#Why_doesn_t_my_c_if_ui_repeat_ui</a></p>
<img src ="http://www.blogjava.net/sealyu/aggbug/265212.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-04-13 08:52 <a href="http://www.blogjava.net/sealyu/archive/2009/04/13/265212.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Seam中 select list的用法</title><link>http://www.blogjava.net/sealyu/archive/2009/04/09/264599.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Thu, 09 Apr 2009 02:54:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/04/09/264599.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/264599.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/04/09/264599.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/264599.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/264599.html</trackback:ping><description><![CDATA[<h2>Selecting from a list of entities </h2>
<p>See <a href="http://docs.jboss.org/seam/latest/reference/en/html/controls.html" class="external free" title="http://docs.jboss.org/seam/latest/reference/en/html/controls.html" rel="nofollow">http://docs.jboss.org/seam/latest/reference/en/html/controls.html</a>
</p>
<ul>
    <li> Use <tt>&lt;s:selectItems&gt;</tt> to produce a list of labeled select items from a list of entities.
    </li>
    <li> Use <tt>&lt;s:convertEntity&gt;</tt> to map back and forth between the select items and the actual entity values.  This is what allows you to map the <tt>value</tt> of the <tt>&lt;h:selectOneMenu&gt;</tt> directly to the property of the referencing entity (e.g. a property that is a many-to-one).
    </li>
</ul>
<pre>&lt;h:selectOneMenu value="#{person.continent}" required="true"&gt;                        (1)<br />
&lt;s:selectItems value="#{continents.resultList}" var="continent"                  (2)<br />
label="#{continent.name}" noSelectionLabel="Please Select..."/&gt;<br />
&lt;s:convertEntity /&gt;                                                              (3)<br />
&lt;/h:selectOneMenu&gt;<br />
</pre>
<ol>
    <li> <tt>person</tt> is an entity that has been outjected into the
    conversation. It has a 'continent' property which is many-to-one
    association with another entity.
    </li>
    <li> <tt>continents</tt> is a Seam application framework 'query'
    object. This 'query' object should probably use a Seam-managed
    EntityManager because we want have the Hibernate <a href="http://shrubbery.mynetgear.net/wiki/Session-in-view_with_Seam" title="Session-in-view with Seam">session-in-view behavior</a> so we don't get lazy initialization exceptions when rendering the labels, etc.
    </li>
    <li> <tt>s:convertEntity</tt> will convert the Continent entities into values for the HTML select, and vice versa.
    </li>
</ol>
<h3> Tips </h3>
<ol>
    <li> To avoid LazyInitializationExceptions and/or writing extra code in your EJB/Controller bean to initialize objects, use <a href="http://shrubbery.mynetgear.net/wiki/Session-in-view_with_Seam" title="Session-in-view with Seam">session in view</a>.
    </li>
    <li> For required fields, put <tt>required="true"</tt> on the <tt>selectOneMenu</tt> and override <tt>javax.faces.component.UIInput.REQUIRED</tt> in <tt>messages.properties</tt> (see <a href="http://shrubbery.mynetgear.net/wiki/Standard_Faces_Error_Messages" title="Standard Faces Error Messages">Standard Faces Error Messages</a>).
    </li>
</ol>
<h2> Select from an enum </h2>
<p>This works just like selecting an entity, but <tt>&lt;s:convertEnum/&gt;</tt> is used instead.
</p>
<p><br />
XHTML:
</p>
<pre>&lt;h:selectOneMenu id="marketStatus" value="#{person.status}"         (1)<br />
required="true"&gt;<br />
&lt;s:selectItems value="#{enumLists.statusArray}" var="status"    (2)<br />
label="#{status}"<br />
noSelectionLabel="Select a status..."/&gt;<br />
&lt;s:convertEnum/&gt;<br />
&lt;/h:selectOneMenu&gt;<br />
</pre>
<p>EnumLists.java:
</p>
<pre>@Name("enumLists")<br />
@Scope(ScopeType.STATELESS)<br />
public class EnumLists<br />
{<br />
public Status[] getStatusArray()<br />
{<br />
return Status.values();<br />
}<br />
}<br />
</pre>
<ol>
    <li> <tt>person</tt> is an entity that has been outjected into the conversation.  It has a 'status' property which is an enum.
    </li>
    <li> We need to expose the values of the enum as a list or an
    array, so we make a stateless POJO component with getters that returns
    arrays for various enums called <tt>enumLists</tt>.
    </li>
</ol>
<h2> Multi-select from an enum </h2>
<p>Here we use a <a href="http://www.exadel.com/tutorial/jsf/jsftags-guide.html#selectmany" class="external text" title="http://www.exadel.com/tutorial/jsf/jsftags-guide.html#selectmany" rel="nofollow">selectManyCheckbox</a>.
</p>
<p><br />
</p>
<pre>&lt;h:selectManyCheckbox id="roles" <br />
layout="pageDirection" value="#{person.roles}"<br />
required="true"&gt;<br />
&lt;s:selectItems value="#{enumLists.roleArray}" var="role"<br />
label="#{role}"/&gt;<br />
&lt;s:convertEnum/&gt;<br />
&lt;/h:selectManyCheckbox&gt;<br />
</pre>
<p>Unfortunately, Seam's <tt>convertEnum</tt> can't handle multi selects yet.  This example will yeild a strange exception:
</p>
<pre>java.lang.IllegalArgumentException: java.util.List is not an enum type<br />
</pre>
<p>Luckily, it's very easy to create <a href="http://shrubbery.mynetgear.net/wiki/Custom_converter_tags_with_Facelets" title="Custom converter tags with Facelets">custom converter tags with Facelets</a>.  Here is the converter class that handles both ordinary enums and multi-selects:
</p>
<pre>package eg;<br />
<br />
import javax.faces.component.*;<br />
import javax.faces.context.*;<br />
import javax.faces.convert.*;<br />
import javax.faces.el.ValueBinding;<br />
import java.util.List;<br />
import java.util.Collection;<br />
<br />
/**<br />
* Converter for enum multi-selects.<br />
* &lt;br&gt;User: Joshua Davis<br />
* Date: May 16, 2007<br />
* Time: 7:25:58 AM<br />
*/<br />
public class EnumListConverter implements Converter<br />
{<br />
@SuppressWarnings({"unchecked"})<br />
public Object getAsObject(FacesContext context,<br />
UIComponent comp,<br />
String value)<br />
throws ConverterException<br />
{<br />
ValueBinding binding = comp.getValueBinding("value");<br />
Class enumType = binding.getType(context);<br />
if (enumType.isEnum())  // Single enum?<br />
return Enum.valueOf(enumType, value);<br />
else    // List of enums.<br />
{<br />
// Find the s:selectItems so we can get the enum.<br />
List children = comp.getChildren();<br />
for (Object child&nbsp;: children)<br />
{<br />
if (child instanceof UIComponent)<br />
{<br />
UIComponent c = (UIComponent) child;<br />
ValueBinding b = c.getValueBinding("value");<br />
Class t = b.getType(context);<br />
// Array of enums: use the component type.<br />
if (t.isArray() &amp;&amp; t.getComponentType().isEnum())<br />
{<br />
t = t.getComponentType();<br />
return Enum.valueOf(t,value);<br />
}<br />
else<br />
{<br />
Object v = b.getValue(context);<br />
// Collection of enum values, get the type of the first element.<br />
if (v instanceof Collection)<br />
{<br />
t = ((Collection) v).iterator().next().getClass();<br />
return Enum.valueOf(t,value);<br />
}<br />
}<br />
}<br />
}<br />
throw new ConverterException("Unable to find selectItems with enum values!");<br />
}<br />
}<br />
<br />
public String getAsString(FacesContext context,<br />
UIComponent component,<br />
Object object)<br />
throws ConverterException<br />
{<br />
if (object == null) {<br />
return null;<br />
}<br />
<br />
return ((Enum) object).name();<br />
}<br />
<br />
}<br />
</pre>
<div>
Retrieved from "<a href="http://shrubbery.mynetgear.net/wiki/Select_lists_with_Seam">http://shrubbery.mynetgear.net/wiki/Select_lists_with_Seam</a>"</div>
<img src ="http://www.blogjava.net/sealyu/aggbug/264599.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-04-09 10:54 <a href="http://www.blogjava.net/sealyu/archive/2009/04/09/264599.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Richfaces中&lt;a4j:repeat&gt;标签判断最后一个元素的方法</title><link>http://www.blogjava.net/sealyu/archive/2009/04/02/263588.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Thu, 02 Apr 2009 09:42:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/04/02/263588.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/263588.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/04/02/263588.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/263588.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/263588.html</trackback:ping><description><![CDATA[<pre>&lt;a4j:repeat value="#{personList}" var="person" rowKeyVar="rowIndex"&gt;<br />
&lt;img src="img/arrow.png"&gt; &lt;/img&gt;<br />
&lt;h:outputText rendered="#{rowIndex == personList.size() -1}" value="#{entry.description}"/&gt;<br />
&lt;/a4j:repeat&gt;<br />
<br />
使用rowKeyVar按照上面的方法判断就可以了<br />
</pre>
<img src ="http://www.blogjava.net/sealyu/aggbug/263588.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-04-02 17:42 <a href="http://www.blogjava.net/sealyu/archive/2009/04/02/263588.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在JSF和SEAM中对java.util.Set及其子类作循环</title><link>http://www.blogjava.net/sealyu/archive/2009/04/01/263344.html</link><dc:creator>seal</dc:creator><author>seal</author><pubDate>Wed, 01 Apr 2009 05:47:00 GMT</pubDate><guid>http://www.blogjava.net/sealyu/archive/2009/04/01/263344.html</guid><wfw:comment>http://www.blogjava.net/sealyu/comments/263344.html</wfw:comment><comments>http://www.blogjava.net/sealyu/archive/2009/04/01/263344.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sealyu/comments/commentRss/263344.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sealyu/services/trackbacks/263344.html</trackback:ping><description><![CDATA[<h2>How to iterate over java.util.Set in&nbsp;JSF</h2>
<small>By bozhobg</small>
<p>I
spent quite some time trying to find a solution for the following JSF
issue: it is not possible to iterate over a java.util.Set.<br />
- ui:repeat (facelets) doesn&#8217;t work<br />
- a4j:repeat (richfaces) doesn&#8217;t work<br />
- c:forEach works..only in case it does not rely on a variable defined by a parent component (rich:dataTable for instance)</p>
<p>All above are pretty logical phenomena, as UIData relies on ordered data, and generally a Set is not ordered.</p>
<p>In my case I had to use a Set defined in the Hibernate (JPA) object (PersistentSet).<br />
An important note: you should use a set in case the view order is of no matter to you.</p>
<p>The solution..is pretty simple. And I&#8217;ll suggest it to be a part of
facelets/richfaces for the next version, unless of course there is some
valid specific</p>
<p>reason for it not to be.</p>
<p>1. Define your own UI component extending an existing repeater component. I used a4j:repeat (HtmlAjaxRepeat)<br />
2. Override the metohd getDataModel<br />
3. Define your component in your faces-config<br />
4. create a custom facelets tag definition<br />
5. Define a context-variable in web.xml pointing to the facelet tag definition.</p>
<p>Note: for use with JSP instead of Facelets, you should define a .tld and a Tag handler, which is not an ojbect of this post.</p>
<p>Now let&#8217;s see the steps in detail:</p>
<p>1,2. Here some code:</p>
<div>
<div>
<div><a href="http://bozhobg.wordpress.com/2009/03/03/how-to-iterate-over-javautilset-in-jsf/#" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><a href="http://bozhobg.wordpress.com/2009/03/03/how-to-iterate-over-javautilset-in-jsf/#" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;">copy to clipboard</a><a href="http://bozhobg.wordpress.com/2009/03/03/how-to-iterate-over-javautilset-in-jsf/#" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a><a href="http://bozhobg.wordpress.com/2009/03/03/how-to-iterate-over-javautilset-in-jsf/#" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div>
</div>
<ol>
    <li>package&nbsp;com.myproject.components;&nbsp;&nbsp;</li>
    <li>import&nbsp;java.util.ArrayList;&nbsp;&nbsp;</li>
    <li>import&nbsp;java.util.Set;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>import&nbsp;javax.faces.model.DataModel;&nbsp;&nbsp;</li>
    <li>import&nbsp;javax.faces.model.ListDataModel;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>import&nbsp;org.ajax4jsf.component.html.HtmlAjaxRepeat;&nbsp;&nbsp;</li>
    <li>import&nbsp;org.ajax4jsf.model.SequenceDataModel;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>public&nbsp;class&nbsp;UIIterator&nbsp;extends&nbsp;HtmlAjaxRepeat&nbsp;{&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;@SuppressWarnings("unchecked")&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;@Override&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;protected&nbsp;DataModel&nbsp;getDataModel()&nbsp;{&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;current&nbsp;=&nbsp;getValue();&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(current&nbsp;instanceof&nbsp;Set){&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;SequenceDataModel(new&nbsp;ListDataModel(&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;ArrayList((Set)&nbsp;current)));&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;super.getDataModel();&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li>
    <li>}&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="java">package com.myproject.components;
import java.util.ArrayList;
import java.util.Set;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import org.ajax4jsf.component.html.HtmlAjaxRepeat;
import org.ajax4jsf.model.SequenceDataModel;
public class UIIterator extends HtmlAjaxRepeat {
@SuppressWarnings("unchecked")
@Override
protected DataModel getDataModel() {
Object current = getValue();
if(current instanceof Set){
return new SequenceDataModel(new ListDataModel(
new ArrayList((Set) current)));
}
return super.getDataModel();
}
}
</pre>
<p>So, as we don&#8217;t care about the order of the elements, we just create
a new ArrayList out of the Set. And we can now easily return the
appropirate DataModel.</p>
<p>3. Add this to your faces-config. (I copied it from the a4j definition)</p>
<div>
<div>
<div><a href="http://bozhobg.wordpress.com/2009/03/03/how-to-iterate-over-javautilset-in-jsf/#" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><a href="http://bozhobg.wordpress.com/2009/03/03/how-to-iterate-over-javautilset-in-jsf/#" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;">copy to clipboard</a><a href="http://bozhobg.wordpress.com/2009/03/03/how-to-iterate-over-javautilset-in-jsf/#" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a><a href="http://bozhobg.wordpress.com/2009/03/03/how-to-iterate-over-javautilset-in-jsf/#" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div>
</div>
<ol>
    <li>&lt;component&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;description&nbsp;/&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;display-name&gt;Iterator&lt;/display-name&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;component-type&gt;com.myproject.Iterator&lt;/component-type&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;component-class&gt;com.myproject.components.UIIterator&lt;/component-class&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;component-extension&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;component-family&gt;javax.faces.Data&lt;/component-family&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;renderer-type&gt;org.ajax4jsf.components.RepeatRenderera&lt;/renderer-type&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/component-extension&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/component&gt;&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="xml">&lt;component&gt;
&lt;description /&gt;
&lt;display-name&gt;Iterator&lt;/display-name&gt;
&lt;component-type&gt;com.myproject.Iterator&lt;/component-type&gt;
&lt;component-class&gt;com.myproject.components.UIIterator&lt;/component-class&gt;
&lt;component-extension&gt;
&lt;component-family&gt;javax.faces.Data&lt;/component-family&gt;
&lt;renderer-type&gt;org.ajax4jsf.components.RepeatRenderera&lt;/renderer-type&gt;
&lt;/component-extension&gt;
&lt;/component&gt;
</pre>
<p>4. Here is the tag definition for facelets</p>
<div>
<div>
<div><a href="http://bozhobg.wordpress.com/2009/03/03/how-to-iterate-over-javautilset-in-jsf/#" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><a href="http://bozhobg.wordpress.com/2009/03/03/how-to-iterate-over-javautilset-in-jsf/#" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;">copy to clipboard</a><a href="http://bozhobg.wordpress.com/2009/03/03/how-to-iterate-over-javautilset-in-jsf/#" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a><a href="http://bozhobg.wordpress.com/2009/03/03/how-to-iterate-over-javautilset-in-jsf/#" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div>
</div>
<ol>
    <li>&lt;?xml&nbsp;version="1.0"&nbsp;encoding="UTF-8"?&gt;&nbsp;&nbsp;</li>
    <li>&lt;!DOCTYPE&nbsp;facelet-taglib&nbsp;PUBLIC&nbsp;&nbsp;</li>
    <li>"-//Sun&nbsp;Microsystems,&nbsp;Inc.//DTD&nbsp;Facelet&nbsp;Taglib&nbsp;1.0//EN"&nbsp;&nbsp;</li>
    <li>"http://java.sun.com/dtd/facelet-taglib_1_0.dtd"&gt;&nbsp;&nbsp;</li>
    <li>&lt;facelet-taglib&nbsp;xmlns="http://java.sun.com/JSF/Facelet"&gt;&nbsp;&nbsp;</li>
    <li>&lt;namespace&gt;http://myproject.com/cust&lt;/namespace&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>&lt;tag&gt;&nbsp;&nbsp;</li>
    <li>&lt;tag-name&gt;repeat&lt;/tag-name&gt;&nbsp;&nbsp;</li>
    <li>&lt;component&gt;&nbsp;&nbsp;</li>
    <li>&lt;component-type&gt;com.myproject.Iterator&lt;/component-type&gt;&nbsp;&nbsp;</li>
    <li>&lt;renderer-type&gt;org.ajax4jsf.components.RepeatRenderer&lt;/renderer-type&gt;&nbsp;&nbsp;</li>
    <li>&lt;/component&gt;&nbsp;&nbsp;</li>
    <li>&lt;/tag&gt;&nbsp;&nbsp;</li>
    <li>&nbsp;&nbsp;</li>
    <li>&lt;/facelet-taglib&gt;&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE facelet-taglib PUBLIC
"-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
"http://java.sun.com/dtd/facelet-taglib_1_0.dtd"&gt;
&lt;facelet-taglib xmlns="http://java.sun.com/JSF/Facelet"&gt;
&lt;namespace&gt;http://myproject.com/cust&lt;/namespace&gt;
&lt;tag&gt;
&lt;tag-name&gt;repeat&lt;/tag-name&gt;
&lt;component&gt;
&lt;component-type&gt;com.myproject.Iterator&lt;/component-type&gt;
&lt;renderer-type&gt;org.ajax4jsf.components.RepeatRenderer&lt;/renderer-type&gt;
&lt;/component&gt;
&lt;/tag&gt;
&lt;/facelet-taglib&gt;
</pre>
<p>Save this file as /WEB-INF/facelets/custom.taglib.xml</p>
<p>5. Add to your web.xml</p>
<div>
<div>
<div><a href="http://bozhobg.wordpress.com/2009/03/03/how-to-iterate-over-javautilset-in-jsf/#" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><a href="http://bozhobg.wordpress.com/2009/03/03/how-to-iterate-over-javautilset-in-jsf/#" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;">copy to clipboard</a><a href="http://bozhobg.wordpress.com/2009/03/03/how-to-iterate-over-javautilset-in-jsf/#" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a><a href="http://bozhobg.wordpress.com/2009/03/03/how-to-iterate-over-javautilset-in-jsf/#" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div>
</div>
<ol>
    <li>&lt;context-param&gt;&nbsp;&nbsp;</li>
    <li>&lt;param-name&gt;facelets.LIBRARIES&lt;/param-name&gt;&nbsp;&nbsp;</li>
    <li>&lt;param-value&gt;/WEB-INF/facelets/custom.taglib.xml&lt;/param-value&gt;&nbsp;&nbsp;</li>
    <li>&lt;/context-param&gt;&nbsp;&nbsp;</li>
</ol>
</div>
<pre style="display: none;" name="code" class="xml">&lt;context-param&gt;
&lt;param-name&gt;facelets.LIBRARIES&lt;/param-name&gt;
&lt;param-value&gt;/WEB-INF/facelets/custom.taglib.xml&lt;/param-value&gt;
&lt;/context-param&gt;
</pre>
<p>6. It is now ready to use<br />
&#8230;<br />
xmlns:cust=&#8221;http://myproject.com/cust&#8221;<br />
&#8230;</p>
<p>&lt;cust:repeat var=&#8221;myVar&#8221; value=&#8221;${aSet}&#8221;&gt;<br />
&#8230;<br />
&lt;/cust:repeat&gt;<br />
I think it is way neater than other workarounds, like defining a custom EL Resolver.</p>
<hr />
<img src ="http://www.blogjava.net/sealyu/aggbug/263344.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sealyu/" target="_blank">seal</a> 2009-04-01 13:47 <a href="http://www.blogjava.net/sealyu/archive/2009/04/01/263344.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>