<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    寫程序,做產品,過日子

    成功其實很簡單,就是強迫自己堅持下去

    BlogJava 首頁 新隨筆 聯系 聚合 管理
      69 Posts :: 1 Stories :: 92 Comments :: 0 Trackbacks

    #

    Spring對Hibernate Session Factory提供了高度封裝。如下例所示。

    <bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="myDataSource"/>
    <property name="mappingResources">
    <list>
    <value>product.hbm.xml</value>
    </list>
    </property>
    <property name="hibernateProperties">
    <value>
    hibernate.dialect=org.hibernate.dialect.HSQLDialect
    </value>
    </property>
    </bean>

    然而,在我的案例中,因為業務需要,我們必須在運行時加入新的HBM。在單獨使用Hibernate的時,只要取到Hiberante Configuration對象,修改一下配置,然后rebuild session factory就可以了。

    可是經Spring這一封裝,我只能取到一個只讀的SessionFactory對象,無法進行重置。

    這里有兩種可能方法,但我都不知道如何做。

    1,取到LocalSessionFactoryBean對象進行重置。

    2,取到Hibernate Configuration對象進行重置。

    Technorati : , ,

    posted @ 2007-06-11 17:46 Welkin Hu 閱讀(4513) | 評論 (5)編輯 收藏

    Spring 2.0無縫集成了Hibernate.提供了很多功能。但在我看來,除了整合事務管理外,很多功能都 是可有可無的。

    最典型的就是HibernateTemplate,這個類其實就是代理了Hibernate Session的所有功能。把我看得一愣一愣的。半天沒明白這個類有什么奇妙用處。我用Hiberante API已經輕車熟路,自然不愿再學習新的API。

    它引入這個HibernateTemplate有什么作用呢?其API也不比Hibernate的API簡單啊。

    后來的測試表明Spring對Hibernate原生的API在事務支持上存在一些問題,而用HibernateTemplate,事務就運行得很好。

    Technorati : , ,

    posted @ 2007-06-11 13:53 Welkin Hu 閱讀(5872) | 評論 (8)編輯 收藏

    1. 在Eclipse中運行DOS

    這種方法的好處是連DOS執行窗口也集成在Eclipse Console中。

    在上面的設置是,Working Directory的設置非常重要。${container_loc}表示以當前選中文件的上級目錄為工作目錄。如果你選中的是某個目錄,比如說某個包,那么很不幸,它會指向這個目錄的上級目錄。所以,${container_loc}只適合選中一個文件的情況。

    另一個變量${resource_loc}則相反,它總是以選中的文件或目錄為工作目錄。就是說它適合選中一個目錄的情況。如果選中一個文件,運行DOS就會出錯,因為文件不能作為DOS的工作目錄。

    兩個變量各有優缺點。由于Java編程中,大部分DOS命令是在工程目錄下執行的,所以${resource_loc}會好一些。使用${container_loc}很難定位到工程目錄。

    2. Mylar導致Content Assist中出現重復的方法提示。

    最近發現我的Eclipse 3.3M7中出了個不大不小的問題,就是Java編輯窗口中的代碼提示工具把每一個方法都重復的列了兩次。如下圖所示。

    這個問題讓我百思不得其解,最后打開java -> Editor ->Content Assist的設置,才發現是新裝了Mylar的原因。如下圖所示,Mylar為content assist增加了幾個同名的Proposal,將這些同名的Porposals任意勾掉一個就解決問題了。

    Technorati :

    posted @ 2007-05-22 09:48 Welkin Hu 閱讀(384) | 評論 (1)編輯 收藏

    Spring和AOP像一個強力的粘合劑,將完全獨立開發的組件(或說是模塊,下同)粘合成一個有機的,完整的,可擴展的系統。正是有了這個粘合劑的幫助,才實現了比較徹底的獨立組件開發。

    說它是“比較徹底”,是因為它極大的減少了組件之間的依賴。在你開發一個組件時,基本上不會因為其它組件沒有開發完成,或出現Bug而影響到你的進度。

    但是,它并沒有完全消除開發時組件之間的依賴,你仍然得依賴于其它組件提供的API接口。為此,我們不得不把一個組件拆成兩個jar包:一個component-api.jar,一個component-impl.jar。由于api包內全是公用接口和Value Object,所以它相對穩定,可以早早的提供出來。這樣,一個組件如果要使用另一個組件的服務,在開發階段,只須依賴于api包即可。運行時,Spring再根據服務提供組件的配置信息找到正確的實現類。

     

    昨天,我們在一個討論會上發現了一個有趣的問題:

    組件UIA是一個UI組件,它要求提供一些數據,于時它把自己的要求寫時接口ProviderA中。組件C1和C2是兩個不同的業務組件,它們的UI中都有使用UIA這個組件,而它們都提供了自己的數據接口ServiceC1和ServiceC2。

    ProviderA所要求的方法,在ServiceC1和ServiceC2中都有提供。這個時候怎么做才能使各個組件完獨立呢。

    一、讓ServiceC1和ServiceC2繼承于ProviderA。但是這樣將導致業務組件依賴于UI組件。有誰知道一共有多少個UI組件需要依賴啊?而且UI組件是最易變的。

    二、把ProviderA從uia.jar抽出來,放到單獨的uia-api.jar中。這個就未免小題大做了。一個系統少說也有幾十個UI組件,難道要生成上百個jar包不成?

    三、把所有的UI的要求的API都抽出來,放到一個ui-api.jar中。這樣jar包是少了,可是單個的UI組件就失去獨立性了。

    上面三個方案,不管怎么管理UI組件的接口,都沒有解決業務組件依賴于不定數目的UI組件這個問題。

     

    最后,我們采用的方法是:把UI組件視為某個業務組件的子組件,UI組件自己不定義接口。所有對外的接口和對UI的接口,都放在業務組件的api包中。

    這樣做,業務組件和UI組件都依賴于api包,互相之間沒有依賴。當然,這樣做,UI組件就不能游離于大的業務組件之外。而我們采用這個方案的原因也在于,我們認定為多個組件提供服務的UI組件是很少的。

     

    顯然我們采用的方法只是就事論事的一個折衷方案。并沒有解決服務提供者和消費者之間的交叉依賴。

    要解決這種交叉依賴,我的思路是再提供一個接口之間的粘合機制。消費者定義自己要求的服務接口,提供者定義自己提供的服務接口。最后用一個配置文件,將二者粘合起來。

    目前,Spring還沒有提供這種功能。

    posted @ 2007-05-11 10:00 Welkin Hu 閱讀(1200) | 評論 (9)編輯 收藏

    Windows網上鄰居互訪的基本條件

    1) 雙方計算機打開,且設置了網絡共享資源;
    2) 雙方的計算機添加了 "Microsoft 網絡文件和打印共享" 服務;
    3) 雙方都正確設置了網內IP地址,且必須在一個網段中;

    4) 雙方的計算機中都關閉了防火墻,或者防火墻策略中沒有阻止網上鄰居訪問的策略。



    Windows 98/2000/XP/2003訪問XP的用戶驗證問題



    首先關于啟用Guest為什么不能訪問的問題:



    1、默認情況下,XP 禁用Guest帳戶



    2、默認情況下,XP的本地安全策略禁止Guest用戶從網絡訪問



    3、默認情況下,XP的 本地安全策略 -> 安全選項 里,"賬戶:使用空密碼用戶只能進行控制臺登錄"是啟用的,也就是說,空密碼的任何賬戶都不能從網絡訪問只能本地登錄,Guest默認空密碼......



    所以,如果需要使用Guest用戶訪問XP的話,要進行上面的三個設置:啟用Guest、修改安全策略允許Guest從網絡訪問、禁用3里面的安全策略或者給Guest加個密碼。



    有時還會遇到另外一種情況:訪問XP的時候,登錄對話框中的用戶名是灰的,始終是Guest用戶,不能輸入別的用戶帳號。



    原因是這個安全策略在作怪(管理工具 -> 本地安全策略 -> 安全選項 -> "網絡訪問:本地帳戶的共享和安全模式")。默認情況下,XP的訪問方式是"僅來賓"的方式,那么你訪問它,當然就固定為Guest不能輸入其他用戶帳號了。



    所以,訪問XP最簡單的方法就是:不用啟用Guest,僅修改上面的安全策略為"經典"就行了。別的系統訪問XP就可以自己輸入帳戶信息。



    至于訪問2003,默認情況下2003禁用Guest,但是沒有 XP 那個討厭的默認自相矛盾的來賓方式共享,所以可以直接輸入用戶名密碼訪問。



    一個小型辦公局域網,都是winxp系統,都能上外網,也能看到對方計算機,卻不能看到對方共享的計算機提示網絡路徑不正確,或你沒有權限使用網絡大概就是這個意思 我記的不太清楚!!來賓帳戶我也啟用了!winxp的防火墻也是關閉的,ip地址也沒什么問題!!



    原因:Win2000/XP中存在安全策略限制。



    有時,Win2000/XP"聰明"過了頭,雖然我們已經啟用了Guest賬戶,從Win98中卻仍然無法訪問Win2000/XP,比如使用了類似瑞星等的防火墻漏洞修補,它會修改"拒絕從網絡訪問這臺計算機"的策略,按下面的方法修改回來:



    開始 -> 運行 -> gpedit.msc -> 計算機配置 -> windows設置 -> 本地策略 -> 用戶權利分配 -> 刪除"拒絕從網絡訪問這臺計算機"中的guest用戶。



    Win2000/XP與Win98互訪



    如果兩臺電腦都使用Win2000/XP操作系統,那么組建局域網是一件非常簡單輕松的事情,當硬件連接完成后,正常情況下立即可以在"網上鄰居"中看到對方。但如果局域網中有一臺電腦使用Win98,那情況可就不一定了,我們經常會發覺雖然Ping命令可以通過,但仍然無法在"網上鄰居"中實現互訪,這時該怎么辦呢?




    對策一:在Win2000/XP中啟用Guest用戶。在Win2000/XP系統安裝之后會缺省建立兩個用戶賬戶,即Administrator(系統管理員)和Guest(來賓賬戶),所有在本地計算機沒有被分配到賬戶的用戶都將默認使用Guest賬戶,該賬戶是沒有密碼的。不過,在缺省設置下,這個Guest賬戶并未被啟用,我們可以從"控制面板|管理工具|計算機管理|本地用戶和組|用戶"中找到 "Guest"賬戶,并用鼠標右擊打開"Guest屬性"對話框,去除這里的"賬戶已停用"復選框上的對鉤標記,這樣退出后就可以從Win98中訪問到 Win2000/XP了。



    其實,啟用了Guest賬戶后,最大的好處是從Win98訪問Win2000/XP時就不需要輸入用戶名和密碼了,這種方法比較適合于用戶不確定、訪問量較大的局域網,但對家庭用戶來說并不適用。



    對策二:檢查Win2000/XP中是否存在安全策略限制。有時,Win2000/XP"聰明"過了頭,雖然我們已經啟用了Guest賬戶,從 Win98中卻仍然無法訪問Win2000/XP,這時就要從"控制面板|管理工具|本地安全策略|本地策略|用戶權利指派"中找到"從網絡訪問此計算機 "或者"拒絕從網絡訪問這臺計算機",然后檢查一下其中是否出現了Guest賬戶或者其他對應的賬戶,然后根據不同情況進行添加或者刪除即可。



    對策三:停用本地連接上的防火墻。防火墻是充當網絡與外部世界之間的保衛邊界的安全系統,微軟在WinXP中為用戶提供了一個內置的Internet連接防火墻(ICF),啟用后可以限制某些不安全信息從外部進入內部網絡。不過,如果您是在本地連接上啟用了這個防火墻,那么就會造成工作組之間無法互訪,出現"XXX無法訪問"、"您可能沒有權限使用網絡資源"、"請與這臺服務器的管理員聯系以查明您是否有訪問權限"、"找不到網絡路徑"等類似的提示,此時請停用本地連接的防火墻屏蔽。



    對策四:為WinXP添加NetBEUI協議。其實,直接添加NetBEUI協議對于解決不能互訪的問題有時反而更為簡單一些,而且它可以解決上面提到的啟用防火墻的問題。Win98安裝時會自動安裝NetBEUI協議,但由于WinXP已經不再提供對NetBEUI協議的技術支持,因此只能手工添加了。



    找出WinXP安裝光盤,進入"valueadd\Msft\Net\ Netbeui"文件夾下,這里有Nbf.sys、Netbeui.txt、Netnbf.inf共3個文件,先將Nbf.sys文件復制到本機的 "Windows\System32\Drivers"文件夾下(這里的本機指安裝了WinXP的那臺電腦),再將Netnbf.inf文件復制到本機的 "Windows\INF"文件夾下,Netbeui.txt文件可有可無。不過, INF文件夾具有隱藏屬性,用戶需要先在WinXP下的"工具|屬性"窗口中選擇顯示文件才可以看到該目錄。



    對策五:啟用 Win98中的"文件及打印機共享"。這是一個很簡單但卻經常被人忽略的問題,就是裝有Win2000/XP的機器雖然可以從"網上鄰居"中發現裝有 Win98的機器,但卻無法訪問,這是因為Win98未啟用"允許其他用戶訪問我的文件"而造成的,啟用該選項就可以解決這個問題。



    當然,除了上面提到的各種原因外,還有兩臺電腦不處于同一工作組中,或者是兩臺電腦的內部IP地址發生了沖突,甚至包括Hub故障、線路故障等。

    posted @ 2007-05-10 21:48 Welkin Hu 閱讀(572) | 評論 (0)編輯 收藏

         摘要: Powerdesigner是我最喜歡的建模軟件,其功能最全,易用性最好,使用感受最舒服。可擴展性也非常好。
    Powerdesigner對MDA的支持很靈活。其實,MDA工具所要做的事情,就是UML模型與代碼間的雙向轉換,這里面有兩個關鍵點:
    1、模型生成的代碼不能是垃圾代碼,要正確,還要符合我們所指定的編碼規范——尤其是注釋。
    2、從代碼到模型再到代碼時,原始代碼中的所有內容應當充分保留。不應發生注釋或方法體丟失。
    我根據特定的編碼規范,通過二次定制powerdeisgner的java 5語言成功實現了上述MDA特性。  閱讀全文
    posted @ 2007-05-04 15:57 Welkin Hu 閱讀(1333) | 評論 (1)編輯 收藏

    AOP的概念已經熱了很久了,我一直不太關注,也不太理解這個面向方面編程中的方面是什么意思。由于AOP和OOP僅一字之差,所以在網上看到大量的文章來拿這兩個作對比,看完后還是稀里糊涂的。

     

    這段時間開始拿Spring做新產品,于是開始仔細研究AOP。這才發現AOP和OOP講的根本不是同一類的東西。 

    AOP中的方面是指問題的一個方面,相對于問題的全部來說的。AOP就是針對問題的一個方面編程。它把一個問題(或者說是需求)從程序級別上拆分成幾個方面,讓程序員在編程時只關注自己應當關注的方面,而完全忽略其它的方面。最后由AOP框架來組合不同程序員(或者說是不同模塊)的程序。

     

    從這點上來說,AOP的確對模塊化開發有很大的裨益。



    AOP的好處,主要有兩點。
    一、完全消除了編碼時模塊之間的依賴,解決了團隊開發中一龍攔住千江水的瓶頸問題。當然,做到這一點除了AOP外,還必須做到面向接口編程。
    二、可以在任意階段,向已有功能模塊中填加新功能,且不侵入原有功能。
    posted @ 2007-04-24 12:07 Welkin Hu 閱讀(3968) | 評論 (2)編輯 收藏

    Myeclipse無疑是最優秀的Java開發平臺之一。它以年費方式銷售,標準版31.75美元,專業版52.95美元。對老美來說實在是太便宜了。但換成人民幣可就不菲。

    這里列幾個Myelipse做得好與不好的地方,供大家參考。以下為個人體驗,不代表官方意見:)

    用Myeclipse的理由:

    1. 可視化的HTML/JSP/JSF編輯器。
    2. JSP, Javascripte調試功能
    3. 良好的XML編輯器。
    4. 良好的Hibernate集成。

    在以上幾個方面,Bea workshop都有相關功能,而且界面做得非常好。可惜一來價錢太貴,二來在我的機子上出現茂名其妙的bug,所以就放棄了。

    Myeclipse使用Hibernate Tools集成了很多功能,除了HQL編輯器的集成我不滿意外,其它的都不錯。

    XML編輯器,個人一直很納悶為什么eclipse本身不提供一個這樣的插件,居然缺省用普通文本編輯器編輯XML。其它開源的XML插件都差強人意,收費倒是有一些。但僅為XML買一個插件,有點冤。Myeclipse的剛剛夠用,好!

    開源的插件中,沒有可視化的HTML/JSP/JSF編輯器。想要這個功能,只能選Myeclipse或Bea workshop了。

    再說說Myelipse做得不好的地方。

    1. UML功能,可用性很不好,沒有MDA,一些開源軟件都做得比它好。
    2. 項目粒度過細,做一個ear,至少要做三個項目:ear, war,ejb。
    3. 圖片編輯,這是個雞肋功能。
    4. 對eclipse, hibernate, spring等開源軟件的新版本支持不及時。

    UML和圖片編輯是Myelipse專業本才有的功能。如此看來,用標準版就足夠滿足我的需要。但是標準版中沒有Java script 調試功能,這個確實不爽。

    最后說說Netbeans. Netbeans 6中提供了UML功能,雖然易用性上不及Rose和Powerdesigner,但是比一般的開源UML工具好用。如果它再提供可視化的HTML/JSP開發,我就轉向Netbeans了。說來也奇怪,Netbeans支持可視化的JSF開發,卻不支持可視化的HTML/JSP開發。



    2007-4-27: 這兩天受到UML功能的吸引,再次試了一下Netbeans5.5和6.0M8。6.0M8還很不穩定,經常有些錯誤框跳出來。兩個版本都通過mavenide2這個插件支持maven。但是支持的很不好。所有的maven項目都不能單獨debug一個java class,全部要求在Junit下運行。看來還不是用netbeans的時候。

    posted @ 2007-04-18 10:05 Welkin Hu 閱讀(3216) | 評論 (5)編輯 收藏

         摘要: Insert title here 為了驗證 Hibernate 批量數據插入的性能,選擇合適的 batchsize ,我做了一個 benchmark 的測試。可是測試的結果非常奇怪。 Jdbc.batch_size 的設置對性能基本沒有影響。 ...  閱讀全文
    posted @ 2007-03-27 10:43 Welkin Hu 閱讀(4298) | 評論 (5)編輯 收藏

     

    ejb-jar.xml in ejb/META-INF

     

    <session >
    ... ...

    <resource-ref>
    <res-ref-name>XPCDataSource</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Application</res-auth>
    <res-sharing-scope>Shareable</res-sharing-scope>
    </resource-ref>

    </session>

     

    jboss.xml in ejb/META-INF

     

    <?xml version="1.0"?>
    <!DOCTYPE jboss PUBLIC
    "-//JBoss//DTD JBOSS 3.0//EN"
    ">

    <jboss>
    <enterprise-beans>
    <session>
    <ejb-name>CacheDemo1</ejb-name>
    <jndi-name>ejb/CacheDemo1</jndi-name>
    <local-jndi-name>ejb/CacheDemo1Local</local-jndi-name>
    <resource-ref>
    <res-ref-name>XPCDataSource</res-ref-name>
    <jndi-name>java:/XPCDataSource</jndi-name>
    </resource-ref>
    </session>
    </enterprise-beans>
    </jboss>

     

    web.xml  in web/WEB-INF

    <resource-ref>
    <res-ref-name>XPCDataSource</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Application</res-auth>
    <res-sharing-scope>Shareable</res-sharing-scope>
    </resource-ref>

     

    jboss-web.xml in web/WEB-INF

    <resource-ref>
    <res-ref-name>XPCDataSource</res-ref-name>
    <jndi-name>java:/XPCDataSource</jndi-name>
    </resource-ref>

     

    創建Data Source

    Context c = new InitialContext();
    Object obj = c.lookup("java:comp/env/XPCDataSource");
    DataSource ds = (DataSource)narrow(obj, DataSource.class);
    connection = ds.getConnection();

     

    取得Transaction

    //context is javax.ejb.SessionContext

    //Transaction should be getten from EJB

    UserTransaction tx = context.getUserTransaction();

     

    Webspere deployer will change ejb-jar.xml. Never put struts to Webspere/lib/ext

    posted @ 2007-03-07 09:51 Welkin Hu 閱讀(515) | 評論 (0)編輯 收藏

    這兩天因為想測試一下群集Cache,用Myeclipse 建了一個測試程序,快把我折騰死了。

    在Myeclipse的設計中,Project的粒度很細。EAR Project, WAR Project, 和EJB Project是三個不同的Project。它不支持EAR Project包打天下不太一樣。

    我按照這個要求,創建了四個項目:EAR, WAR, EJB和一個公用的Pojo Project。

    公司剛剛換用了SubVersion首先涮了我一把。Subeclipse 1.0.1只認一個項目一個項目的check out。一下子把我的四個項目合并成一個什么都不是的大項目。 我只好把這個大項目關掉,再一個一個的導入進來。

    可是碰在新建Subversion庫的當口上,項目的服務器路徑變動了好幾次。每次都要我這么弄幾下。迫不得已,裝上TortoiseSVN-1.4.3。這東西爽!可以一下子把四個項目全取下來,而且不破壞eclipse項目結構。

    然而,當我打開eclipse,又碰到一個經典問題: subeclipse 1.0.1和TortoiseSVN-1.4.3不兼容,報告說我的subversion客戶端太老(其實是它自己老了),直接罷工了。

    左找右找,終于發現有人說subeclipse 1.1.6搞定了這個問題。于是升級,搞定了這個問題。

    ?

    要說Myeclipse對于EJB和JSP的支持確實漂亮,輕輕松松的就開發完成了。部署并初步運行也是成功的。

    只有一個美中不足:它生成的war包和jar包不能指定名字。在EAR的.mymetadata中,有這么一段配置:

    < project-modules >
    < project-module
    type ="WEB"
    name
    ="Cache?Web"
    id
    ="myeclipse.1171417787608"
    context-root
    ="/cache"
    j2ee-spec
    ="1.4"
    archive
    ="Cache?Web.war" >
    < attributes >
    < attribute? name ="webrootdir" ?value ="/root" ? />
    </ attributes >
    </ project-module >
    < project-module
    type ="EJB"
    name
    ="Cache?Ejb"
    id
    ="myeclipse.1171417692847"
    j2ee-spec
    ="1.4"
    archive
    ="Cache?Ejb.jar" ? />
    </ project-modules >

    ?

    包名中帶空格可不是我的風格。我嘗試修改上面的archive屬性。但是最后生成的EAR中,包名還是照舊。很有可能archive屬性根本就沒有作用。Myeclipse簡單的拿工程名做包名。

    ?

    沒辦法,將就過吧。繼續測試。Pojo是個單獨的Hibernate Pojo項目。EJB和JSP都有引用到。

    在EJB中,調用Pojo得到一個List,里面的元素是Order對象。在EJB中從Object轉成Order成功。但在JSP中轉型時,碰到一個極為古怪的問題:ClassCastException。

    調用EJB得到List都成功了,可怎么從中轉出Order對象會出問題呢?打開Debug看看,List中的確是Order對象啊!太古怪了!

    沒救了,死馬當活馬醫吧。把遠程EJB調用改成本地EJB調用——問題照舊!檢查所有配置文件,都簡單得不可能出問題啊!

    ……神啊,救救我吧。

    最后,在檢查部署后的文件時發現了問題。WAR包和EJB包各自把Pojo項目中的所有classs合并了進來。這樣在一個EAR中,每個pojo的class都有兩份。JSP和EJB各引用各的,從而導致了類型不匹配。

    問題的原因在于Myeclipse中指定的部署方法不對。為了省事,我在WAR和EJB的部署配置中,都選擇了“Merge dependent Java Project Delopyment"。如下圖所示。

    將部署配置改為Ignore之后,然后手工將pojo包放到jboss server的lib中,問題終于解決了。

    可是這樣一來,每次我都得手工的部署pojo包。在EAR的配置中有一個"Jar dependent Java projects"。選中它,并且在引用項目中選中Pojo項目。Myeclipse就會自動將Pojo包部署到EAR中。

    然而,它部署是部署了,沒把人家放到classpath中去,一運行就報錯:ClassNotFound。這個問題好解決,在EJB和WAR的MANIFEST.MF中加入classpath就可以了。

    一開始我用的是pojo.jar這個名字,放到classpath中后運行成功。

    可是Myeclipse在每次自動生成pojo包時,給的是工程名"cache pojo.jar",里面有個空格。classpath死活不認識它,用引號引起來也不行。

    問題到了最后,還是沒有圓滿解決——早知今日,我還不如直接用個ant building呢!

    posted @ 2007-02-16 16:15 Welkin Hu 閱讀(2855) | 評論 (3)編輯 收藏

    登錄及任意操作,70%出現無效用戶請求

    每次點“信用卡”,有90%概率出現下面的問題。

     

    銀行軟件,安全固然重要。可是這樣的可用性,拿出來不嫌丟人嗎?

     

    我的瀏覽器這么大,可它出來的“疑難解答”只用了那么一點點,還搞了個滾動條。真是笨得可以啊。

    posted @ 2007-02-08 16:52 Welkin Hu 閱讀(890) | 評論 (0)編輯 收藏

     

    http://www.wujianrong.com/archives/2006/11/jdbc.ht...

    posted @ 2007-02-08 10:38 Welkin Hu 閱讀(306) | 評論 (0)編輯 收藏

    Right-click contex menu doesn't work
    http://www.myeclipseide.com/index.php?name=PNphpBB2&file=viewtopic&t=15728

    http://www.eclipseworld.org/bbs/read.php?tid=9920

    This is a known problem when installing the 5.1 release of MYEclipse into an install of Eclipse that has the JST and WST plugins already installed (it supreceedes our versions of the plugin that need to get loaded).

    The workaround is to load the manage configuration dialog from Help > Software Updates > Mangae Configuration. Then find the JST and WST plugins from your Eclipse install (probably under WTP) and disable them, then restart.

    posted @ 2007-02-01 09:15 Welkin Hu 閱讀(639) | 評論 (0)編輯 收藏

    目前Java IDE的主流自然是eclipse系列,我一直用的也是這個。在Sun積極宣傳Netbeans5.5的時候,我也試用了一下,并沒有找到從eclipse轉移過去的理由。我對它的不滿意主要有兩點:
    1、沒有所見即所得的JSP/HTML編輯器。
    2、沒有為Hibernate提供開發支持。
    Netbeans5.5在java 6下的桌面開發能力很強,不過短期內我還用不上。

    下面重點說說Eclipse平臺下的一些開發工具。

    1、JSP/HTML編輯工具
    Lomboz是開源的JSP編輯器,不過它不支持所見即所得的可視化編輯。雖然我并不喜歡在可視化設計界面中通過拖拉來調整頁面。但是它對代碼的快速定位是我所需要的。
    Bea Workshop for JSP的確精彩,不過它要求把所有的JSP一個WEB-INF的目錄。我的項目很大,每個模塊都有獨立的JSP目錄,這個要求很煩的。好像這個目錄可以配置(但是必須有),不過由于其它原因,我已經放棄了。
    我現在選的是MyEclipse,它的JSP編輯器做得不如Bea Workshop精細和強大,但是自由,夠用。另外,MyEclipse比Bea Workshop便宜得多,有可能說服老板買單。不過,MyEclipse集成的Hibernate功能著實讓我光火了很長的時間。

    2. Hibernate集成工具
    在Eclipse中集成Hibernate開發的有三種:Hibernate官方出的Hibernate Tools, Myeclipse和Bea Workshop。Jbuilder 2007也部分支持Hibernate。Hibernate Tools是開源的,其它的工具都是在它的基礎上進行增強而來的。

    如果使用Ant命令來操作Hibernate Tools,你會發現它非常強大,可以靈活的在表,HBM和pojo間互相轉換。可是它的Eclipse集成太狠了點,只要求一個逆向工程的配置文件,就可以根據數據庫表生成所有的HBM和pojo。這個功能貌似一步到位,其實很不靈活。
    (1)如何寫好HBM是很有學問的,我經常需要細心的調理好HBM再生成pojo。
    (2)每次生成時都一刀切的做法對于增量開發來說是個災難。好不容易調理好的HBM和Pojo,一下子全被沖掉了。
    (3)它的數據庫連接也有個問題,不會過濾Schema,每次都把所有的數據庫列出來。我們的開發數據庫服務器上安裝有三四十個數據庫,想想多么恐怖啊。
    Hibernate Tools最強的功能,當數HQL編輯器。可以查錯,可以檢查最終生成的SQL,可以得到運行結果,可以添加參數。這些功能實在是太有用了。

    Myeclipse對Hibernate Tools進行了改進。所以它和原生的Hibernate Tools共存時會發生一些奇怪的問題。Myeclipse中有兩個改進非常棒:指定數據庫Schema(再也不用在三四個數據庫中找我的那份試驗田了),根據選中的HBM生成Pojo(放心大膽的用吧,已經做好的HBM和Pojo不會再被沖掉了)。
    不過,Myeclipse對HQL編輯器的改進就有點讓人光火了。首先是連接問題,橫豎就是連不上數據庫,左找右找找不到原因,最后把Eclipse workspace重建,把相同的配置連接,一下子又可以了。
    其次,Myeclipse沒有提供新建HQL編輯器的菜單,而是在我手工建立一個hql的文件后,在打開它時調用HQL編輯器!打開的過程可能涉及到數據庫連接,非常慢。如果你在退出eclipse中沒有關掉HQL文件,那么再次進入eclipse的時候,您先去喝杯茶,慢慢等吧。

    Bea Workshop各方面做得都非常精致,Hiberenate集成也不例外,各類編輯器的功能布局明了易用。但是我在試用時碰到一個難以置信的致命的bug:所有Bea Workshop編輯器和對話框中的文本輸入框基本不接收光標!
    這是什么概念?就是說你沒法點進文本框,沒法輸入任何東西。我唯一成功的一次是在沒有光標的情況下,亂打了幾個字母再回車。對話框沒有顯示任何東西直接關閉,但在主編輯器中我打的字母顯示了出來。不過除了文本框外,其它的如下拉框,選擇框都正常。
    哪個開發人員會出這么離譜的Bug啊!我試過兩臺機,問題一模一樣。難道是因為我的JDK是1.5的緣故?!
    不管什么原因,我是沒辦法再試下去了,只好將其請出了我的電腦。在請出之前,通過菜單檢查,沒有發現指定HBM生成Pojo的功能。這兩大原因,足夠我放棄它了。

    Jbuilder 2007做得太強了。我用它明顯感覺小腳穿大鞋。人家根本不希罕Hibernate。僅僅把Hiberenate作為EJB 3.0和JPA的一種實現方式。所以根據沒有HBM這一說。而且是徹頭徹尾的可視化MDA開發。真的需要一個明星團隊,在嚴格的流程支持下,才能玩轉Jbuilder 2007。我兩個條件都不符合,最重要的是老板嫌它太貴,只能放棄。

    Technorati : , , , ,

    posted @ 2007-01-28 17:27 Welkin Hu 閱讀(1014) | 評論 (3)編輯 收藏

    最近正在做JDO 2.0與Hibernate的方案選擇。JDO實現選的是Jpox,個別問題也參看了Bea Kodo 4.1。但是今天發現JDO2.0在一項關鍵功能上無法滿足要求,有可能被直接叫停。

    這個功能就是動態O/R Mapping。就是說,在系統運行時,動態生成一份新的O/R Mapping,或者往原來的O/R Mapping中添加字段。并且這些改動,應當無須重啟Application Server就能生效。

    Hibernate雖然也沒有很好的支持這一點,但是提供了可實現的渠道。

    1. 重建SessionFactory時可以添加新的Mapping文件。

    2. Dynamic Component可以在pojo中將動態字段表達為Map,這樣只用修改Mapping文件,不用修改java類。

    3. Hibernate 3.2.1還提供不用java類的Mapping方式。在Mapping文件中,只指定entity-name,不指定class,Hiberante就會使用Map來表達它。

    Jpox沒有提供上面三種渠道中的任何一種。我已經在Jpox forum上發貼問了,不知道什么時候能有答復。

    Kodo的文檔中也沒有直接提到,本想去bea發貼的,但是網速太慢。

    posted @ 2007-01-24 10:50 Welkin Hu 閱讀(682) | 評論 (0)編輯 收藏

    一直以為,在Hiberenate中用多對一關系表達外鍵,并設置為延遲加載時,Hibernate不會在查主表時去查引用表。今天的測試卻發現不是這么回事。

    我定義了一個Topic類,其中有一個外鍵引用Company類:

    ?

    < many-to-one? name ="company" ?class ="Company" ?lazy ="no-proxy" >
    < column? name ="COMPANY" ?length ="32" ? />
    </ many-to-one >

    ?

    測試HQL如下:select id, company from Topic

    而我期望的SQL應當是這樣:select boid, company from DT_TOPIC.

    結果Hiberate Tools 生成的SQL是這樣:

    ?

    select
    topic0_.BOID?
    as ?col_0_0_,
    topic0_.COMPANY?
    as ?col_1_0_,
    company1_.COMPID?
    as ?COMPID409_,
    company1_.COMPNAME?
    as ?COMPNAME409_,
    company1_.DESCRIPTION?
    as ?DESCRIPT3_409_,
    company1_.STATUS?
    as ?STATUS409_?
    from
    DT_TOPIC?topic0_?
    inner ? join
    XPC_COMPANY?company1_?
    on ?topic0_.COMPANY = company1_.COMPID

    ?

    Hibernate生成的SQL多做了兩件影響性能的事情:

    1, 與XPC_COMPANY進行inner join。

    2,把XPC_COMPANY中的所有字段全取出來了。

    這樣還叫什么延遲加載啊?

    ?

    哪位高手能告訴我這是為什么?

    posted @ 2007-01-17 21:54 Welkin Hu 閱讀(3023) | 評論 (4)編輯 收藏

    Java 5.0發布了,許多人都將開始使用這個JDK版本的一些新增特性。從增強的for循環到諸如泛型(generic)之類更復雜的特性,都將很快出現在您所編寫的代碼中。我們剛剛完成了一個基于Java 5.0的大型任務,而本文就是要介紹我們使用這些新特性的體驗。本文不是一篇入門性的文章,而是對這些特性以及它們所產生的影響的深入介紹,同時還給出了一些在項目中更有效地使用這些特性的技巧。

    簡介
      在JDK 1.5的beta階段,我們為BEA的Java IDE開發了一個Java 5編譯器。因為我們實現了許多新特性,所以人們開始以新的方式利用它們;有些用法很聰明,而有些用法明顯應該被列入禁用清單。編譯器本身使用了新的語言特性,所以我們也獲得了使用這些特性維護代碼的直接體驗。本文將介紹其中的許多特性和使用它們的體驗。
      我們假定您已經熟悉了這些新特性,所以不再全面介紹每個特性,而是談論一些有趣的、但很可能不太明顯的內容和用法。這些技巧出自我們的實際體驗,并大致按照語言特性進行了分類。
      我們將從最簡單的特性開始,逐步過渡到高級特性。泛型所包含的內容特別豐富,因此占了本文一半的篇幅。

    增強的for循環
      為了迭代集合和數組,增強的for循環提供了一個簡單、兼容的語法。有兩點值得一提:

    Init表達式
      在循環中,初始化表達式只計算一次。這意味著您通常可以移除一個變量聲明。在這個例子中,我們必須創建一個整型數組來保存computeNumbers()的結果,以防止每一次循環都重新計算該方法。您可以看到,下面的代碼要比上面的代碼整潔一些,并且沒有泄露變量numbers:
    未增強的For:
    


    int?sum?=?0;
    Integer[]?numbers?
    =?computeNumbers();
    for?(int?i=0;?i?<?numbers.length?;?i++)
    ????sum?
    +=?numbers[i];
    增強后的For:
    int?sum?=?0;

    for?(?int?number:?computeNumbers()?)
    ????sum?
    +=?number;


    局限性

    有時需要在迭代期間訪問迭代器或下標,看起來增強的for循環應該允許該操作,但事實上不是這樣,請看下面的例子:

    for?(int?i=0;?i?<?numbers.length?;?i++)?{
    ????
    if?(i?!=?0)?System.out.print(",");
    ????System.out.print(numbers[i]);
    }

      我們希望將數組中的值打印為一個用逗號分隔的清單。我們需要知道目前是否是第一項,以便確定是否應該打印逗號。使用增強的for循環是無法獲知這種信息的。我們需要自己保留一個下標或一個布爾值來指示是否經過了第一項。   這是另一個例子:

    for?(Iterator<integer>?it?=?n.iterator()?;?it.hasNext()?;?)
    ????
    if?(it.next()?<?0)
    ????????it.remove();

      在此例中,我們想從整數集合中刪除負數項。為此,需要對迭代器調用一個方法,但是當使用增強的for 循環時,迭代器對我們來說是看不到的。因此,我們只能使用Java 5之前版本的迭代方法。   順便說一下,這里需要注意的是,由于Iterator是泛型,所以其聲明是Iterator<Integer>。許多人都忘記了這一點而使用了Iterator的原始格式。

    注釋
      注釋處理是一個很大的話題。因為本文只關注核心的語言特性,所以我們不打算涵蓋它所有的可能形式和陷阱。  我們將討論內置的注釋(SuppressWarnings,Deprecated和Override)以及一般注釋處理的局限性。

    Suppress Warnings
      該注釋關閉了類或方法級別的編譯器警告。有時候您比編譯器更清楚地知道,代碼必須使用一個被否決的方法或執行一些無法靜態確定是否類型安全的動作,而使用:

    @SuppressWarnings("deprecation")
    public?static?void?selfDestruct()?{
    ????Thread.currentThread().stop();
    }

      這可能是內置注釋最有用的地方。遺憾的是,1.5.0_04的javac不支持它。但是1.6支持它,并且Sun正在努力將其向后移植到1.5中。
    Eclipse 3.1中支持該注釋,其他IDE也可能支持它。這允許您把代碼徹底地從警告中解脫出來。如果在編譯時出現警告,可以確定是您剛剛把它添加進來——以幫助查看那些可能不安全的代碼。隨著泛型的添加,它使用起來將更趁手。

    Deprecated
      遺憾的是,Deprecated沒那么有用。它本來旨在替換@deprecated javadoc標簽,但是由于它不包含任何字段,所以也就沒有方法來建議deprecated類或方法的用戶應該使用什么做為替代品。大多數用法都同時需要javadoc標簽和這個注釋。

    Override
      Override表示,它所注釋的方法應該重寫超類中具有相同簽名的方法:

    @Override
    public?int?hashCode()?{
    ????
    }

      看上面的例子,如果沒有在hashCode中將“C”大寫,在編譯時不會出現錯誤,但是在運行時將無法像期望的那樣調用該方法。通過添加Override標簽,編譯器會提示它是否真正地執行了重寫。
      在超類發生改變的情況中,這也很有幫助。如果向該方法中添加一個新參數,而且方法本身也被重命名了,那么子類將突然不能編譯,因為它不再重寫超類的任何東西。

    其它注釋
      注釋在其他場景中非常有用。當不是直接修改行為而是增強行為時,特別是在添加樣板代碼的情況下,注釋在諸如EJB和Web services這樣的框架中運行得非常好。
    注釋不能用做預處理器。Sun的設計特別預防了完全因為注釋而修改類的字節碼。這樣可以正確地理解該語言的成果,而且IDE之類的工具也可以執行深入的代碼分析和重構之類的功能。
    注釋不是銀彈。第一次遇到的時候,人們試圖嘗試各種技巧。請看下面這個從別人那里獲得的建議:

    public?class?Foo?{
    ?
    ????@Property
    ????
    private?int?bar;
    ?
    }

      其思想是為私有字段bar自動創建getter和setter方法。遺憾的是,這個想法有兩個失敗之處:1)它不能運行,2)它使代碼難以閱讀和處理。   它是無法實現的,因為前面已經提到了,Sun特別阻止了對出現注釋的類進行修改。
      即使是可能的,它也不是一個好主意,因為它使代碼可讀性差。第一次看到這段代碼的人會不知道該注釋創建了方法。此外,如果將來您需要在這些方法內部執行一些操作,注釋也是沒用的。   總之,不要試圖用注釋去做那些常規代碼可以完成的事情。

    枚舉
      enum非常像public static final int聲明,后者作為枚舉值已經使用了很多年。對int所做的最大也是最明顯的改進是類型安全——您不能錯誤地用枚舉的一種類型代替另一種類型,這一點和int不同,所有的int對編譯器來說都是一樣的。除去極少數例外的情況,通常都應該用enum實例替換全部的枚舉風格的int結構。
      枚舉提供了一些附加的特性。EnumMap和EnumSet這兩個實用類是專門為枚舉優化的標準集合實現。如果知道集合只包含枚舉類型,那么應該使用這些專門的集合來代替HashMap或HashSet。
      大部分情況下,可以使用enum對代碼中的所有public static final int做插入替換。它們是可比的,并且可以靜態導入,所以對它們的引用看起來是等同的,即使是對于內部類(或內部枚舉類型)。注意,比較枚舉類型的時候,聲明它們的指令表明了它們的順序值。

    “隱藏的”靜態方法
      兩個靜態方法出現在所有枚舉類型聲明中。因為它們是枚舉子類上的靜態方法,而不是Enum本身的方法,所以它們在java.lang.Enum的javadoc中沒有出現。
      第一個是values(),返回一個枚舉類型所有可能值的數組。
      第二個是valueOf(),為提供的字符串返回一個枚舉類型,該枚舉類型必須精確地匹配源代碼聲明。
    方法
      關于枚舉類型,我們最喜歡的一個方面是它可以有方法。過去您可能需要編寫一些代碼,對public static final int進行轉換,把它從數據庫類型轉換為JDBC URL。而現在則可以讓枚舉類型本身帶一個整理代碼的方法。下面就是一個例子,包括DatabaseType枚舉類型的抽象方法以及每個枚舉實例中提供的實現:

    public?enum??DatabaseType?{
    ??ORACLE?
    {
    ??
    public?String?getJdbcUrl()?{}
    ??}
    ,
    ??MYSQL?
    {
    ??
    public?String?getJdbcUrl()?{}
    ??}
    ;
    ??
    public?abstract?String?getJdbcUrl();
    ??}
      現在枚舉類型可以直接提供它的實用方法。例如:

    DatabaseType dbType = ...;
    String jdbcURL = dbType.getJdbcUrl();

      要獲取URL,必須預先知道該實用方法在哪里。


    可變參數(Vararg)
      正確地使用可變參數確實可以清理一些垃圾代碼。典型的例子是一個帶有可變的String參數個數的log方法:

    Log.log(String?code)
    Log.log(String?code,??String?arg)
    Log.log(String?code,??String?arg1,?String?arg2)
    Log.log(String?code,??String[]?args)
      當討論可變參數時,比較有趣的是,如果用新的可變參數替換前四個例子,將是兼容的:
    Log.log(String code, String... args)
      所有的可變參數都是源兼容的——那就是說,如果重新編譯log()方法的所有調用程序,可以直接替換全部的四個方法。然而,如果需要向后的二進制兼容性,那么就需要舍去前三個方法。只有最后那個帶一個字符串數組參數的方法等效于可變參數版本,因此可以被可變參數版本替換。

    類型強制轉換

      如果希望調用程序了解應該使用哪種類型的參數,那么應該避免用可變參數進行類型強制轉換。看下面這個例子,第一項希望是String,第二項希望是Exception:
    Log.log(Object??objects)?{
    ????String?message?
    =?(String)objects[0];
    ????
    if?(objects.length?>?1)?{
    ????????Exception?e?
    =?(Exception)objects[1];
    ????????
    //?Do?something?with?the?exception
    ????}

    }
      方法簽名應該如下所示,相應的可變參數分別使用String和Exception聲明:

    Log.log(String message, Exception e, Object... objects) {...}

      不要使用可變參數破壞類型系統。需要強類型化時才可以使用它。對于這個規則,PrintStream.printf()是一個有趣的例外:它提供類型信息作為自己的第一個參數,以便稍后可以接受那些類型。

    協變返回

      協變返回的基本用法是用于在已知一個實現的返回類型比API更具體的時候避免進行類型強制轉換。在下面這個例子中,有一個返回Animal對象的Zoo接口。我們的實現返回一個AnimalImpl對象,但是在JDK 1.5之前,要返回一個Animal對象就必須聲明。:
    public?interface?Zoo??{
    ????
    public?Animal?getAnimal();
    }

    public?class?ZooImpl??implements?Zoo?{
    ??
    public?Animal?getAnimal(){
    ?????
    return?new?AnimalImpl();
    ??}

    }
      協變返回的使用替換了三個反模式:

    • 直接字段訪問。為了規避API限制,一些實現把子類直接暴露為字段:

    ZooImpl._animal

    • 另一種形式是,在知道實現的實際上是特定的子類的情況下,在調用程序中執行向下轉換:

    ((AnimalImpl)ZooImpl.getAnimal()).implMethod();

    • 我看到的最后一種形式是一個具體的方法,該方法用來避免由一個完全不同的簽名所引發的問題:

    ZooImpl._getAnimal();

      這三種模式都有它們的問題和局限性。要么是不夠整潔,要么就是暴露了不必要的實現細節。

    協變

      協變返回模式就比較整潔、安全并且易于維護,它也不需要類型強制轉換或特定的方法或字段:
    public AnimalImpl getAnimal(){
    return new AnimalImpl();
    }
      使用結果:
    ZooImpl.getAnimal().implMethod();

    使用泛型
      
    我們將從兩個角度來了解泛型:使用泛型和構造泛型。我們不討論List、Set和Map的顯而易見的用法。知道泛型集合是強大的并且應該經常使用就足夠了。
      我們將討論泛型方法的使用以及編譯器推斷類型的方法。通常這些都不會出問題,但是當出問題時,錯誤信息會非常令人費解,所以需要了解如何修復這些問題。

    泛型方法
      
    除了泛型類型,Java 5還引入了泛型方法。在這個來自java.util.Collections的例子中,構造了一個單元素列表。新的List的元素類型是根據傳入方法的對象的類型來推斷的:
    static <T> List<T> Collections.singletonList(T o)
    示例用法:
    public List<Integer> getListOfOne() {
        return Collections.singletonList(1);
    }

      在示例用法中,我們傳入了一個int。所以方法的返回類型就是List<Integer>。編譯器把T推斷為Integer。這和泛型類型是不同的,因為您通常不需要顯式地指定類型參數。
    這也顯示了自動裝箱和泛型的相互作用。類型參數必須是引用類型:這就是為什么我們得到的是List<Integer>而不是List<int>。

    不帶參數的泛型方法
      
    emptyList()方法與泛型一起引入,作為java.util.Collections中EMPTY_LIST字段的類型安全置換:
    static <T> List<T> Collections.emptyList()
    示例用法: 
    public List<Integer> getNoIntegers() {
        return Collections.emptyList();
    }

      與先前的例子不同,這個方法沒有參數,那么編譯器如何推斷T的類型呢?基本上,它將嘗試使用一次參數。如果沒有起作用,它再次嘗試使用返回或賦值類型。在本例中,返回的是List<Integer>,所以T被推斷為Integer。
      如果在返回語句或賦值語句之外的位置調用泛型方法會怎么樣呢?那么編譯器將無法執行類型推斷的第二次傳送。在下面這個例子中,emptyList()是從條件運算符內部調用的:

    public List<Integer> getNoIntegers() {
        return x ? Collections.emptyList() : null;
    }

      因為編譯器看不到返回上下文,也不能推斷T,所以它放棄并采用Object。您將看到一個錯誤消息,比如:“無法將List<Object>轉換為List<Integer>。”
    為了修復這個錯誤,應顯式地向方法調用傳遞類型參數。這樣,編譯器就不會試圖推斷類型參數,就可以獲得正確的結果:

    return x ? Collections.<Integer>emptyList() : null;

      這種情況經常發生的另一個地方是在方法調用中。如果一個方法帶一個List<String>參數,并且需要為那個參數調用這個傳遞的emptyList(),那么也需要使用這個語法。

    集合之外
      這里有三個泛型類型的例子,它們不是集合,而是以一種新穎的方式使用泛型。這三個例子都來自標準的Java庫:
    • Class<T>
      Class在類的類型上被參數化了。這就使無需類型強制轉換而構造一個newInstance成為可能。
    • Comparable<T>
      Comparable被實際的比較類型參數化。這就在compareTo()調用時提供了更強的類型化。例如,String實現Comparable<String>。對除String之外的任何東西調用compareTo(),都會在編譯時失敗。
    • Enum<E extends Enum<E>>
      Enum被枚舉類型參數化。一個名為Color的枚舉類型將擴展Enum<Color>。getDeclaringClass()方法返回枚舉類型的類對象,在這個例子中就是一個Color對象。它與getClass()不同,后者可能返回一個無名類。
    通配符
      
    泛型最復雜的部分是對通配符的理解。我們將討論三種類型的通配符以及它們的用途。
      首先讓我們了解一下數組是如何工作的。可以從一個Integer[]為一個Number[]賦值。如果嘗試把一個Float寫到Number[]中,那么可以編譯,但在運行時會失敗,出現一個ArrayStoreException:
    Integer[] ia = new Integer[5];
    Number[] na = ia;
    na[0] = 0.5; // compiles, but fails at runtime
    如果試圖把該例直接轉換成泛型,那么會在編譯時失敗,因為賦值是不被允許的:
    List<Integer> iList = new ArrayList<Integer>();
    List<Number> nList = iList; // not allowed
    nList.add(0.5);

      如果使用泛型,只要代碼在編譯時沒有出現警告,就不會遇到運行時ClassCastException。

    上限通配符
      我們想要的是一個確切元素類型未知的列表,這一點與數組是不同的。
    List<Number>是一個列表,其元素類型是具體類型Number。
    List<? extends Number>是一個確切元素類型未知的列表。它是Number或其子類型。

    上限
      
    如果我們更新初始的例子,并賦值給List<? extends Number>,那么現在賦值就會成功了:

    List<Integer> iList = new ArrayList<Integer>();
    List<? extends Number> nList = iList;
    Number n = nList.get(0);
    nList.add(0.5); // Not allowed

      我們可以從列表中得到Number,因為無論列表的確切元素類型是什么(Float、Integer或Number),我們都可以把它賦值給Number。
      我們仍然不能把浮點類型插入列表中。這會在編譯時失敗,因為我們不能證明這是安全的。如果我們想要向列表中添加浮點類型,它將破壞iList的初始類型安全——它只存儲Integer。
      通配符給了我們比數組更多的表達能力。

    為什么使用通配符
      在下面這個例子中,通配符用于向API的用戶隱藏類型信息。在內部,Set被存儲為CustomerImpl。而API的用戶只知道他們正在獲取一個Set,從中可以讀取Customer。
    此處通配符是必需的,因為無法從Set<CustomerImpl>向Set<Customer>賦值:
    public class CustomerFactory {
        private Set<CustomerImpl> _customers;
        public Set<? extends Customer> getCustomers() {
            return _customers;
        }
    }

    通配符和協變返回
      通配符的另一種常見用法是和協變返回一起使用。與賦值相同的規則可以應用到協變返回上。如果希望在重寫的方法中返回一個更具體的泛型類型,聲明的方法必須使用通配符:

    public interface NumberGenerator {
        public List<? extends Number> generate();
    }
    public class FibonacciGenerator extends NumberGenerator {
        public List<Integer> generate() {
            ...
        }
    }

      如果要使用數組,接口可以返回Number[],而實現可以返回Integer[]。

    下限
      我們所談的主要是關于上限通配符的。還有一個下限通配符。List<? super Number>是一個確切“元素類型”未知的列表,但是可能是Mnumber,或者Number的超類型。所以它可能是一個List<Number>或一個List<Object>。
      下限通配符遠沒有上限通配符那樣常見,但是當需要它們的時候,它們就是必需的。

    下限與上限
    List<? extends Number> readList = new ArrayList<Integer>();
    Number n = readList.get(0);
    
    List<? super Number> writeList = new ArrayList<Object>();
    writeList.add(new Integer(5));

      第一個是可以從中讀數的列表。
      第二個是可以向其寫數的列表。

    無界通配符
      最后,List<?>列表的內容可以是任何類型,而且它與List<? extends Object>幾乎相同。可以隨時讀取Object,但是不能向列表中寫入內容。

    公共API中的通配符
      總之,正如前面所說,通配符在向調用程序隱藏實現細節方面是非常重要的,但即使下限通配符看起來是提供只讀訪問,由于remove(int position)之類的非泛型方法,它們也并非如此。如果您想要一個真正不變的集合,可以使用java.util.Collection上的方法,比如unmodifiableList()。
      編寫API的時候要記得通配符。通常,在傳遞泛型類型時,應該嘗試使用通配符。它使更多的調用程序可以訪問API。
      通過接收List<? extends Number>而不是List<Number>,下面的方法可以由許多不同類型的列表調用:

    void removeNegatives(List<? extends Number> list);

    構造泛型類型
      現在我們將討論構造自己的泛型類型。我們將展示一些例子,其中通過使用泛型可以提高類型安全性,我們還將討論一些實現泛型類型時的常見問題。

    集合風格(Collection-like)的函數
      第一個泛型類的例子是一個集合風格的例子。Pair有兩個類型參數,而且字段是類型的實例:

    public final class Pair<A,B> {
        public final A first;
        public final B second;
    
        public Pair(A first, B second) {
            this.first = first;
            this.second = second;
        }
    }

      這使從方法返回兩個項而無需為每個兩種類型的組合編寫專用的類成為可能。另一種方法是返回Object[],而這樣是類型不安全或者不整潔的。
    在下面的用法中,我們從方法返回一個File和一個Boolean。方法的客戶端可以直接使用字段而無需類型強制轉換:

    public Pair<File,Boolean> getFileAndWriteStatus(String path){
        // create file and status
        return new Pair<File,Boolean>(file, status);
    }
    
    Pair<File,Boolean> result = getFileAndWriteStatus("...");
    File f = result.first;
    boolean writeable = result.second;

    集合之外
      在下面這個例子中,泛型被用于附加的編譯時安全性。通過把DBFactory類參數化為所創建的Peer類型,您實際上是在強制Factory子類返回一個Peer的特定子類型:

    public abstract class DBFactory<T extends DBPeer> {
        protected abstract T createEmptyPeer();
        public List<T> get(String constraint) {
            List<T> peers = new ArrayList<T>();
            // database magic
            return peers;
        }
    }
    通過實現DBFactory<Customer>,CustomerFactory必須從createEmptyPeer()返回一個Customer:
    public class CustomerFactory extends DBFactory<Customer>{
    
        public Customer createEmptyPeer() {
            return new Customer();
        }
    }

    泛型方法
      不管想要對參數之間還是參數與返回類型之間的泛型類型施加約束,都可以使用泛型方法:
      例如,如果編寫的反轉函數是在位置上反轉,那么可能不需要泛型方法。然而,如果希望反轉返回一個新的List,那么可能會希望新List的元素類型與傳入的List的類型相同。在這種情況下,就需要一個泛型方法:


    <T> List<T> reverse(List<T> list)

    具體化
      當實現一個泛型類時,您可能想要構造一個數組T[]。因為泛型是通過擦除(erasure)實現的,所以這是不允許的。
      您可以嘗試把Object[]強制轉換為T[]。但這是不安全的。

    具體化解決方案
      
    按照泛型教程的慣例,解決方案使用的是“類型令牌”,通過向構造函數添加一個Class<T>參數,可以強制客戶端為類的類型參數提供正確的類對象:
    public class ArrayExample<T> {
        private Class<T> clazz;
    
        public ArrayExample(Class<T> clazz) {
            this.clazz = clazz;
        }
    
        public T[] getArray(int size) {
            return (T[])Array.newInstance(clazz, size);
        }
    }

      為了構造ArrayExample<String>,客戶端必須把String.class傳遞給構造函數,因為String.class的類型是Class<String>。
    擁有類對象使構造一個具有正確元素類型的數組成為可能。

    結束語
      總而言之,新的語言特性有助于從根本上改變Java。通過了解在什么場景下使用以及如何使用這些新特性,您將會編寫出更好的代碼。

    補充閱讀

    原文出處:Experiences with the New Java 5 Language Features http://dev2dev.bea.com/pub/a/2005/09/java_5_features.html
    ?作者簡介
    Jess Garms 是BEA Systems中Javelin編譯器團隊的領導者。在此之前,Jess致力于BEA的 Java IDE,WebLogic Workshop。此外,他在密碼學方面也具有豐富的經驗。他還與他人合著了“Professional Java Security”,由Wrox出版社出版。
    Tim Hanson 是BEA Systems中Javelin編譯器的架構師。Tim對BEA的Java編譯器做了很多開發工作,該編譯器是最早兼容1.5的實現之一。他曾經編寫過許多其他的編譯器,包括他在IBM時編寫的CORBA/IDL編譯器,以及XQuery編譯器。
    posted @ 2007-01-03 21:29 Welkin Hu 閱讀(187) | 評論 (0)編輯 收藏

    如今的XML,在文檔生成方面可謂大紅大紫。使用XML + XSLT可以動態生成HTML文檔和表單。而XML + XSL +?FO更可以動態生成PDF/RTF文檔。

    所謂動態生成,就是在運行,才將數據放到具有指定DTD/schema的XML文檔中,使用預定義的XSL文檔生成可供瀏覽或打印的文檔。

    一般來說,生成HTML和PDF的XSLT要分別定義。對于HTML和PDF表現差別較大的文檔,有必要使用這種方法。

    但是,對于一些格式要求較高的表單和報表,在HTML和PDF下的表現是基本一致的。這個時候就有必要用同一個樣式表輸出HTML和PDF。要知道,手工定義一份XSLT可是很費工夫的。

    FO似乎能達到這個目標,它具備足夠精細的樣式定義,借助FOP等工具,可直接輸出PDF等格式。可惜的是,目前的主流瀏覽器,如IE和firefox,并不能直接顯示FO文檔。必須將其轉換成HTML或XHTML。然后,我沒有發現任何的開源工具可以做到這一點。

    ?

    Altove StyleVision,恰到好處的實現上述目標。

    顧名思義,StyleVision就是用來設計樣式表的,它提供一個非常友好的GUI設計界面。它使用一個私有的XML格式(SPS)來保存樣式表,這個樣式表可轉換成生成HTML的XSLT和生成FO的XSLT。

    這樣,做為開發方,購買一份Altova StyleVision,用來設計樣式表,然后將其生成的XSLT發布給用戶,就可以實現同源輸出報表了。而最終用戶可以不購買Altova StyleVision

    附圖:兩種動態文檔生成方案(在圖中體現為兩條可選的路線):

    ?

    posted @ 2006-12-30 12:26 Welkin Hu 閱讀(1861) | 評論 (0)編輯 收藏

    RBAC(基于角色的權限控制)是一個老話題了,但是這兩天我試圖設計一套表結構實現完整的RBAC時,發現存在很多困難。

    我說的完整的RBAC,是指支持角色樹形結構和角色分組。具體來說,應當包含如下權限控制需求:

    1. 父級角色可以訪問甚至是修改其子級的數據,包含直接子級直到最終子級。
    2. 角色可以訪問其所在組的數據。
    3. 父級角色可以訪問其所有子級(從直接子級到最終子級)所在組的數據。

    而具體到我的系統中,還應當有如下需求。

    1. 兼容多種數據庫產品。只能用簡單的表,視圖,存儲過程和函數等實現。
    2. 同時兼容單條數據處理和批量數據處理的需求。

    且不論這些具體需求,RBAC的基本表應當如下四個:

    • roleList表,記錄所有的角色和角色組。
      • roleId: PK, 角色/組的ID,全局唯一,不區分角色和組。
      • roleName:角色/組的名稱。
      • roleType: R - 角色,G - 組
    • rolePermission表,記錄每一個角色/組對每一個對象的權限。
      • permissionID: PK, 無特定意義。
      • role: 角色/組的ID。
      • object: 對象的ID。
      • permission: 權限標識,如讀,寫,刪等。
    • roleRelationship表,記錄角色/組之間的關系。
      • relationId: PK, 無特定意義。
      • superiorRole: 父角色/組的ID。
      • role:子角色,子組,成員角色,成員組的ID。
      • relationship: 關系標識,可在如下設置集中選取一個。
        • PG標識:P - 父子關系,G - 組/成員關系。
        • PPGG標識:在PG集上,再加三種:PP - 間接父級關系,GG - 組內組關系,CG - parentRole是組,childRole的子角色或間接子角色是其成員,或其子組(含間接子組)的成員
    • objectList表,記錄所有的對象。
      • objectId: PK,對象ID,全局唯一。
      • objectName: 對象名稱。
      • ... ...

    分析上述表結構,不難發現,問題的關鍵在于從rolePermission表中讀取數據時,如何限定角色/組的范圍.

    方案一

    如果角色和組的總量不大,比如在100以內,采用PPGG標識關系,讀取數據時是最快的。這個時候的SQL只需要一個輸入參數?roleId:

    SELECT object FROM rolePermission p left join roleRelationship r on p.role = r.role WHERE p.role = ?roleId or r.superiorRole = ?roleId. (尚未驗證SQL的正確性)

    但是,這個方案是以極度冗余roleRelationship表的數據為代價的,比如有100個角色,那么roleRelationship中將會有100 * 100 =10,000條記錄。而在每次調整角色和R角色組的時候,就要在roleRelationship中一次增加或刪除100條記錄。這個開銷是比較大的。

    方案二

    只標識PG,查詢時接收的輸入參數為一個完整的相關角色列表?roleList。

    SELECT object FROM rolePermission WHERE role in (?roleList)

    在系統運行時,這個?roleList通常可以從role hierarchy cache中取到,比較方便。這個方案的主要問題有二:

    1)如果?roleList過長,使用in判斷性能會很差。

    2)在有些情況下,如報表查詢和系統外查詢時,取得roleList不太方便。

    方案三

    只標識PG,但使用如下三個數據庫函數來判斷角色/組之間的關系。

    • boolean isChild(role, parentRole) - 如role為parentRole的子,返回true。
    • boolean isDescendant(role, ancestorRole) - 如role為ancestorRole的子或間接子級,返回true。
    • boolean isMember(role, group) - 如role為group的成員或子組的成員,返回true。
    • boolean descendantIsMember(role, group) - 如role的子或間接子級為group的成員,返回true。
    • boolean isBelong(role, super) - 如role為super的子,間接子,成員或間接員,或者role的子(含間接子)是super的成員或子組成員,返回true。

    在查詢時,也只需要接收一個?roleId:SELECT object FROM rolePemission WHERE isBelong(?roleId, role)

    如何寫出高性能的數據庫函數是實現這個方法的關鍵。

    上述方法僅是理論分析,我傾向于方案二。

    終于想到新的方案了。

    方案四,

    結合方案一和方案二,在roleRelationship中,對前兩級(也可以是三級或四級)角色,保存其所有的下級角色和組。這樣,如果以前兩級角色查詢數據,就使用方案一,如果以第三級及以下的角色查詢數據,就使用方案二。

    仍以100個角色為例,每個角色要保存三個關系:一級主管角色,二級主管角色,直接主管角色,最多有300條數據。

    每往角色組中加一個角色,也需要加入三條數據:角色本身,一級主管角色,二級主管角色。

    但往角色組中加一個子組,需要加入的數據量就大一些:子組本身,子組所有角色,子組所有角色的一級主管角色和二級主管角色。如在多個子組中發現同一角色,可重復保存,但應在表中附加說明是由哪個子組導入的。這樣在刪除子組時就可以有選擇性的刪除。

    但重復子組的情況就比較麻煩,還有等考慮。假充有組g01,g11,g12,g21。g01包含g11和g12,g11和g12分別包含g21。從g01中刪除g11時,如何判斷g21的去留?看來還是應當在維護時判斷應不應當刪除。

    Technorati :

    posted @ 2006-12-27 17:12 Welkin Hu 閱讀(6159) | 評論 (0)編輯 收藏

    僅列出標題
    共4頁: 上一頁 1 2 3 4 下一頁 
    主站蜘蛛池模板: 亚洲一区二区三区免费在线观看| 69视频在线观看免费| 区三区激情福利综合中文字幕在线一区亚洲视频1 | 久久亚洲中文字幕精品一区四 | 亚洲av日韩av综合| 免费在线看v网址| 亚洲精品无码mⅴ在线观看| 亚洲国产成人五月综合网| 免费人成在线观看网站| 在线亚洲午夜片AV大片| 亚洲综合在线另类色区奇米| 日本成年免费网站| 久久久久女教师免费一区| 亚洲第一页在线视频| 亚洲福利在线播放| 91成人免费观看网站| 人妖系列免费网站观看| 亚洲18在线天美| 亚洲国产成人精品无码区在线观看 | 亚洲国产女人aaa毛片在线| 最新中文字幕电影免费观看| 在线观看黄片免费入口不卡| 国产精品高清视亚洲精品| 亚洲精品V欧洲精品V日韩精品| 中国黄色免费网站| 亚洲国产精品久久久久秋霞小| 免费观看黄网站在线播放| 国产精品成人免费综合| 在线免费不卡视频| 久久久久久久岛国免费播放| 亚洲校园春色另类激情| 国产精品亚洲片在线观看不卡| 一级毛片免费在线观看网站| 亚洲成av人片不卡无码| 国产亚洲人成无码网在线观看 | 三年片在线观看免费观看大全动漫| 亚洲人成影院在线观看 | 亚洲色大成网站www尤物| 亚洲AV无码不卡无码| 国产亚洲av片在线观看18女人| 51午夜精品免费视频|