
Thursday December 28, 2006
How to Integrate AJAX4JSF into Creator2.
How to Integrate AJAX4JSF into Creator2.
AJAX4JSF(A4J) is amazing me when I first see it, my fisrt idea
is can't it integrate it into Creator2 (or Netbean 5.5VWP).
I followed the A4J develop guide steps got a Creator2 crash result.
I found no solutions in the internet, fortunately I
find/try-out the solutions my-self. So,I write a Englinsh step version, hope
this solution can help anyone who want to use A4J in Creator2.
Step1.Extract ajax4jsf.jar, remove files in META-INF\ except
MANIFETS.MF , a4j.taglib.xml and a4j.tld, then re-package to
ajax4jsf-dt.jar
Step2.Add jars below into your project.
ajax4jsf-dt.jar, (uncheck package flag, this jar is for
designtime only)
commons-beanutil.jar,
commons-collections.jar
common-digester.jar
(those commons jars are for preventing designtime exception, some webap
already contains those jars)
Don't add oscache.jar into project, add this jar
crash Creator2.
You should add ajax4jsf.jar and oscache.jar manual( or by build.xml) when
deploy application
Step3.
Follow the A4J Develop Guide, add filter into web.xml and write you
JSF code.
Remeber adding ajax4jsf.jar and oscache.jar to your application's
lib.
==
如何在Creator2裏加入AJAX4JSF的功能
AJAX4JSF(A4J),是一個很簡單就能讓JSF的頁面,擁有AJAX的功能,
雖然他只支援預設的JSF元件(例如h:inputText,h:selectOneMenu這類的)
不過對於某些ajax的需來講,已經很神奇了
例如檢查textfield裏的資料是否正確,及drowdown的連動等等..
這裏就不介紹如何使用A4J了.
你可以到A4J的網頁逛逛,應該就可以看到如何開發使用了...
我在這裏要討論的是如何講A4J的功能加到Creator2的開發環境裏.
遵從A4J的Developer Guide,將A4J加入Creator2時,
竟然導致我的專案頁面從此不能被Creator2開啟,
最後甚至連Creator2本身都無法啟動..
如果你不小心因為A4J讓Creator2掛了,你可以將設定目錄下的
.Creator\2_1\var全部清掉
另外也需清除Creator\2_1\config,
不過由於清除這個目錄會讓設定(包含lib)通通不見
所以目前,我只是留org-netbeans-api-project-libraries這個目錄不清(可以保留專案的lib)
(很抱歉我並不想再花時間去找只清那些就行..)
然後再自行去開啟專案.
記得,你必需先手動把接下來講的設定給設好,然後才用Creator2去開,否則又要讓Creator2
Crash一次了.
經過兩天的分析原因跟測試後,我終於發現原因,並試出了正確的整合方法...
1.解開ajax4jsf.jar,將\META-INF\下的檔案,除了a4j.taglib.xml及a4j.tld留下外,全部刪除。然後重新包裝一成ajax4jsf-dt.jar檔.
(主要應該是拿掉faces-conofig.xml就行了,我沒作多餘的細節測試,讓creator2不會去使用裏面的東西,而導至exception)
2.替你的專案加入下列jar檔.
ajax4jsf-dt.jar, (要把package的勾給免掉,免得被放到runtime,
runtime要手動加,或是改build.xml來加,請自己動手吧)
commons-beanutil.jar,
(這三個commons是為了designtime加的,不加會出exception)
commons-collections.jar,
common-digester.jar
千萬不要加入a4j的Developer
Guide裏說要加的oscache.jar,這個檔應該是導至Creator2整個不能開啟的主要原因
原本的ajax4jsf.jar及oscache.jar留到develop時,再加到web-inf\lib即可.
3.接下來就是依A4J的Developer Guide來設定你的專案了
3.1.將a4j的filter加入web.xml,(Developer
Guide說要放在第一個Filter)
<filter>
<display-name>Ajax4jsf
Filter</display-name>
<filter-name>ajax4jsf</filter-name>
<filter-class>org.ajax4jsf.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>ajax4jsf</filter-name>
<servlet-name>Faces Servlet</servlet-name>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
3.3.寫你的a4j的程式吧~
3.4.記得把ajax4jsf.jar,及oscache.jar加到(手動或變build.xml)\build\web\web-inf\lib,不然是不會動的喲.
此外.我也在Netbean 5.5
vwp上試過,可以省掉制作ajax4jsf-dt.jar這個步驟,只需注意不要加入oscache.jar即可.(commons的那幾個jar還是要加)
目前我只測試過h:inputText,及h:selectOneMenu是OK的,不過已經夠我目前的案子使用了~
另外提一個目前寫selectOneMenu遇到的小提示.
我在selectOneMenu使用的a4j
tag為
<h:selectOneMenu
binding="#{Page1.dropdown1}" id="dropdown1">
<f:selectItems
binding="#{Page1.dropdown1SelectItems}" id="dropdown1SelectItems"
value="#{Page1.dropdown1DefaultItems}"/>
<a4j:support
action="#{Page1.changeDropdown1}" event="onchange"
reRender="groupPanel1,groupPanel2"/>
</h:selectOneMenu>
這裏在onchange時,理論上會呼叫Page1.changeDropdown1()這個method,
可是在實作上要小心一點.
當selectItems的來源也是動態決定的時候,如果你select到的值,並不在重新request時所動態產生的那群新值裏.這時候onchange是不會被呼叫的.
而,這其實是符合JSF元件的行為的.
完蛋,今天一整天都沒作專案的東西...

Thursday November 09, 2006
NetBeans Visual Web Pack 5.5 Release again...

前前陣子NetBeans 5.5 出了Visual Web Pack ...(看畫面,其實就是creator2 proting 到 netbean 5.5的版本吧..)
不過好像有問題..
我在前陣子要下載時時,download都被拿掉了..
不過,昨天又看到可以下載了~~
昨天晚上玩了一下...
感覺起來比Creator2漂亮~~
不過import webproject時,跳出一個import完的project,creator2就不能開了(設定沒有相容?),要我備份~~~
這個真是蠻可怕的~~~
開了一個舊的測試DWR的Web Proejct,
速度感覺有比較快...(感覺~~!)
不過在編Java時跳出的assitistant就真的比較快了~
重新clean build時發生了一些library的問題~~~
當然,因為netbeans 5.5上當然沒有我creator2上的lib.
不過也需自己加入jsf 1.1的library...
重新build完後,deploy到內建的tomcat上,竟然上不去.~~
不過內建的tomcat有跑來了~~
不想找原因..
手動deploy到我的tomcat 5.5 ..總算是跑起來了~
所有的action也都正常~
不過案子要轉成visual web package大概還需要full test吧..
不太安心~~~
還沒試自己的complib上去的結果~

Monday November 06, 2006
Createor2檔案上傳元件-上傳中文檔名解法
在使用Creator2提供的上傳元件時,
會發生上傳檔案為中文檔名時,
在Server上捉取到的檔名uploadedFile.getOriginalName()會為亂碼~
找過一些文章討論後
http://gceclub.sun.com.cn/NASApp/sme/jive/thread.jsp?forum=27&thread=34660原來是UploadFilter並不會去設定request的characterEncoding.(request.getCharacterEncoding=null)
而Creator2Upload元件似乎是使用Apache Common Upload 的元件
如果request.getCharacterEncoding() == null,則會用Server編碼來解析(例MS950),而客戶端用的是頁面內容編碼(例UTF-8)
所以,就出現亂碼了~~
解決的方法有二.
A.強制設定頁面編碼為MS950..
不過我都是用UTF8來開發,才能應付多國語系,這個解法不適用.
B.繼承修改UploadFilter,強制將編碼設定為UTF-8,作法如下:
1.Write a filter which extends UploadFilter
public class UploadFilterExt extends com.sun.rave.web.ui.util.UploadFilter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException,ServletException{
if(request.getCharacterEncoding()==null){
request.setCharacterEncoding("UTF-8");
}
super.doFilter(request,response,chain);
}
} |
2.modify web.xml將UploadFilter置換成UploadFilterExt

Sunday November 05, 2006
在JSP裏混用JSF元件與HTML/JavaScript,輸出到Client時會被分離之迷解答
開發JSF頁面及元件這半年來,常遇到一個問題,
在JSF的頁面裏,混著寫html/javascript文字及元件tag時,
輸出結果在最後output到client端時有時會被分離成兩組輸出,
而不是以我們在JSP看到的順序輸出。
例如一:
<ui:Panel id="panel">
<div>
<script>alert("A")</script>
<ui:Button id="button"/>
</div>
</ui:Panel>
期望在client端應該是,
<div id="form1:panel>
<div>
<script>alert("A")</script>
<input type="button" id="form1:button"/>
</div>
</div>
但事實上會變成
<div>
<script>alert("A")</script>
</div>
<div id="form1:panel>
<input type="button" id="form1:button"/>
</div>
這個列子在初步一看一定覺得不合理,
而且在實際的開發上,一定會產生困優。
但這件事經過最終看完source後,又覺得無可厚非
會發生這件事情的主要元因是JSF的架構性的問題...
當你使用的元件是一個Container時(例如Panel這類的元件)
他可能會期望自己來排列兒子的順序(例如grid layout)
而不是依tag寫的"單純"順序去輸出結果。
這時候,這顆元件會(應該)去改寫getRenderChildren(),並retrun true,表示他要自己來render兒子.
(以gridPanel來看,就必需在各個兒子間用tr/td來作排版)
即表示,這時候利用的JSP裏tag的順序來out是不合用的,
因為tag跟tag中間可能要有其parent的客制化輸出
從JSF規格的source(UIComponentTag)來看
當一個元件不用自己render兒子元件時,
他的encodeStart會在doStartTag被呼叫
他的encodeEnd會在doEndTag被呼叫
他其兒子就理所當然的依JSP裏tag執行的順序被呼叫到,(而不呼叫該元件的encodeChildren)
而穿插在tag中的純文字輸出就理所當然依順序被輸出
例如JSP的JAVA Code:
panel_tag.doStartTag()
out.write("<div>")
out.wirte("<script>alert(\"A\")</script>");
button_tag.doStartTag();
button_tag.doEndTag();
out.write("</div>");
panel_tag.doEndTag();
可是當一顆元件需要自己render兒子元件時
元件會設定了一個suppressed falg,(還有其他狀況的設suppressed,列如這個元件是在facet裏)
則它的encodeStart,encodeChildren及encodeEnd就會只在doEndTag時被呼叫(UIComponentTag的實作)
從這個元件之後.
它的所有下層元件將被壓制,不再在doStartTag,及doEndTag裏來輸出,
而這顆元件有將其下層元件呼叫輸出的義務(直到遇到下層中另外一顆也需自己輸出兒子的元件)。
從JSP的JAVA CODE來看.
panel_tag.doStartTag() ==> no output
out.write("<div>")
out.wirte("<script>alert(\"A\")</script>");
button_tag.doStartTag(); ==> no output
button_tag.doEndTag(); ==> no output
out.write("</div>");
panel_tag.doEndTag(); ==> out panel &
button
很明顯的,將導致輸出被分離的結果。
結論是,當一個頁面用了類似Panel這種要自己layout children的Componet後,
在裏面寫的HTML或javascript,必需不包含位置及序頁的特性
也就是說JavaScript寫成在.js裏,HTML....應該是沒救了...不要寫HTML~~~
Or,請愛用Tiles Panel元件~~~~~將script及html寫在tiles對應的layout.jsp裏

Wednesday November 01, 2006
Use tielsPanel if you don't want to wait....
因為我手頭上的事要進行,,所以想要的JSF元件還是排隊一個一個來~~
如果真的想把一些javascript的元件用進你的JSF案子該怎麼進行呢??
舉個例子吧~
我現在想把一堆TextField分成兩組,放到Dojo 的Tab裏,由於我們目前並沒有dojo的tab元件..所以只能手動來作了...
如果我直接在我的JSP裏寫javascript或是HTML,且會因為JSF的關系,得到的結果卻會JSF元件跟我的code是分離的。
這個時候,請用神奇的tilesPanel吧~~~~
Step1.
把這些TextFiled分別用兩個PaneLayout包起來,再用一個TilesPanel來包這兩個PanelLayout


在Designer你會看到..


Step2.
設定TielsPanel的definitionName為TAB_LAYOUT
Step3.
將TAB_LAYOUT的tiels設定加進/web-inf/tiels-defs.xml,內容如下:
<definition
name="TAB_LAYOUT"
path="/layout/TabLayout.jsp"
></definition>
Step4.
編輯/layout/TabLayout.jsp,這裏是使用dojo的tab,如果你是使用其他的元件,或是只是想要單純作layout,請依你使用的需求編輯。
其中使用insertComponent指定其加入JSF元件的順序,這裏0對應到layoutPanel1,1對應到layoutPanel2
<jsp:root
version="1.2"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:tiles="http://struts.apache.org/tags-tiles"
xmlns:tjsf="http://www.infinitiessoft.com/jsf/creator2ex/jsptag"
xmlns:jsp="http://java.sun.com/JSP/Page"
>
<script
type="text/javascript">
dojo.require("dojo.widget.TabContainer");
dojo.require("dojo.widget.ContentPane");
</script>
<div
style="padding:
4px;">
<div
id="mainTabContainer"
dojoType="TabContainer"
style="width:
400px;height:300px" selectedTab="unitInfoTab1">
<div
id="unitInfoTab1"
dojoType="ContentPane"
label="聯絡資訊">
<tjsf:insertComponent
sequence="0"
silence="true"/>
</div>
<div
id="unitInfoTab2"
dojoType="ContentPane"
label="其他資訊">
<tjsf:insertComponent
sequence="1"
silence="true"/>
</div>
</div>
</div>
</jsp:root>
Step5.
(相依於Step4,因為使用了dojo)為你的頁面加入dojo.js及dojoHelper.js,如下:


Step6.
(相依於Step4,因為使用了dojo)為你的頁面設定Body的onLoad=”
dojoInitial();”,onUnload=”
dojoUnload();”。
Step7.
把Project跑起來,應該就會看到dojo-tab把欄位分成兩個tab了.


其他
TilesPanel還可以應用在Layout上面。如果你很厭煩用一堆gridPanel,layotPanle才能組出你要的畫面(或許跟本組不出你要的畫面),何妨使用TilesPanel,自己寫table來設計畫面呢?

Wednesday October 18, 2006
Cookie Overflow in IE & FF
之前使用dojo tree元件的網頁玩太久就會掛的問題總算讓我找到原因了~~~
因為真的是因為Cookie爆掉了~~
只是IE跟FF竟然連一個訊息都沒有,只是變成空白頁面真是過份...
寫了一個測試的JSF如下.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
|
<%@ page language="java" contentType="text/html; charset=BIG5" pageEncoding="BIG5"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=BIG5"> <title>Insert title here</title> </head> <body> <% Cookie[] cookies = request.getCookies(); if(cookies!=null){ for(int i=0;i<cookies.length;i++){ String name = cookies[i].getName(); String value = cookies[i].getValue(); String domain = cookies[i].getDomain(); String path = cookies[i].getPath(); int maxAge = cookies[i].getMaxAge(); %> <%=i+1%>. Cookie:<%=name%>, domain:<%=domain%>, path:<%=path%>, maxAge:<%=maxAge%>, valueLength:<%=value.length()%> <br/> <% } } %> <script> function assignCookie(){ var csize = parseInt(document.getElementById("cookieLength").value); var cname = document.getElementById("cookieName").value; var cvalue = ""; for(var i=0;i<csize;i++){ cvalue += "A"; } setCookie(cname,cvalue); return true; } function setCookie(name, value, days, path, domain, secure) { var expires = -1; if(typeof days == "number" && days >= 0) { var d = new Date(); d.setTime(d.getTime()+(days*24*60*60*1000)); expires = d.toGMTString(); } value = escape(value); document.cookie = name + "=" + value + ";" + (expires != -1 ? " expires=" + expires + ";" : "") + (path ? "path=" + path : "") + (domain ? "; domain=" + domain : "") + (secure ? "; secure" : ""); } </script> <form method="post" > Cookie Name:<input type="text" name="cookieName" id="cookieName" value="test"/><br> Cookie Length:<input type="text" name="cookieLength" id="cookieLength" value="3471"/><br> <input type="submit" value="submit" onclick="return assignCookie()"/> </form> </body> </html>
|
在FF
1. Cookie:test, domain:null, path:null, maxAge:-1, valueLength:3471
2. Cookie:JSESSIONID, domain:null, path:null, maxAge:-1, valueLength:32
長度到3471,在submit後,會變成空白頁面
在IE
1. Cookie:test, domain:null,
path:null, maxAge:-1, valueLength:3456
2. Cookie:JSESSIONID, domain:null,
path:null, maxAge:-1, valueLength:32
長度到3456,在submit後,會變成空白頁面
所以cookie目前在FF及IE上確實會發生4k的限制
而量不是單一cookie的size,而是每次送出的總cookie的大小限制在4k
我的元件會出錯是因為我的元件設cookie時忘了指定path.
所以預設的path會是jsp的目錄
例如,/test/cookieTest.jsp 其cookie路徑會是/test/
所以當我玩了太多頁面後,每一頁所累計的cookie都會傳送到server.
結果當然就在玩太多頁後超過4k了..
目前的解法就是指定path到JSP,
例如,/test/cookieTest.jsp
設定其cookie路徑會是/test/cookieTest.jsp
這樣就會只有這個cookie會被送到Server.
這樣子應該能解掉我目前玩太久就會掛的問題...
不過如果遇到畫面上的樹太深太廣的話...
還是有可能單一頁面的cookie就超過4k了...>____<
看來最終解法還是要轉成用dyanmic input來傳送才行...