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

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

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

    lbom

    小江西

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      18 隨筆 :: 21 文章 :: 69 評論 :: 0 Trackbacks

    2006年1月10日 #

    昨日年終總結(jié)會,公司總裁給出IT產(chǎn)業(yè)未來發(fā)展的幾個新趨勢,值得我們這些從事軟件工作的人員沉思,現(xiàn)對他的發(fā)言摘錄如下:
    1)管理虛擬化:有形的組織型管理和虛擬的IT流程管理相結(jié)合管理模式;
    2)制造虛擬化:由生產(chǎn)線工人和由程序控制的機器人相結(jié)合的生產(chǎn)模式;
    3)渠道虛擬化:由實體銷售店和虛擬的網(wǎng)上銷售相結(jié)合的渠道管理模式;
    4)服務(wù)虛擬化:實體保養(yǎng)維修和遠(yuǎn)程診斷,軟件更新相結(jié)合的服務(wù)模式;
    5)組織虛擬化:垂直的組織機構(gòu)和橫向的項目型組織機構(gòu)相結(jié)合的企業(yè)組織模式。
    posted @ 2014-01-24 22:28 lbom 閱讀(285) | 評論 (0)編輯 收藏

    今天,花費1個小時,研究了一下在Windows下,使用Telent登錄至UNIX的腳本,現(xiàn)將其貼下,以供下次使用(tt.bat)

     

     

    @echo off
    echo set sh=WScript.CreateObject("WScript.Shell") >telnet_tmp.vbs

    echo WScript.Sleep 3000 >>telnet_tmp.vbs
    rem ----------------UNIX IPAddress
    echo sh.SendKeys "open 10.0.18.100{ENTER}" >>telnet_tmp.vbs

    echo WScript.Sleep 3000 >>telnet_tmp.vbs
    rem ----------------userID
    echo sh.SendKeys "root{ENTER}" >>telnet_tmp.vbs

    echo WScript.Sleep 3000 >>telnet_tmp.vbs
    rem ----------------password
    echo sh.SendKeys "root{ENTER}" >>telnet_tmp.vbs

    echo WScript.Sleep 3000 >>telnet_tmp.vbs

    echo sh.SendKeys "ls {ENTER}">>telnet_tmp.vbs

    start telnet

    cscript //nologo telnet_tmp.vbs

    rem del telnet_tmp.vbs

     

    posted @ 2011-10-10 16:02 lbom 閱讀(4029) | 評論 (1)編輯 收藏

    1)啟動LiveWriter客戶端

    2)添加Blog帳戶:

    image image

    3)設(shè)置日志類型:

    image

    4)連接測試

    posted @ 2010-09-25 18:02 lbom 閱讀(313) | 評論 (0)編輯 收藏

    很久沒有動手寫WebService了,這次,借項目間隙,對系統(tǒng)進(jìn)行一個小改造,將一部分功能使用WS進(jìn)行封裝,為下一步異構(gòu)系統(tǒng)集成打下基礎(chǔ)。

    但在WS化時,由于日久生疏,一個小小的WS化變動,卻花了整整好幾天時間!為此,狠下以來,將其過程進(jìn)行記錄,以便下次參考。

     

    WS整體流程:

    clip_image001

    以下分別介紹:

    1、設(shè)計和實現(xiàn)WebService服務(wù)端功能組件,用于統(tǒng)一處理針對本應(yīng)用系統(tǒng)所需進(jìn)行WebService化的邏輯實現(xiàn)。并將系統(tǒng)邏輯處理中的對象轉(zhuǎn)成序列化后的String對象,以符合WebService交互標(biāo)準(zhǔn)。

    clip_image002

    2、根據(jù)SBPApi.java,生成WSDL等:通過Eclipse右鍵菜單中的WebService-->Create Web Service項。完成后,會在web目錄下建立wsdl目錄和SBPApi.wsdl,在WEB-INF目錄下建立(改寫)server-config.wsdd等文件,并完成對web.xml的修改。其操作流程示如下:

    clip_image003

    3、根據(jù)SBPApi.wsdl,生成WebService客戶端開發(fā)包和部署文件:

    1)為不影響已有項目,可另建java Web項目;

    2)將wsdl目錄復(fù)制至新項目對應(yīng)的web目錄下;

    3)通過eclipse已提供的webService插件(右鍵)功能,生成客戶端開發(fā)包所各文件。此時,所生成的文件與服務(wù)端對象文件結(jié)構(gòu)一至。

    clip_image004

    4)調(diào)整關(guān)聯(lián)引用文件,將其調(diào)整至客戶端開發(fā)包,從而避免與服務(wù)器端的引用路徑重復(fù)而引發(fā)不便,并將服務(wù)器SDK中已有文件刪除。

    clip_image005

    5)建立客戶端的快速使用代理SBPClient.java,對WebService服務(wù)端交互工作的SBPApiSoapBindingStub.java進(jìn)行客戶端封裝,并根據(jù)服務(wù)端中交互對象進(jìn)行反向工程,其示例結(jié)構(gòu)如下:

    clip_image006

    6)將clientApi下的所有文件打包后,加入測試項目進(jìn)行測試。此時,因客戶端所使用的服務(wù)端對象未包含在WebService客戶端開發(fā)包中,因此需要將服務(wù)端對象也一同打包。

    7)測試。

    4、開發(fā)環(huán)境:Eclipse3.3.1.1 + JDK1.5.06 + Apache Axis version: 1.4

    posted @ 2010-04-02 15:45 lbom 閱讀(2166) | 評論 (4)編輯 收藏

    在一次基于多線程的編碼測試中,發(fā)現(xiàn)繼承Runnable接口的線程實現(xiàn)類在運行時并未按預(yù)計啟動多線程,經(jīng)分析和比較后,找出問題所現(xiàn),現(xiàn)將其記錄下來,以供分享。

    Java中,多線程編程中的線程編寫,有兩種方式,即擴展Thread基類或繼承Runnable接口;例如:

    public class T extends Thread {

    public void run() {

    ……

    }

    }

    public class R implements Runnable {

    public void run() {

    ……

    }

    }

    對于擴展Thread的實現(xiàn)類T,可以使用T.start()來啟動此線程;如

    public static void main(String[] args) {

    Thread t = new T();

    t.start();

    }

    但對于繼承Runnable接口的實現(xiàn)類R,因接口中并沒有提供直接啟動線程的start()方法,只有一個線程主邏輯運行的run()方法。此時,如執(zhí)行run(),會因為R.run()只是作為此線程實現(xiàn)類的一個方法,并未在主線程之外,啟動另一個線程,從而導(dǎo)致R.run()阻斷主線程繼續(xù)向下執(zhí)行;并未達(dá)到多線程運行的目的。

    錯誤啟動代碼如下:

    public static void main(String[] args) {

    R r = new R();

    r.run();

    }

    那么,如何使用另外線程來啟動繼承Runnable接口的實現(xiàn)類呢?以下就是它的正確的使用方式:

    public static void main(String[] args) {

    R r = new R();

    Thread t = new Thread(r);

    t.start();

    }

    此時,需注意,在主線程執(zhí)行時,需等待子線程執(zhí)行,否則,當(dāng)主線程結(jié)束后,子線程也將結(jié)束。

    posted @ 2010-03-10 16:48 lbom 閱讀(1582) | 評論 (2)編輯 收藏

    需求:

    系統(tǒng)A與系統(tǒng)B分別部署在不同域的兩臺服務(wù)器中,但它們的身份都統(tǒng)一在身份認(rèn)證服務(wù)器中;身份認(rèn)證信息以Session方式存貯于各自系統(tǒng)中,并輔以cookie進(jìn)行使用。

    當(dāng)用戶在A系統(tǒng)登錄后,訪問B系統(tǒng)時,由于是跨域訪問,導(dǎo)致身份信息不能正確的傳遞到B系統(tǒng)中,從而致使用戶需在B系統(tǒng)中重新登錄。

    clip_image001[6]

    解決方案:

    處理這類跨域訪問時,我們最先使用從B系統(tǒng)向C通過HttpRequest(類AJAX請求)的方式獲取身份信息,此方式好處是同步處理,方便用使用;但其限制諸多,如需設(shè)置信任站點、用戶訪問確認(rèn)等,甚至,在對應(yīng)用服務(wù)器作了一次安全升級后,根本無法訪問了。因此,需另行開辟途徑,于是,在同事建議下,我們使用IFrame內(nèi)嵌跨域驗證網(wǎng)頁,來解決此問題。

    1、原理設(shè)計:用戶在訪問B系統(tǒng)時,先使用一內(nèi)置的iframe,并將iframe的src指向身份認(rèn)證服務(wù)器系統(tǒng)代理驗證接口;如果用戶已經(jīng)在A系統(tǒng)中進(jìn)行過登錄,即A域了中已存在著身份認(rèn)證信息后,身份認(rèn)證服務(wù)器中也將具有其身份信息將其附帶著身份認(rèn)證信息后重定向訪問B系統(tǒng)代理接口;B系統(tǒng)代理驗證接口在接收到由A系統(tǒng)傳遞而來的身份認(rèn)證信息后,通過身份認(rèn)證服務(wù)器驗證后,在B系統(tǒng)所在域重建身份認(rèn)證信息。

    2、實現(xiàn)邏輯貼碼:

    1)B系統(tǒng)代理驗證接口:

    (1)IFrame邏輯貼碼:

    clip_image002[6]

    (2)JS檢測是否通過認(rèn)證邏輯貼碼:

    clip_image003[6]

    2)身份認(rèn)證服務(wù)器端接口(JSP):

    clip_image004[6]

    3、注意事項:

    1)由于身份認(rèn)證中心使用cookie作為身份標(biāo)識,因此,需要用戶在瀏覽器中允許使用cookie的設(shè)置;

    2)由于在iframe中進(jìn)行跨域重定向,因此需在IE安全中的跨域瀏覽子框架項設(shè)為啟用:

    clip_image005[6]

    4、源碼文件:

    ……

    posted @ 2010-02-08 17:55 lbom 閱讀(3500) | 評論 (3)編輯 收藏

    在windows下進(jìn)行j2ee項目開發(fā)和部署時,常需要對系統(tǒng)存在問題進(jìn)行更深入的分析。由此,實時的javacore就是分析的最佳方式之一。但如何以最方便直接的方式產(chǎn)生javacore文件,就是這項工作必需做的準(zhǔn)備工作了。

    1、通過dos窗口,進(jìn)入至jdk安裝目錄下的bin目錄中;

    2、運行jconsole.exe,并設(shè)置信息輸出的目標(biāo)文件,以便于分析,否則將直接輸出至屏幕上;

    image

    3、連接正在運行的目標(biāo)jvm;

    image

    4、連接后的jconsole如下:

    image

    5、通過通過Ctrl+Break組合鍵,產(chǎn)生javacore至指定文件中。

    6、下一步就是對所產(chǎn)生的javacore文件進(jìn)行具體的分析和使用了。

    posted @ 2009-12-10 15:00 lbom 閱讀(2358) | 評論 (2)編輯 收藏

    某日,公司進(jìn)行年度一次的體檢!

    在連續(xù)查出10個脂肪肝后,醫(yī)生對第11個進(jìn)來檢查的人說:“等會,我們的B超機好像出問題了,等檢修后再進(jìn)行”

    這是一個真實的事件,我們這些IT行業(yè)的從業(yè)人員,多坐少動,壓力大,時間長,導(dǎo)致體質(zhì)差的邊醫(yī)生都懷疑機器了!

    唉!

    posted @ 2009-10-29 15:32 lbom 閱讀(332) | 評論 (0)編輯 收藏

    一、項目建立及應(yīng)用實現(xiàn)

    1、建立J2ME項目

    clip_image001

    2、在完成開發(fā)后,進(jìn)入Application Descriptor編輯界面

    clip_image002

    3、因默認(rèn)情況下,Application Descriptor文件中未定義MIDlet啟動對象,因此需使用EditPlus或記事本等文本編輯器,編輯Application Descriptor文件(位于項目根目錄下),并添加以下項目,如:

    clip_image003

    4、運行Application Descriptor編輯界面中的Lanuch as enumlated Java ME JAD,進(jìn)行測試

    clip_image004

    5、在步驟4之后,會在項目根目錄下的.mtj.tmp中生成LaunchFromJAD子目錄,其中的worm.jad和worm.jar即是手機程序的安裝文件

    clip_image005

    6、將worm.jad和worm.jar復(fù)制至手機中,運行worm.jad進(jìn)行安裝后,即可使用

    二、問題分析:

    1、如報【文件不完整】錯誤,則檢查worm.jad中的項目是否完整。在Eclipse中使用Lanuch as enumlated Java ME JAD測試通過,并自動生成的此文件,一般都是完整的,不需作任何修改。

    2、如報【版本錯誤】,則檢查您在Eclipse中使用的的模擬器版本是否是您手機所支持的,出現(xiàn)此錯誤后,將模擬器版本調(diào)低試試。其位置如下

    clip_image006

    三、開發(fā)環(huán)境:

    1、java JDK1.6.0_10;

    2、EclipseV3.3.1.1;

    3、sun公司J2ME-WTK開發(fā)包:sun_java_wireless_toolkit-2_5_2-ml-windows.exe

    4、Eclipse移動應(yīng)用開發(fā)包:eclipseme.feature_1.7.9_site.zip

    posted @ 2009-10-15 17:50 lbom 閱讀(1475) | 評論 (0)編輯 收藏

     

     

    消息中心產(chǎn)品簡介

    產(chǎn)品簡介

    XXX產(chǎn)品框架中,我們根據(jù)產(chǎn)品發(fā)展規(guī)劃和業(yè)務(wù)領(lǐng)域需要,使用基于JMS技術(shù),通過應(yīng)用WEBService,開發(fā)了消息中心中間件(簡稱MC)。通過消息中間件,我們可以實現(xiàn)各系統(tǒng)間的異步數(shù)據(jù)交換和事務(wù)處理、執(zhí)行不需前臺使用人員干預(yù)的如后臺業(yè)務(wù)和數(shù)據(jù)同步工作,也可用來處理一些受到安全和其它一些因素制約,導(dǎo)致無法直接通過數(shù)據(jù)庫或應(yīng)用系統(tǒng)進(jìn)行處理的受限業(yè)務(wù)。

    消息中心中間件,包括消息總線和消息客戶端兩部分:消息客戶端負(fù)責(zé)業(yè)務(wù)類消息實例的產(chǎn)生、發(fā)送消息實例到消息總線、接收從消息總線轉(zhuǎn)發(fā)而來的消息實例、將收到的消息實例交由其載體應(yīng)用系統(tǒng)進(jìn)行與之對應(yīng)的業(yè)務(wù)處理等活動;消息總線負(fù)責(zé)接收從消息客戶端產(chǎn)生并發(fā)送而來的消息實例、消息重建、根據(jù)消息配置進(jìn)行消息實例重建,將重建后的消息實例轉(zhuǎn)發(fā)至對應(yīng)的消息客戶端等活動。

    消息客戶端與XXX各應(yīng)用系統(tǒng)集成在一起,并通過應(yīng)用系統(tǒng)開放WEBService端口進(jìn)行消息的發(fā)送和接收等,從而避免單獨部署和發(fā)布所帶來的困難和額外資源消耗。消息總線可單獨部署,也可和消息客戶端一樣,與XXX應(yīng)用系統(tǒng)集成部署,在XXX產(chǎn)品框架下,有且只需要一套消息總線即可滿足需要。消息配置中心,其作用包括配置和管理消息中心各組成部分的部署方式和訪問信息,以此將消息中心各部有機的聯(lián)系起來;同時,各消息業(yè)務(wù)應(yīng)用,也使用配置文件進(jìn)行配置化管理,并與消息中心各組成部分進(jìn)行關(guān)聯(lián)配置,從而形成一個統(tǒng)一且開放的整體;其它的如性能優(yōu)化處理、日志記錄等也在配置中心進(jìn)行配置和管理。

    應(yīng)用現(xiàn)狀

    在消息中間件V1.0版本開發(fā)完成后,我們即將其投入實用。在XXX各分子系統(tǒng)這近一年時間的運行和使用過程中,消息中心很好的完成了預(yù)定任務(wù),其可靠性、可擴展性和適用性得到很好的驗證。以此為據(jù),通過使用消息中心,開發(fā)出基于消息中心的客戶化應(yīng)用和業(yè)務(wù)活動也在持續(xù)的增加中,到現(xiàn)在為止,已經(jīng)有包括網(wǎng)絡(luò)檢測、信息同步、配置更新、電子目錄樹更新、權(quán)限同步等諸多應(yīng)用是基于消息中心應(yīng)用開發(fā),并很好的使用在XXX各分子系統(tǒng)的測試和內(nèi)網(wǎng)正式環(huán)境中。

    問題出現(xiàn)、描述、分析與處理記錄

    問題出現(xiàn)

    在XXX系統(tǒng)正式接入外網(wǎng)后,通過對業(yè)務(wù)進(jìn)行跟蹤,發(fā)現(xiàn)外網(wǎng)用戶(系統(tǒng))所產(chǎn)生的消息實例無法正常的到達(dá)指定的消息總線及消息客戶端。最主要的體現(xiàn)是權(quán)限同步消息應(yīng)用無法正常完成的問題,導(dǎo)致外網(wǎng)用戶權(quán)限未得到及時更新。對此過程中消息中心所涉及部分進(jìn)行分析發(fā)現(xiàn):所有的權(quán)限同步消息實例在產(chǎn)生后,不能正常的將此消息實例發(fā)送至消息總線,分析失敗原因,只有一種,那就是”connect time out”。從此信息可看出,應(yīng)該是外網(wǎng)系統(tǒng)所發(fā)出的消息無法通過WEBService送達(dá)指定的消息總線接收端所至。但從內(nèi)網(wǎng)發(fā)出的同一類消息,其發(fā)送和接收卻又都是正常的。

    分析過程記錄

    1、先分析我們系統(tǒng)的整體部署方式,如下圖所示:

    根據(jù)外網(wǎng)用戶可正常登錄和訪問系統(tǒng),并可通過系統(tǒng)準(zhǔn)確及時的發(fā)出執(zhí)行指令操作,完成其所需的業(yè)務(wù)活動來看,網(wǎng)絡(luò)方面和系統(tǒng)和硬件方面都不存在問題。

    2、在外網(wǎng)環(huán)境下,直接進(jìn)行各消息客戶端和消息總線的服務(wù)的檢測,所發(fā)請求都能夠正確的到達(dá)指定目標(biāo),WEBService的響應(yīng)也正常且正確,也就是說,各應(yīng)用系統(tǒng)加載的消息服務(wù)運行也正常。

    3、根據(jù)本次檢測需要,另行開發(fā)消息中心專用檢測工具,為本次和今后的行的消息中心檢測和問題分析,作好更充分的準(zhǔn)備。

    4、通過檢測工具,發(fā)現(xiàn),外網(wǎng)環(huán)境下,消息客戶端和消息總線之間不能夠聯(lián)通,從而找到問題所出:即不知是何原因,導(dǎo)致外網(wǎng)消息與外網(wǎng)的消息總線間聯(lián)絡(luò)不通!

    5、對外網(wǎng)用戶消息產(chǎn)生和發(fā)送的過程和邏輯實現(xiàn)進(jìn)行分析:我們發(fā)現(xiàn),為了滿足應(yīng)用系統(tǒng)外網(wǎng)訪問的需要,我們對消息系統(tǒng)配置信息中服務(wù)地址的ServerName進(jìn)行了偽處理,即在運行時,根據(jù)用戶瀏覽器的請求頭來判斷用戶使用的是哪一個WEB服務(wù)器地址,并將此地址動態(tài)的代替消息配置中的各ServerName信息,從而保證各使用用戶只能夠訪問其指定的WEB服務(wù)器,從而避免因WEB服務(wù)器的不匹配而影響其訪問速度、處理效率等故障的發(fā)生。此方式已在我部門多套同時服務(wù)于內(nèi)外網(wǎng)絡(luò)的系統(tǒng)中得到可靠的驗證。

    那么,會不會因為ServerName在動態(tài)解釋過程中,因多并發(fā)情況下,因后訪問者將前訪問者的ServerName改寫而導(dǎo)致錯誤的解釋,即將不同網(wǎng)絡(luò)用戶的消息地址進(jìn)行張冠李戴而導(dǎo)致消息無法正常發(fā)送呢?

    分析消息中心各部分WEBService生成和使用機制:因系統(tǒng)的并發(fā)性要求較高,在高峰期其在線用戶可達(dá)3000人,并發(fā)用戶在300以上,且系統(tǒng)穩(wěn)定性要求極高。為提高系統(tǒng)的性能和穩(wěn)定性,在系統(tǒng)啟動時即將消息中心各部的WEBService連接進(jìn)行創(chuàng)建和緩存,以提升消息中心資源利用率,并提升其訪問性能。

    當(dāng)存在多網(wǎng)絡(luò)用戶訪問時,可能因消息中心存貯的WEBService連接并不是其用戶所使用的那個網(wǎng)絡(luò)的WEBService服務(wù)地址,此時,消息肯定是無法送達(dá)至此用戶所需要的目標(biāo)的。因此,報”connect time out”錯誤就成必然的了。

    既然已找到問題的可能原因,我們立即進(jìn)行著手分析和解決:根據(jù)部署要求,我們對對消息服務(wù)連接服務(wù)進(jìn)行了升級,即將服務(wù)請求進(jìn)行分類處理和實現(xiàn),并在消息配置中對所使用的部署方式、代理實現(xiàn)后,交由測試人員進(jìn)行部署和測試。

    測試結(jié)果:令人失望的是,此問題依然存在!在通過外網(wǎng)WEB服務(wù)器訪問的系統(tǒng),其消息還是無法發(fā)送至消息總線。由此得知,此種分析方向是錯誤的!

    至此,好像已經(jīng)走入了死區(qū),能想到的方式都已經(jīng)想到了,但問題到底出在哪呢?

    問題解決

    在一次與同事聊天的過程中,忽然想到一個問題,那就是:我們的消息的產(chǎn)生和應(yīng)用都是由應(yīng)用系統(tǒng)和與之集成在一起的消息客戶端自動產(chǎn)生和處理的,此過程中完全不受人工干預(yù)和影響。而應(yīng)用系統(tǒng)是部署在應(yīng)用服務(wù)器中,WEB服務(wù)器僅是用來處理用戶的HTTP請求à將此請求轉(zhuǎn)發(fā)至對應(yīng)的應(yīng)用服務(wù)器后à將應(yīng)用服務(wù)器的響應(yīng)返回給用戶。

    在此過程中WEB服務(wù)器并未對用戶業(yè)的http請求進(jìn)行過任何業(yè)務(wù)上的處理!那么,問題會不會出在WEB服務(wù)器端呢?檢查一下消息中心的配置不管是使用ServerName還是寫死IP和域名,我們的消息中心配置的地址都是指向WEB服務(wù)器。而在應(yīng)用系統(tǒng)發(fā)現(xiàn)消息時,其所在位置是應(yīng)用服務(wù)器。而應(yīng)用服務(wù)器是無法直接訪問部署于外網(wǎng)IP中的WEB服務(wù)器的,當(dāng)然,消息無法發(fā)送至目標(biāo)就成為必然了。

    既然已經(jīng)找到問題,那就動手,將消息中心的配置信息指向應(yīng)用服務(wù)器后,重啟應(yīng)用系統(tǒng)后測試,問題果然解決!

    通過應(yīng)用服務(wù)器進(jìn)行后臺自動處理的,進(jìn)行HTTPWEBService活動,其目標(biāo)必需是它能夠訪問的有效地址!這個問題在以前也曾經(jīng)碰到過,只是由于時間隔得太久,且這些場景應(yīng)用出現(xiàn)太少,而導(dǎo)致再次發(fā)生。

    補充與心得

    1、    基于應(yīng)用系統(tǒng)或后臺自動觸發(fā)的一些業(yè)務(wù)邏輯,如其中存在著系統(tǒng)間相互訪問或遠(yuǎn)程調(diào)用等,必需以應(yīng)用系統(tǒng)自身為根,進(jìn)行連接測試;通過外層包裝或其它代理,進(jìn)行訪問時,必需先剝離過外層包裝或其它代理后,再進(jìn)行連接測試,并以測試結(jié)果,作為決策的依據(jù)!此舉適用于各類系統(tǒng)的架構(gòu)設(shè)計和邏輯實現(xiàn)過程中。

    2、    基于中間件產(chǎn)品應(yīng)用,及時開發(fā)與之配套的檢測和使用工具,是一件必不可少的工作,此舉將為后期的實施和問題分析節(jié)省大量的工作量。

    posted @ 2009-10-07 17:06 lbom 閱讀(1489) | 評論 (0)編輯 收藏

        幾天前,偶爾和鄰居聊天,她說要去買頂蚊帳過夏,不由的也動了心。是啊,在小時候,那家不是用蚊帳來保證漫長夏的良好睡眠呢!現(xiàn)在隨著科技發(fā)達(dá),家家戶戶,特別是城市住戶都已經(jīng)將蚊帳扔掉而改用蚊香或蚊片了。
        于是等夫人下班回家,和其商量,卻是死活不同意,理由如下:1)影響臥室美觀;2)擠占空間;3)拆洗不便。。。。。。
        沒辦法,為了達(dá)到目的,我只得絞盡腦汁,想出各種理由,以期望能夠說服夫人:
        1)身體牌:我對蚊香有過敏,因此,在夏天,我們是不能點蚊香的;再說,各種滅蚊產(chǎn)品其主要成份都有毒性,不管其含量多少,都對身體無益。
        2)經(jīng)濟牌:在重慶,一年有6個月的夏天,以每晚一片滅蚊片計算,一年下來,加上電熱滅蚊器最少需要投入120元以上才能保證夏季無憂,三四年下來,就可以買個較好的蚊帳了;再說,滅蚊片用久后,還得防止蚊子產(chǎn)生的抗藥性;但使用蚊帳卻不需要用電,一年下來,其電費也能節(jié)約不少,還可防止可能因電熱滅蚊器散熱不良而導(dǎo)致的用電風(fēng)險的發(fā)生;
        3)環(huán)保牌:在臥室支個蚊帳,即溫馨又浪漫,還無滅蚊產(chǎn)品的各類化學(xué)合成的氣味,最環(huán)保不過了;
        4)衛(wèi)生牌:在床上支個蚊帳,將有效的減少灰塵降落,也免了蜘蛛等小蟲在晚間不意間打擾我們的安眠,多好的一件事!
        。。。。。。
        啰啰嗦嗦,直說的口干舌燥,并許下一堆好處之后,終于換來老婆的點頭。于是二話不說,拉上夫人,直奔商場,在東挑西比之后,買下一款合意的落地式蚊帳。
        至此,我的環(huán)保蚊帳計劃就此實現(xiàn)!
     
        所以,回歸和懷舊,并不都是倒退!
    posted @ 2009-05-26 09:43 lbom 閱讀(294) | 評論 (0)編輯 收藏

            在一周前,項目組碰到一個大問題:NTKO Office Activex控件在上傳文件及提交頁面信息時,其提交的頁面元素輸入中文值變成了無法識別的、也不屬于已知編碼中的任何一種編碼格式的亂碼;但在NTKO Office Activex控件包裝項目組提供的的測試項目中,此問題并未出現(xiàn),因此判斷是項目兼容性所導(dǎo)致。
           在項目組功能開發(fā)員和控件包裝組成員進(jìn)行近一周的努力后,也未解決此問題。最后,此問題交由我來做最后分析和處理。
           經(jīng)過三天時間對問題項目的分拆、組裝、分析、測試后,終于找到問題所出,現(xiàn)將此過程進(jìn)行記錄,以備參考:
            1)以控件包裝組測試項目為基準(zhǔn),建立項目級測試項目,并保證在此測試項目中不存在兼容性問題;
            2)檢測web.xml:將問題項目的web.xml代替測試項目中的web.xml,未出現(xiàn)兼容性問題,從而排除因web.xml的差異而導(dǎo)致的兼容性;
            3)測試問題項目中的項目依賴:將問題項目的項目依賴關(guān)系復(fù)制至測試項目中,發(fā)現(xiàn)兼容性問題未出現(xiàn),從而排除項目依賴導(dǎo)致的兼容性;
            4)檢測支持包:將問題項目中的支持包(各jar)代替測試項目中的支持包,未出現(xiàn)兼容性問題,從而排除因支持包的差異導(dǎo)致的兼容性,也就排除了各servers,servlet,listener等導(dǎo)致的兼容性問題;
            5)檢測js支撐:將問題項目中的所有相關(guān)js文件取出,代替測試項目中的相關(guān)js文件,未出現(xiàn)兼容性問題,從而排除因js支持文件的差異導(dǎo)致的兼容性;
            6)檢測css支撐:將問題項目中的所有相關(guān)css文件取出,代替測試項目中的相關(guān)js文件,未出現(xiàn)兼容性問題,從而排除因css支持文件的差異導(dǎo)致的兼容性;
            7)檢測tld,xml文件:將問題項目中的tld,xml文件取出,代替測試項目中的tld,xml文件,未出現(xiàn)兼容性問題,從而排除因tld,xml的差異導(dǎo)致的兼容性;
            8)至此,正常解決的兼容性措施都已用完,還是未找到問題所出!如何辦?
            9)開始使用非正常手段進(jìn)行排查:
                <1>對比檢查.project和.classes未發(fā)現(xiàn)異常,從而排除基本項目配置導(dǎo)致的兼容性;
                <2>將問題項目的web項目設(shè)置文件(.settings)代替測試項目的web項目設(shè)置文件(.settings),問題出現(xiàn)了!繼續(xù)排隊分析,發(fā)現(xiàn)問題出現(xiàn)在文件org.eclipse.wst.common.component中,
    問題項目的設(shè)置為:
                                        <?xml version="1.0" encoding="UTF-8"?>
                                        <project-modules id="moduleCoreId" project-version="1.5.0">
                                           <wb-module deploy-name="XXX_IC">
                                           <wb-resource deploy-path="/" source-path="/web"/>
                                           <wb-resource deploy-path="/WEB-INF/classes" source-path="/src"/>
                                           <wb-resource deploy-path="/WEB-INF/classes" source-path="/test"/>
                                           <property name="java-output-path" value="build/classes"/>
                                           <property name="context-root" value="XXX_IC"/>
                                       </wb-module>
                                       </project-modules>
    測試項目設(shè)置為:
                                        <?xml version="1.0" encoding="UTF-8"?>
                                        <project-modules id="moduleCoreId" project-version="1.5.0">
                                           <wb-module deploy-name="test">
                                           <wb-resource deploy-path="/" source-path="/web"/>
                                           <wb-resource deploy-path="/WEB-INF/classes" source-path="/src"/>
                                           <wb-resource deploy-path="/WEB-INF/classes" source-path="/test"/>
                                           <property name="java-output-path" value="build/classes"/>
                                           <property name="context-root" value="test"/>
                                       </wb-module>
                                       </project-modules>
    且無論如何修改"XXX_IC",都會導(dǎo)致兼容性出現(xiàn),最后沒辦法,將下劃線"_"去掉,奇跡出現(xiàn)了。
            原來NTKO Office Activex控件在提交數(shù)據(jù)時,是通過scoket模擬Http進(jìn)行文件和頁面元素的提供,如提交的頁URL完整路徑中包含了"_"等字符時,將導(dǎo)致無法識別,從而導(dǎo)致兼容性的產(chǎn)生。
    posted @ 2009-05-15 22:13 lbom 閱讀(1509) | 評論 (2)編輯 收藏

     

    從小到大,椰子已經(jīng)吃過很多次了,但在這些吃椰子有經(jīng)歷中,我只知道一種吃法:開孔à插吸管à喝椰汁à丟椰殼à完事!

           但在今天,事情有了些變化,于是產(chǎn)生的椰子的第二種吃法。

    我和夫人在散步時,順便準(zhǔn)備到超市買點水果,看到水果區(qū)的椰子又大又好且正在打特價。心中一動,就挑了個大的,買回家準(zhǔn)備細(xì)細(xì)品嘗一番。在按通常吃法吸光椰子中的水汁后,突然想起,我們平時很喜歡吃超市中的一種叫椰角小吃的,又甜又韌很有嚼勁,但椰角是長大哪的呢?不會是椰子樹上的另一種產(chǎn)品吧!看著椰子開口的硬殼下面的白色軟組織,我們就突發(fā)奇想,這白色軟組織會不會就是那椰角呢?

    說動就動,先用刀將空椰子殼砍開,發(fā)現(xiàn)其內(nèi)層確實是一層約0.8cm厚的白色果肉。小心的切下一小塊嘗一嘗,味道淡淡的,很有韌勁,確實就是那椰角的源料。這就是我發(fā)現(xiàn)的椰子的第二種吃法了。

    在生活中有很多事:你沒經(jīng)歷,就不會想到;當(dāng)你想不到時,美好的事情就可能錯過!
        這就是生活。

                                                                                        2009/5/5

    posted @ 2009-05-05 22:31 lbom 閱讀(2373) | 評論 (2)編輯 收藏

     

    在我們公司的軟件研發(fā)體系中,存在著三種截然不同的軟件開發(fā)方式。而我,作為公司最老同事之一,也是這三種開發(fā)模式的親歷者,曾不只一次的被公司同事問過我關(guān)于這三類方式之間的異同點。于是利用空閑時間,對其進(jìn)行一番整理、分析和對比。

    1、全能型

    部門經(jīng)理在接到項目之后,將此項目交給部門內(nèi)的熟練程序員后,此程序員就自動被委任其為項目經(jīng)理。從此開始,程序員將根據(jù)項目售前方案和銷售合同內(nèi)容,在項目進(jìn)行過程中分別擔(dān)當(dāng)起項目經(jīng)理、功能設(shè)計師、數(shù)據(jù)存貯設(shè)計師、程序員、測試員和項目實施人員等諸多角色。并在項目進(jìn)行的過程中,帶領(lǐng)少量其它程序員和輔助資源來完成此項目的所有工作。

    此類項目其功能單一且不復(fù)雜,只是為了幫助用戶提升某一項工作的工作效率或解決客戶在其工作中的一些問題,如工作日志信息的采集和分析業(yè)務(wù)項目、辦公用品的申請和領(lǐng)用等。它們因為其涉及范圍小,使用人員不多,從而具有項目總費用少、開發(fā)和實施周期短、對性能要求不高的特點。

    在此類開發(fā)模式中,程序員由于其工作的全面性,使他們在進(jìn)入項目組后,能夠得到很快且全面的提升,并會在與客戶交往的過程中,建立起良好的客戶關(guān)系處理經(jīng)驗,為其今后的成長和發(fā)展打開良好的基礎(chǔ)。

    由于項目需要,程序員需要掌握全面技能,容易造成其在項目開發(fā)過程中需要全面的接觸項目管理及人際關(guān)系、需求分析、數(shù)據(jù)庫及對象設(shè)計、人機交互和用戶體驗設(shè)計、系統(tǒng)設(shè)計和開發(fā)、測試和系統(tǒng)提升、應(yīng)用實施和售后維護(hù)等諸多截然不同的領(lǐng)域范圍;所以,作為此類程序員,其工作壓力之大,事務(wù)之復(fù)雜、綜合素質(zhì)要求之高,是其它模式的程序員所無法對比的,這也是造成此類項目按時完成率極低、尾款回收困難、項目售后工作難做、用戶滿意度差、二次項目獲取困難的根本原因。

    同時,由于程序員被大量的非開發(fā)性事務(wù)所干擾,造成他們無法專心致力于專業(yè)技能的學(xué)習(xí)和提升,也就無法造就一支高效率、高穩(wěn)定性、配合默契的開發(fā)隊伍,這也是造成公司內(nèi)此類人才大量流失的重要原因。

    2、英雄型

           部門經(jīng)理在接到此類項目后,按項目所涉及的領(lǐng)域范疇,將其按領(lǐng)域進(jìn)行分工。以企業(yè)信息協(xié)同系統(tǒng)為例,我們將進(jìn)行如下分工:門戶信息的獲取、聚合、交互和展現(xiàn)工作交給專職于門戶開發(fā)的程序員;內(nèi)部郵件系統(tǒng)的分析、設(shè)計、和實現(xiàn)將給郵件開發(fā)程序員;日程和事務(wù)的設(shè)計交給日程開發(fā)程序員;工作流應(yīng)用工作交由工作流客戶化開發(fā)程序員等等。

           在此類型的開發(fā)模式中,程序員將會是某一領(lǐng)域內(nèi)的英雄式人物!由于他長期且相對穩(wěn)定的負(fù)責(zé)著這個有限領(lǐng)域范圍內(nèi)的一切事務(wù),可以幫助他在一定時期內(nèi)進(jìn)行系統(tǒng)而穩(wěn)定的業(yè)務(wù)研究和分析工作,進(jìn)而成長為此領(lǐng)域內(nèi)的業(yè)務(wù)專家。而且,通過持續(xù)的對其工作進(jìn)行迭代式開發(fā)、升級和完善,可使此產(chǎn)品在產(chǎn)品品質(zhì)、適用性和用戶體驗等方面得到穩(wěn)定的提升,進(jìn)而提升了整個產(chǎn)品的品質(zhì)。

           如果此領(lǐng)域內(nèi)的工作產(chǎn)品能夠得到合理的規(guī)劃和實現(xiàn),進(jìn)而將其進(jìn)行單獨的封裝、應(yīng)用集成和推廣,就有可能形成一個具有相當(dāng)競爭力的產(chǎn)品,從而為公司獲取新的銷售機會和利潤點。

           但是,此類開發(fā)模式中的分工也容易造成程序員涉及業(yè)務(wù)領(lǐng)域單一和適應(yīng)性窄的缺陷:由于其長期面對和研究著單一業(yè)務(wù)領(lǐng)域內(nèi)的業(yè)務(wù)活動,而無法更多的接收和參考來自于用戶、企業(yè)和其它行業(yè)內(nèi)的非它業(yè)務(wù)發(fā)展需要和趨勢,從而對其在產(chǎn)品領(lǐng)域內(nèi)的發(fā)展產(chǎn)生限制,并造成其產(chǎn)品方向上的不準(zhǔn)確或錯誤定位;由于其長期的在單一領(lǐng)域內(nèi)工作,并在此領(lǐng)域內(nèi)獲得了公司內(nèi)的認(rèn)可,這也將限制他在領(lǐng)域間的流動性。當(dāng)公司或部門的產(chǎn)品方向和需要調(diào)整和改變時,此類程序員就需要被迫改變甚至放棄其在原領(lǐng)域內(nèi)的所有積累而重新開始,從而造成巨大的浪費。

    3、專業(yè)型

           項目經(jīng)理在接到項目之后,根據(jù)項目組成員的能力、特長職業(yè)規(guī)劃,對他們進(jìn)行適當(dāng)且專業(yè)化分工:由業(yè)務(wù)規(guī)劃人員負(fù)責(zé)項目的需求收集、業(yè)務(wù)規(guī)劃和需求分析;由系統(tǒng)架構(gòu)師對系統(tǒng)的進(jìn)行技術(shù)構(gòu)架和支撐性技術(shù)的規(guī)劃和引進(jìn);由數(shù)據(jù)庫專員負(fù)責(zé)數(shù)據(jù)庫對象的設(shè)計和性能調(diào)優(yōu);由功能分析員在人機交互人員輔助下負(fù)責(zé)功能設(shè)計和人機交互模式;由業(yè)務(wù)邏輯實現(xiàn)專員根據(jù)功能設(shè)計進(jìn)行高性能的業(yè)務(wù)邏輯處理實現(xiàn)和外部接口的設(shè)計和實現(xiàn);由頁面開發(fā)人員負(fù)責(zé)實現(xiàn)人機交互;測試人員負(fù)責(zé)對系統(tǒng)進(jìn)行全過程的測試和質(zhì)量監(jiān)督;專業(yè)化實施人員可快速高效的進(jìn)行系統(tǒng)實施和在線維護(hù),售后服務(wù)工作也將由專人負(fù)責(zé);

           通過恰當(dāng)和合理的分工,將軟件研發(fā)過程中的各個環(huán)節(jié)進(jìn)行拆分,從而將復(fù)雜的軟件工程分解成一個個相對獨立且又緊密關(guān)聯(lián)的工作項,從而有效的降低了軟件開發(fā)過程中的困難度和風(fēng)險性;項目經(jīng)理把分解后的工作項交給項目組中的合適項目成員,并根據(jù)項目組成員的能力、工作難度和工作量,制定出科學(xué)的項目計劃;同時,項目組成員在項目經(jīng)理的協(xié)調(diào)和管理下進(jìn)行密切的分工合作,此舉即能調(diào)動項目組成員的其工作積極性,又能使他們將工作、興趣和個人職業(yè)成長規(guī)劃進(jìn)行有效的結(jié)合,從而使其在技能、收入和社會認(rèn)可度等諸多方面得到快速成長,達(dá)到人盡其材,材盡其用的目的。通過使用專業(yè)的人做專業(yè)的事,公司將在人員分工、資源使用和業(yè)務(wù)拓展等領(lǐng)域走向?qū)I(yè)化、規(guī)?;?,最終成為專業(yè)且強大的產(chǎn)業(yè)實體。

           但此開發(fā)模式也具有相當(dāng)?shù)木窒扌?!其一,如何合理的利用項目組資源?項目組成員因其性格、能力和興趣各有不同,如何能將他們按項目分工和角色組成需要,進(jìn)行專業(yè)化訓(xùn)練和培養(yǎng);其二,因項目組成員長期單一職能的工作,與其它環(huán)節(jié)的交叉和交流都受到限制,對其未來的全面發(fā)展和綜合成長都很不利;其三、各角色之間的分工、合作與工業(yè)化生產(chǎn)中的生產(chǎn)線相似,那么,建立與之相適應(yīng)的質(zhì)量保證體系,保證各工序之間生產(chǎn)產(chǎn)品的質(zhì)量,從而從事實上提升軟件產(chǎn)品的整體質(zhì)量?

           通過對這三類開發(fā)模式的分析,我們可以看出,它們各有合理性,也又具有的相當(dāng)?shù)木窒扌浴?/span>

           全能型開發(fā)模式是早期的CS類項目開發(fā)的主要模式,其適用于哪些規(guī)模小,程序員少的小規(guī)模IT開發(fā)企業(yè)進(jìn)行小型項目的開發(fā)中。但對于那些工期較長、業(yè)務(wù)范疇廣、復(fù)雜度較大的項目,此種開發(fā)模板將采用將導(dǎo)致風(fēng)險最大化,失敗幾乎是其唯一的結(jié)局。

           英雄型開發(fā)模式,因項目組成員領(lǐng)域化的分工和合作,使它在通用型復(fù)合類產(chǎn)品開發(fā)中具有優(yōu)勢。通過對產(chǎn)品的各組成部份進(jìn)行持續(xù)的改進(jìn)和迭代性開發(fā),使產(chǎn)品在功能、性能、用戶體驗等方面得到持續(xù)的改善和提升,從而有利于產(chǎn)品拓展并在此過程中做大做強,最終取得競爭優(yōu)勢。但此開發(fā)模式也將導(dǎo)致項目組成員之間的工作協(xié)調(diào)、技術(shù)互用等方面存在諸多不便;另外,因領(lǐng)域的專業(yè)性和不可替換性,也就限制了公司在處理關(guān)健人員的流動性方面存在諸多困難,并在核心競爭力的保證方面存在著很大風(fēng)險。

           專業(yè)型開發(fā)模式,通過對人員進(jìn)行專業(yè)化分工,從而在軟件開發(fā)過程中最大的利用了人力資源,提升軟件的生產(chǎn)效率,并降低了軟件的從業(yè)門檻。此方式在新形式下的項目開發(fā)和產(chǎn)品研發(fā)中都具有相當(dāng)?shù)母偁幜?,也易有利于保證公司的核心競爭力。但采用此種開發(fā)模式時,需要完善內(nèi)部的人員激勵機制,保證各角色的從業(yè)人員都有與之適應(yīng)的職位規(guī)劃和發(fā)展模式,并能根據(jù)項目組成員所處階段的需要,提供相應(yīng)的技能培訓(xùn)和交流機會,從而促進(jìn)其成長,激勵其上進(jìn)。

           總之,采取何種開發(fā)模式,要根據(jù)公司的實際業(yè)務(wù)情況,發(fā)展規(guī)劃和人員構(gòu)成,進(jìn)行科學(xué)的分析之后,再采取行動、從而得到具有延續(xù)性和競爭性,并與自身相匹配的軟件開發(fā)模式。

                                                                   2009/4/20

    posted @ 2009-04-21 21:52 lbom 閱讀(1880) | 評論 (2)編輯 收藏

             

    今天,在陪夫人逛街回來的路上,看到一幕慘劇的發(fā)生:一位中年男子,從家中跳樓而下,墜落于堅硬的水泥地面上,當(dāng)場身亡!

    人生為何?為已?為親?還是為他?

    人生為已,就應(yīng)該珍惜自己的生命,為自己這短暫的一生中,充實、幸福和快樂的活著,而不能因為暫時的挫折、失敗而絕望和放棄;人生漫漫而無現(xiàn)存路,需要自己去探索和開拓,在此過程中,必然會經(jīng)歷曲折和無法避免的挫折。但是,不經(jīng)歷風(fēng)雨,如何能見彩虹!挫折過后,往往就伴隨著一段平坦的直道;人生艱難,生活、事業(yè)、家庭、社會各種矛盾在我這會聚,理不清也扯不斷!既然如此,何不干脆看開,將不可調(diào)和的矛盾進(jìn)行暫時地休眠,讓時間這個解決矛盾的最好的潤滑劑來慢慢解決它。

    人生為親,為父母:他們含辛茹苦的將你從無到有、從幼養(yǎng)成,而你卻要在他們需要照顧和看護(hù)的年齡離他們而去!你忍心嗎!為妻:相汝以沫幾十年、同床共枕伴一生!鍋碗瓢盆一屋住,酸甜苦辣是生活。你就忍心在她人生路中間,正需你堅強的肩膀作支撐時,卻拋下她一人孤苦的走在這漫長的人生路上,你安心嗎?人生為子:父親是兒女的榜樣和偶像,他們需要借助你那成熟的智慧來打開事業(yè)的大門,也需要你那豐富的閱歷來開拓自己的人生路,更需要你成功的經(jīng)驗來保護(hù)雛鳥并解決初飛時所遇到的種種風(fēng)險!在這種關(guān)鍵的時候,你卻拋棄了他,你放心嗎?

    人生為他,為朋友兄弟:有多少美好時光值得回憶,有多少美妙經(jīng)歷值得回味,又有多少坎坷擔(dān)當(dāng)值得珍惜!你就此離開,從此兄弟聚首少一人,朋友舉杯缺一環(huán)!為事業(yè):你正值人生當(dāng)年,恰逢事業(yè)當(dāng)期,失敗你經(jīng)歷,成功應(yīng)有你,酸甜苦辣都嘗遍,還有什么過不去?為社會:當(dāng)今社會多少不平事,何必事事放我心!不必為人先,也不全落后;比上我不足,哪我就比下,實在比不過,阿Q一把也不錯!

    生命如此脆弱,稍有不慎就將墜落:走在路上被車撞死,走下樓下被東西砸死,乘車墜橋而死,去醫(yī)院被錯藥藥死,上班被累死,下班被煩死,既然如此,何必再來一個自己尋死呢!

    請珍惜生命,愛護(hù)自己!

     

    20090330于家中

    posted @ 2009-04-13 15:51 lbom 閱讀(137) | 評論 (0)編輯 收藏

            項目組使用潤乾報表已一年多了,說實話,潤乾報表在國內(nèi)同類產(chǎn)品中屬于非常不錯的最好的報表開發(fā)和應(yīng)用產(chǎn)品。相應(yīng)的支持也比較到位,使用人員及交流社區(qū)也開展的很合適。在這先給它們作個廣告?。?!
            在項目中使用潤乾報表,對數(shù)據(jù)進(jìn)行專業(yè)的報表應(yīng)用和開發(fā),我對其作簡單總結(jié):
            1)對其服務(wù)器運行系統(tǒng)進(jìn)行項目性客戶化開發(fā),從而利用項目中的權(quán)限管理和模塊,實現(xiàn)對報表進(jìn)行訪問控制。否則,這對企業(yè)級應(yīng)用將是一個非常大的考驗。
            2)潤乾報表自帶的參數(shù)生成模塊、報表運行載體的樣式、風(fēng)格都極其簡陋,與項目的實際風(fēng)格可能存在很大的差距。因此必需對其進(jìn)行深入的擴展和開發(fā)。我們項目組的經(jīng)驗就是單獨開發(fā)參數(shù)生成模塊和潤乾報表載體,如此才保證了報表中心與項目的用戶體驗和交互性的一致性。
            3)為了更好的利用項目組資源,我們將潤乾報表開發(fā)人員獨立出來,形成專門的報表開發(fā)團隊。此團隊負(fù)責(zé)根據(jù)業(yè)務(wù)的需要,利用潤乾報表開發(fā)工具進(jìn)行報表開發(fā),即開發(fā).raq報表文件。此部份人員可從項目組的普通成員和新進(jìn)人員中進(jìn)行培養(yǎng),而無需占用大量的項目組中中高級開發(fā)人員資源,從而節(jié)約了項目組的資源。
            4)潤乾報表對過JSP標(biāo)簽包含在jsp頁面中進(jìn)行加裁我運行。我們稱此jsp頁面為潤乾報表運行載體。我們根據(jù)潤乾報表的運行載體進(jìn)行了科學(xué)的分類,并根據(jù)分類開發(fā)出統(tǒng)一的報表運行載體頁面(jsp)。從而避免針對每個報表文件而開發(fā)與之對應(yīng)的運行載體。此舉也大為減少了項目組的JSP開發(fā)人員的工作量。
            5)建立潤乾報表運行專用配置文件,將報表參數(shù)生成模塊、運行載體及潤乾報表三者之間的關(guān)系進(jìn)行配置化管理,并以此為紐帶,將潤乾報表開發(fā)人員、JSP開發(fā)人員(開發(fā)報表運行載體和報表參數(shù)生成功能)聯(lián)系起來。

             在開發(fā)過程中,我們碰到并解決了如下問題:
             1)填報類潤乾報表在進(jìn)行數(shù)據(jù)驗證時,其提示信息(以js的alert("...")方式提示用戶)成亂碼顯示:此問題是由于潤乾報表在V4.1以后,統(tǒng)一使用UTF-8作編譯編碼。因此,要解決此問題,需要將項目的編碼也改成UTF-8
             2)在潤乾報表的參數(shù)賦值需按序依次進(jìn)行賦值,而不能采用參數(shù)名進(jìn)行統(tǒng)一賦值。因為,如果在潤乾報表的SQL中使用了重復(fù)的參數(shù)進(jìn)行賦值時,會報參數(shù)找不至的錯誤。
             3)在參數(shù)生成模塊中將中文參數(shù)值傳遞給潤乾報表時,會導(dǎo)致少量的參數(shù)值在傳遞過程中發(fā)生改變,如“機油”變成了“箕油”。此問題是由于在urlEncode和urlDecode的bug導(dǎo)致,請在開發(fā)時需特別注意。我們是通過自己對信息進(jìn)行加碼和解碼來解決此bug。
             4)潤乾報表的運行環(huán)境與應(yīng)用服務(wù)器的編碼方式有關(guān):我們項目和報表中心的編碼方式為UTF-8,但運用服務(wù)器(WAS6.1)的編碼方式為GBK時,通過參數(shù)生成功能將中文參數(shù)傳遞給潤乾報表時,會出現(xiàn)亂碼問題。在將WAS的輸出和運行編碼改成UTF-8后,才解決此問題。


    posted @ 2009-03-05 23:08 lbom 閱讀(8014) | 評論 (24)編輯 收藏

            前段時間,項目組安排同事進(jìn)行項目移植,并考慮在其過程中進(jìn)行技術(shù)預(yù)研等相關(guān)工作,以對項目進(jìn)行優(yōu)化;
            在此過程中,有同事誤解面向?qū)ο蠡_發(fā)的精髓,在匆匆了了解JavaScript面向?qū)ο蟮姆椒ê褪纠?,對項目中的公共門戶頭以對象的方式進(jìn)行重寫。結(jié)果,將原30行的單一文件代碼變成了400多行,并分布于多個文件了。
            在拿到此結(jié)果之后,我是哭笑不得,于是得出了:“新技術(shù)的引入必需能夠提高生產(chǎn)效率或降低工作難度,否則,沒有引入的必要”這句話。

    posted @ 2009-02-21 20:52 lbom 閱讀(1323) | 評論 (3)編輯 收藏

     

    總是聽說Vista在軟件兼容性上有諸多問題,且一直未得到很好的解決,由于一直使用XP,對此也就不太在意。但是,因工作因素,需要升級我的飯碗(購買新筆記本,操作系統(tǒng)為vista)后,麻煩果然來了:

         先是Oracle數(shù)據(jù)庫安裝不了。還好,我在開發(fā)時可以使用公司的數(shù)據(jù)庫進(jìn)行開發(fā),不在本機安裝數(shù)據(jù)庫還可節(jié)約一筆硬盤空間和內(nèi)存。故其影響并不大,只是在下班離開公司后,沒時使用數(shù)據(jù)庫而已。

         安裝Eclipse,繼續(xù)java項目開發(fā),未發(fā)現(xiàn)兼容性問題;

         成功安裝Tomcat(版本號為5.5.17),但在啟動時,發(fā)現(xiàn)其只能用管理員身份進(jìn)行啟動,而無法向往常一樣,通過開始菜單直接啟動。進(jìn)入Eclipse,啟動項目(WebApplication),發(fā)現(xiàn)麻煩來了,不管我用何種方式,TomcatServer一直報服務(wù)超時,不能正常啟動!

         唉,難道要我重新恢復(fù)XP嗎,這可不是一張恢復(fù)盤的問題,而是我花了兩天時間,進(jìn)行操作系統(tǒng)和相關(guān)相關(guān)軟件安裝,我的媽也??!

         到網(wǎng)上查找相關(guān)資料,也未獲取明確的解決之道;到MS支持網(wǎng)站,沒找到合適的方案;問周邊同事,得到N種可能的解決方式;經(jīng)過一天時間,逐個試驗,終獲解決之道。

          可在環(huán)境操作系統(tǒng)變量中添加classpath項,其值如:C:/Program Files/Java/jdk1.5.0_11/lib;C:/Program Files/Java/jdk1.5.0_11/lib/tools.jar

    posted @ 2007-12-29 14:52 lbom 閱讀(4310) | 評論 (8)編輯 收藏

    昨日,在將應(yīng)用程序(JSF應(yīng)用,其中包含Tiles包)發(fā)布至測試服務(wù)器(Solaris8+Tomcate5.5)時,發(fā)現(xiàn)其不能正常運行,其錯誤如下:
    ......
    2006-11-1 17:09:54 org.apache.tiles.servlets.TilesServlet init
    信息: Initializing TilesServlet
    2006-11-1 17:09:54 org.apache.tiles.servlets.TilesServlet readFactoryConfig
    信息: CONFIG FILES DEFINED IN WEB.XML
    信息: initializing definitions factory...ets.TilesServlet initDefinitionsFactory
    2006-11-1 17:09:54 org.apache.tiles.servlets.TilesServlet saveExceptionMessage
    警告: Caught exception when initializing definitions factory
    2006-11-1 17:09:54 org.apache.tiles.servlets.TilesServlet saveExceptionMessage
    警告: I/O Error reading definitions.
    2006-11-1 17:09:54 org.apache.tiles.servlets.TilesServlet saveExceptionMessage
    s.
    2006-11-1 17:09:54 org.apache.tiles.servlets.TilesServlet saveExceptionMessage
    警告: Caught exception when initializing definitions factory
    2006-11-1 17:09:54 org.apache.tiles.servlets.TilesServlet saveExceptionMessage
    警告: I/O Error reading definitions.
    2006-11-1 17:09:54 org.apache.tiles.servlets.TilesServlet saveExceptionMessage
    警告: javax.servlet.ServletException: I/O Error reading definitions.
    2006-11-1 17:09:55 org.apache.coyote.http11.Http11BaseProtocol start
    信息: Starting Coyote HTTP/1.1 on http-8800
    ......

    根據(jù)此錯誤分析,是由于TilesServlet未正確讀取tiles.xml配置文件,但在對tiles.xml進(jìn)行權(quán)限變更后,也未解決此問題!!!
    但是,此應(yīng)用在開發(fā)環(huán)境下是正常的,如何是好??
    我和同事在對比開發(fā)環(huán)境和測試環(huán)境之后,發(fā)現(xiàn)二者的運行環(huán)境差別只有操作系統(tǒng)(UNIX<>WINDOWS XP);
    搜索Google和BeiDu,找到一篇相類似的報到,據(jù)其所說,當(dāng)他的系統(tǒng)在斷開網(wǎng)絡(luò)后會出現(xiàn)類似的情況,難道是TilesServlet必需聯(lián)上互聯(lián)網(wǎng)?
    在分析tiles.xml后,發(fā)現(xiàn),其中有如下一句:
    ???<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN" "原來,當(dāng)互聯(lián)網(wǎng)斷開之后,不能從tiles-config_2_0.dtd中獲取驗證,導(dǎo)致此文件解釋失敗,將此刪除之后,系統(tǒng)就可正常部屬在測試環(huán)境之中了.


    懷疑論者的 JSF: JSF 組件開發(fā)

    省時運動使得構(gòu)建 JSF 組件輕而易舉

    developerWorks
    文檔選項
    將此頁作為電子郵件發(fā)送

    將此頁作為電子郵件發(fā)送

    未顯示需要 JavaScript 的文檔選項

    Discuss

    Sample code


    對此頁的評價

    幫助我們改進(jìn)這些內(nèi)容


    級別: 中級

    Rick Hightower , CTO, ArcMind

    2005 年 8 月 16 日

    在四部分的 懷疑論者的 JSF 系列的最后一期中,Rick Hightower 介紹了省時運動,它可以一次或永遠(yuǎn)地說服您:JSF 組件開發(fā)要比您想像的更容易。

    組件模型的關(guān)鍵考驗就是:能否從第三方供應(yīng)商購買組件,并把它們插入應(yīng)用程序?與可購買可視 Swing 組件一樣,也可以購買 Java ServerFaces (JSF) 組件!需要一個好玩的日歷?可以在開源實現(xiàn)和商業(yè)組件之間選擇。可以選擇購買一個,而不是自行開發(fā)復(fù)雜的基于 Web 的 GUI 組件。

    JSF 擁有一個與 AWT 的 GUI 組件模型類似的組件模型。可以用 JSF 創(chuàng)建可重用組件。但不幸的是,存在一個誤解:用 JSF 創(chuàng)建組件很困難。不要相信這些從未試過它的人們的 FUD!開發(fā) JSF 組件并不困難。由于不用一遍又一遍重復(fù)相同的代碼,可以節(jié)約時間。一旦創(chuàng)建了組件,就可以容易地把組件拖到任何 JSP、甚至任何 JSF 表單中,如果正在處理的站點有 250 個頁面,這就很重要了。JSF 的大多數(shù)功能來自基類。因為所有的繁重工作都由 API 和基類完成,所以 JSF 把組件創(chuàng)建變得很容易。

    貫穿這個系列,我一直在試圖幫助您克服造成許多 Java 開發(fā)人員逃避使用 JSF 技術(shù)的 FUD。我討論了對這項技術(shù)的基本誤解,介紹了它的底層框架和它最有價值的開發(fā)特性。有了這些基礎(chǔ)工作之后,我認(rèn)為您已經(jīng)可以采取行動,開發(fā)自己的定制 JSF 組件了。使用 JSF 的東西,我敢保證要比您想像的要更加容易,而且從節(jié)約的時間和精力上來說,回報如此之多,多得不能忽略。

    這篇文章中的示例是用 JDK 1.5 和 Tomcat 開發(fā)的。請單擊頁面頂部的 示例代碼 下載示例源代碼。注意,與以前的文章不同,這篇文章沒有關(guān)聯(lián)的 build 文件,因為我特意把它留給您作為一個練習(xí)了。只要設(shè)置 IDE 或編譯器,把 /src 中的類編譯到 /webapp/WEB-INF/classes,并在 /webapp/WEB-INF/lib 中包含所有 JAR 文件(以及 servlet-api.jarjsp-api.jar,它們包含在 Tomcat 中)。

    JSF 組件模型

    JSF 組件模型與 AWT GUI 組件模型類似。它有事件和屬性,就像 Swing 組件模型一樣。它也有包含組件的容器,容器也是組件,也可以由其他容器包含。從理論上說,JSF 組件模型分離自 HTML 和 JSP。JSF 自帶的標(biāo)準(zhǔn)組件集里面有 JSP 綁定,可以生成 HTML 渲染。

    JSF 組件的示例包括日歷輸入組件和 HTML 富文本輸入組件。您可能從來沒時間去編寫這樣的組件,但是如果它們已經(jīng)存在,那會如何呢?通過把常用功能變成商品,組件模型降低了向 Web 應(yīng)用程序添加更多功能的門檻。

    組件的功能通常圍繞著兩個動作:解碼和編碼數(shù)據(jù)。解碼 是把進(jìn)入的請求參數(shù)轉(zhuǎn)換成組件的值的過程。編碼 是把組件的當(dāng)前值轉(zhuǎn)換成對應(yīng)的標(biāo)記(也就是 HTML)的過程。

    JSF 框架提供了兩個選項用于編碼和解碼數(shù)據(jù)。使用直接實現(xiàn) 方式,組件自己實現(xiàn)解碼和編碼。使用委托實現(xiàn) 方式,組件委托渲染器進(jìn)行編碼和解碼。如果選擇委托實現(xiàn),可以把組件與不同的渲染器關(guān)聯(lián),會在頁面上以不同的方式渲染組件;例如多選列表框和一列復(fù)選框。

    因此,JSF 組件由兩部分構(gòu)成:組件和渲染器。JSF 組件 類定義 UI 組件的狀態(tài)和行為;渲染器 定義如何從請求讀取組件、如何顯示組件 —— 通常通過 HTML 渲染。渲染器把組件的值轉(zhuǎn)換成適當(dāng)?shù)臉?biāo)記。事件排隊和性能驗證發(fā)生在組件內(nèi)部。

    在圖 1 中可以看到數(shù)據(jù)編碼和解碼出現(xiàn)在 JSF 生命周期中的什么階段(到現(xiàn)在,我希望您已經(jīng)熟悉 JSF 生命周期了)。


    圖 1. JSF 生命周期和 JSF 組件
    JSF 組件和 JSF 生命周期
    提示!

    在許多情況下,可以在保持組件本身不變的情況下,通過改變渲染而簡化開發(fā)過程。在這些情況下,可以編寫定制渲染器而不是定制組件。

    更多組件概念

    所有 JSF 組件的基類是 UIComponent。在開發(fā)自己的組件時,需要繼承 UIComponentBase,它擴展了 UIComponent 并提供了 UIComponent 中所有抽象方法的默認(rèn)實現(xiàn)。

    組件擁有雙親和標(biāo)識符。每個組件都關(guān)聯(lián)著一個組件類型,組件類型用于在 face 的上下文配置文件(faces-config.xml)中登記組件??梢杂?JSF-EL (表達(dá)式語言)把 JSF 組件綁定到受管理的 bean 屬性。可以把表達(dá)式關(guān)聯(lián)到組件上的任何屬性,這樣就允許用 JSF-EL 設(shè)置組件的屬性值。在創(chuàng)建使用 JSF-EL 綁定的組件屬性時,需要創(chuàng)建值綁定表達(dá)式。在調(diào)用綁定屬性的 getter 方法時,除非 setter 方法已經(jīng)設(shè)置了值,否則 getter 方法必須用值綁定獲得值。

    組件可以作為 ValueHolderEditableValueHolderValueHolder 與一個或多個 ValidatorConverter 相關(guān)聯(lián);所以 JSF UI 組件也與 ValidatorConverter 關(guān)聯(lián)(請參閱 參考資料 獲得更多關(guān)于 JSF 驗證和轉(zhuǎn)換的內(nèi)容。)

    像表單字段組件這樣的組件擁有一個 ValueBinding,它必須綁定到 JavaBean 的讀寫屬性。組件可以調(diào)用 getParent 方法訪問它們的雙親,也可以調(diào)用 getChildren 方法訪問它們的子女。組件也可以有 facet 組件,facet 組件是當(dāng)前組件的子組件,可以調(diào)用 getFacets 方法訪問它,這個方法返回一個映射。Facets 是著名的子組件。

    這里描述的許多組件的概念將會是接下來展示的示例的一部分,所以請記住它們!



    回頁首


    JSF 樣式的 Hello World!

    我們用一個又好又容易的示例來開始 JSF 組件的開發(fā):我將展示如何渲染 Label 標(biāo)記(示例:<label>Form Test</label>)。

    下面是我要采取的步驟:

    1. 擴展 UIComponent
      • 創(chuàng)建一個類,擴展 UIComponent
      • 保存組件狀態(tài)
      • 用 faces-config.xml 登記組件
    2. 定義渲染器或者內(nèi)聯(lián)地實現(xiàn)它
      • 覆蓋 encode
      • 覆蓋 decode
      • 用 faces-config.xml 登記渲染器
    3. 創(chuàng)建定制標(biāo)記,繼承 UIComponentTag
      • 返回渲染器類型
      • 返回組件類型
      • 設(shè)置可能使用 JSF 表達(dá)式的屬性

    Label 示例將演示 JSF 組件開發(fā)的以下方面:

    • 創(chuàng)建組件
    • 直接實現(xiàn)渲染器
    • 編碼輸出
    • 把定制標(biāo)記與組件關(guān)聯(lián)

    返回 圖 1,可以看到在這個示例中會有兩個生命周期屬性在活動。它們是 Apply Request ValueRender Response。

    在圖 2 中,可以看到在 JSP 中如何使用 Label 標(biāo)記的(<label>Form Test</label>)。


    圖 2. 在 JSP 中使用 JSF 標(biāo)記
    在 JSP 中使用 JSF 標(biāo)記

    第 1 步:擴展 UIComponent

    第一步是創(chuàng)建一個組件,繼承 UIOutput,后者是 UIComponent 的子類。 除了繼承這個類之外,我還添加了組件將會顯示的 label 屬性,如清單 1 所示:


    清單 1. 繼承 UIComponent 并添加 label
    
    import java.io.IOException;
    
    import javax.faces.component.UIOutput;
    import javax.faces.context.FacesContext;
    import javax.faces.context.ResponseWriter;
    
    public class LabelComponent extends UIOutput{
    
    	private String label;
    
    	public String getLabel() {
    		return label;
    	}
    	public void setLabel(String label) {
    		this.label = label;
    	}
    ...
    

    接下來要做的是保存組件狀態(tài)。JSF 通常通過會話、隱藏表單字段、cookies 等進(jìn)行實際的存儲和狀態(tài)管理。(這通常是用戶配置的設(shè)置)。要保存組件狀態(tài),需要覆蓋組件的 saveStaterestoreState 方法,如清單 2 所示:


    清單 2. 保存組件狀態(tài)
    
        @Override
        public Object saveState(FacesContext context) {
            Object values[] = new Object[2];
            values[0] = super.saveState(context);
            values[1] = label;
            return ((Object) (values));
        }
    
        @Override
        public void restoreState(FacesContext context, Object state) {
            Object values[] = (Object[])state;
            super.restoreState(context, values[0]);
            label = (String)values[1];
        }
     

    可以注意到,我使用的是 JDK 1.5。我對編譯器進(jìn)行了設(shè)置,所以我必須指定 override 注釋,以便指明哪些方法要覆蓋基類的方法。這樣做可以更容易地標(biāo)識出 JSF 的鉤子在哪。

    創(chuàng)建組件的最后一步是用 faces-config.xml 登記它,如下所示:

    
    <faces-config>
    
       <component>
          <component-type>simple.Label</component-type>
          <component-class>
             arcmind.simple.LabelComponent
          </component-class>
       </component>
    ...
    

    第 2 步:定義渲染器

    下面要做的是內(nèi)聯(lián)地定義渲染器的功能。稍后我會介紹如何創(chuàng)建獨立的渲染器。現(xiàn)在,先從編碼 Label 組件的輸出、顯示 label 開始,如清單 3 所示:


    清單 3. 編碼組件的輸出
    
    public class LabelComponent extends UIOutput{
    	...
    	public void encodeBegin(FacesContext context) 
    					throws IOException {
    
    		ResponseWriter writer = 
    			context.getResponseWriter();
    
    		writer.startElement("label", this);
            	            writer.write(label);
            	            writer.endElement("label");
            	            writer.flush();
    	}
    	...
    }
    

    注意,響應(yīng)寫入器(javax.faces.context.ResponseWriter)可以容易地處理 HTML 這樣的標(biāo)記語言。清單 3 的代碼輸出 <label> 元素體內(nèi)的 label 的值。

    下面顯示的 family 屬性用來把 Label 組件與渲染器關(guān)聯(lián)。雖然目前 Label 組件還不需要這個屬性(因為還沒有獨立的渲染器),但是在這篇文章后面,在介紹如何創(chuàng)建獨立渲染器的時候,會需要它。

    
    public class LabelComponent extends UIOutput{
    	...
    	public String getFamily(){
    		return "simple.Label";
    	}
    	...
    }
    

    插曲:研究 JSF-RI

    如果正在使用來自 Sun Microsystems 的 JSF 參考實現(xiàn)(不是 MyFaces 實現(xiàn)),那么就不得不在組件創(chuàng)建代碼中添加下面一段:

    
    public void encodeEnd(FacesContext context) 
    			throws IOException {
    	return;
    }
    
    public void decode(FacesContext context) {
    	return;
    }
    

    Sun 的 JSF RI 期望,在組件沒有渲染器的時候,渲染器會發(fā)送一個空指針異常。MyFaces 實現(xiàn)不要求處理這個需求,但是在代碼中包含以上方法依然是個好主意,這樣組件既可以在 MyFaces 環(huán)境中工作也可以在 JSF RI 環(huán)境中工作了。

    MyFaces 更好!

    如果正在使用 Sun JSF RI 或其他替代品,那么請幫自己一個忙,轉(zhuǎn)到 MyFaces。雖然 MyFaces 不總是 更好的實現(xiàn),但是目前它是。它的錯誤消息要比 Sun JSF RI 的好,而這個框架相比之下更嚴(yán)格。

    第 3 步:創(chuàng)建定制標(biāo)記

    JSF 組件不是天生綁定到 JSP 上的。要連接起 JSP 世界和 JSF 世界,需要能夠返回組件類型的定制標(biāo)記(然后在 faces-context 文件中登記)和渲染器,如圖 3 所示。


    圖 3. 連接 JSF 和 JSP
    連接 JSF 和 JSP

    注意,由于沒有獨立的渲染器,所以可以給 getRendererType() 返回 null 值。還請注意,必須已經(jīng)把 label 屬性的值從定制標(biāo)記設(shè)置到組件上,如下所示:

    
    [LabelTag.java]
    
    public class LabelTag extends UIComponentTag {
    …
    protected void setProperties(UIComponent component) {
    	/* you have to call the super class */
    	super.setProperties(component);
    	((LabelComponent)component).setLabel(label);
    }
    
    

    記住,Tag 設(shè)置從 JSP 到 Label 組件的綁定,如圖 4 所示。


    圖 4. 綁定 JSF 和 JSP
    綁定 JSF 和 JSP

    現(xiàn)在要做的全部工作就是創(chuàng)建一個 TLD(標(biāo)記庫描述符)文件,以登記定制標(biāo)記,如清單 4 所示:


    清單 4. 登記定制標(biāo)記
    
    [arcmind.tld]
    
    <taglib>
       <tlib-version>0.03</tlib-version>
       <jsp-version>1.2</jsp-version>
       <short-name>arcmind</short-name>
       <uri>http://arcmind.com/jsf/component/tags</uri>
       <description>ArcMind tags</description>
       
       <tag>
          <name>slabel</name>
          <tag-class>arcmind.simple.LabelTag</tag-class>
          <attribute> 
             <name>label</name> 
             <description>The value of the label</description>
          </attribute> 
       </tag>
    ...
    

    一旦定義了 TLD 文件,就可以開始在 JSP 中使用標(biāo)記了,如下面示例所示:

    
    [test.jsp]
    <%@ taglib prefix="arcmind" 
             uri="http://arcmind.com/jsf/component/tags" %>
                ...
    	<arcmind:slabel label="Form Test"/>
    

    現(xiàn)在就可以了 —— 開發(fā)一個簡單的 JSP 組件不需要更多了。但是如果想創(chuàng)建稍微復(fù)雜一些的組件,針對更復(fù)雜的使用場景時該怎么辦?請繼續(xù)往下看。



    回頁首


    復(fù)合組件

    在下一個示例中,我將介紹如何創(chuàng)建這樣一個組件(和標(biāo)記),它可以記住最后一個人離開的位置。Field 組件把多個組件的工作組合到一個組件中。復(fù)合組件是 JSF 組件開發(fā)的重點,會節(jié)約大量時間!

    Field 組件把標(biāo)簽、文本輸入和消息功能組合到一個組件。Field 的文本輸入功能允許用戶輸入文本。如果有問題(例如輸入不正確),它的標(biāo)簽功能會顯示紅色,還會顯示星號(*)表示必需的字段。它的消息功能允許它在必要的時候?qū)懗龀鲥e消息。

    Field 組件示例演示了以下內(nèi)容:

    • UIInput 組件
    • 處理值綁定和組件屬性
    • 解碼來自請求參數(shù)的值
    • 處理出錯消息

    與 Label 組件不同,F(xiàn)ield 組件使用獨立渲染器。如果為一個基于 HTML 的應(yīng)用程序開發(fā)組件,那么不要費力使用獨立渲染器。這么做是額外的無用功。如果正在開發(fā)許多 JSF 組件,打算賣給客戶,而針對的客戶又不止一個,那么就需要獨立的渲染器了。簡而言之,渲染器適用于商業(yè)框架的開發(fā)人員,不適用于開發(fā)內(nèi)部 Web 應(yīng)用程序的應(yīng)用程序開發(fā)人員。

    了解代碼

    由于我已經(jīng)介紹了創(chuàng)建組件、定義渲染器以及創(chuàng)建定制標(biāo)記的基本步驟,所以這次我讓代碼自己說話,我只點出幾個重要的細(xì)節(jié)。在清單 5 中,可以看到在典型的應(yīng)用程序示例中如何使用 Field 標(biāo)記的:


    清單 5. Field 標(biāo)記
    
    <f:view>
      <h2>CD Form</h2>
          
      <h:form id="cdForm">
            
        <h:inputHidden id="rowIndex" value="#{CDManagerBean.rowIndex}" /> 
          
          	
            <arcmind:field id="title"
                               value="#{CDManagerBean.title}"  
                               label="Title:"
                               errorStyleClass="errorText"
                               required="true" /> <br />
    		
            <arcmind:field id="artist"
                               value="#{CDManagerBean.artist}"  
                               label="Artist:"
                               errorStyleClass="errorText"
                               required="true" /> <br />
          	
            <arcmind:field id="price"
                               value="#{CDManagerBean.price}"  
                               label="CD Price:"
                               errorStyleClass="errorText"
                               required="true">
               <f:validateDoubleRange maximum="1000.0" minimum="1.0"/>
            </arcmind:field>
    

    以上標(biāo)記輸出以下 HTML:

    
    <label style="" class="errorText">Artist*</label>
    <input type="text" id="cdForm:artist " 
           name=" cdForm:artist " />
    Artist is blank, it must contain characters
    

    圖 5 顯示了瀏覽器中這些內(nèi)容可能顯示的效果。


    圖 5. Field 組件
    Field 組件

    清單 6 顯示了創(chuàng)建 Field 組件的代碼。因為這個組件負(fù)責(zé)輸入文本而不僅僅是輸出它(像 Label 那樣),所以要從繼承 UIInput 開始,而不是從繼承 UIOutput 開始。


    清單 6. Field 繼承 UIInput
    
    package com.arcmind.jsfquickstart;
    
    import javax.faces.component.UIInput;
    import javax.faces.context.FacesContext;
    
    
    /**
     * @author Richard Hightower
     *  
     */
    public class FieldComponent extends UIInput {
    
    	private String label;
    
        @Override
         public Object saveState(FacesContext context) {
            Object values[] = new Object[2];
            values[0] = super.saveState(context);
            values[1] = label;
            return ((Object) (values));
        }
    
        @Override
        public void restoreState(FacesContext context, Object state) {
            Object values[] = (Object[])state;
            super.restoreState(context, values[0]);
            label = (String)values[1];
        }
        
    	public FieldComponent (){
    		this.setRendererType("arcmind.Field");
    	}
    
    	/**
    	 * @return Returns the label.
    	 */
    	public String getLabel() {
    		return label;
    	}
    
    	/**
    	 * @param label
    	 *  The label to set.
    	 */
    	public void setLabel(String label) {
    		this.label = label;
    	}
    
    	
    	@Override
    	public String getFamily() {
    		return "arcmind.Field";
    	}
    
    
    	public boolean isError() {
    		return !this.isValid();
    	}
    
    }
    

    可以注意到,代表片段中遺漏了編碼方法。這是因為編碼和解碼發(fā)生在獨立的渲染器中。我稍后會介紹它。

    值綁定和組件屬性

    雖然 Label 組件只有一個屬性(JSP 屬性),可是 Field 組件卻有多個屬性,即 labelerrorStyleerrorStyleClassvaluelabelvalue 屬性位于 Field 組件的核心,而 errorStyleerrorStyleClass 是特定于 HTML 的。因為這些屬性是特定于 HTML 的,所以不需要讓它們作為 Field 組件的屬性;相反,只是把它們作為組件屬性進(jìn)行傳遞,只有渲染器知道這些屬性。

    像使用 Label 組件時一樣,需要用定制標(biāo)記把 Field 組件綁定到 JSP,如清單 7 所示:


    清單 7. 為 FieldComponent 創(chuàng)建定制標(biāo)記
    
    /*
     * Created on Jul 19, 2004
     *
     */
    package com.arcmind.jsfquickstart;
    
    import javax.faces.application.Application;
    import javax.faces.component.UIComponent;
    import javax.faces.context.FacesContext;
    import javax.faces.el.ValueBinding;
    import javax.faces.webapp.UIComponentTag;
    
    
    /**
     * @author Richard Hightower
     *
     */
    public class FieldTag extends UIComponentTag {
    
         private String label;
         private String errorStyleClass="";
         private String errorStyle="";
         private boolean required;
         private String value="";
         
         /**
          * @return Returns the label.
          */
         public String getLabel() {
              return label;
         }
         /**
          * @param label The label to set.
          */
         public void setLabel(String label) {
              this.label = label;
         }
         /**
          * @see javax.faces.webapp.UIComponentTag#setProperties
          * (javax.faces.component.UIComponent)
          */
         @Override
         protected void setProperties(UIComponent component) {
              /* You have to call the super class */
              super.setProperties(component);
              ((FieldComponent)component).setLabel(label);
              component.getAttributes().put("errorStyleClass",
                errorStyleClass);
              component.getAttributes().put("errorStyle",errorStyle);
              ((FieldComponent)component).setRequired(required);
         
         
             FacesContext context = FacesContext.getCurrentInstance();
             Application application = context.getApplication();
             ValueBinding binding = application.createValueBinding(value);
             component.setValueBinding("value", binding);
              
         }
         /**
          * @see javax.faces.webapp.UIComponentTag#getComponentType()
          */
         @Override
         public String getComponentType() {
              return "arcmind.Field";     
         }
    
         /**
          * @see javax.faces.webapp.UIComponentTag#getRendererType()
          */
         @Override
         public String getRendererType() {
              return "arcmind.Field";     
         }
    
         /**
          * @return Returns the errorStyleClass.
          */
         public String getErrorStyleClass() {
              return errorStyleClass;
         }
         /**
          * @param errorStyleClass The errorStyleClass to set.
          */
         public void setErrorStyleClass(String errorStyleClass) {
              this.errorStyleClass = errorStyleClass;
         }
         
         /**
          * @return Returns the errorStyle.
          */
         public String getErrorStyle() {
              return errorStyle;
         }
         /**
          * @param errorStyle The errorStyle to set.
          */
         public void setErrorStyle(String errorStyle) {
              this.errorStyle = errorStyle;
         }
    
         /**
          * @return Returns the required.
          */
         public boolean isRequired() {
              return required;
         }
         /**
          * @param required The required to set.
          */
         public void setRequired(boolean required) {
              this.required = required;
         }
         
         /**
          * @return Returns the value.
          */
         public String getValue() {
              return value;
         }
         /**
          * @param value The value to set.
          */
         public void setValue(String value) {
              this.value = value;
         }
    }
    

    從概念上說,在上面的代碼和 Label 組件之間找不出太大區(qū)別。但是,在這個示例中,setProperties 方法有些不同:

    
    protected void setProperties(UIComponent component) {
        /* You have to call the super class */
        super.setProperties(component);
        ((FieldComponent)component).setLabel(label);
        component.getAttributes().put("errorStyleClass", 
          errorStyleClass);
        component.getAttributes().put("errorStyle",errorStyle);
    
        ((FieldComponent)component).setRequired(required);
    

    雖然 label 屬性傳遞時的方式與前面的示例相同,但是 errorStyleClasserrorStyle 屬性不是這樣傳遞的。相反,它們被添加到 JSF 組件的屬性映射 中。Renderer 類會使用屬性映射去渲染類和樣式屬性。這個設(shè)置允許特定于 HTML 的代碼從組件脫離。

    這個修訂后的 setProperties 方法實際的值綁定代碼也有些不同,如下所示。

    
    protected void setProperties(UIComponent component) {
          ...	
    	
         FacesContext context = FacesContext.getCurrentInstance();
         Application application = context.getApplication();
         ValueBinding binding = application.createValueBinding(value);
         component.setValueBinding("value", binding);
    

    這個代碼允許 Field 組件的 value 屬性綁定到后臺 bean。出于示例的原因,我把 CDManagerBean 的 title 屬性綁定到 Field 組件,像下面這樣:value="#{CDManagerBean.title}。值綁定是用 Application 對象創(chuàng)建的。Application 對象是創(chuàng)建值綁定的工廠。這個組件擁有保存值綁定的特殊方法,即 setValueBinding;可以有不止一個值綁定。

    獨立渲染器

    最后介紹渲染器,但并不是說它不重要。獨立渲染器必須考慮的主要問題是解碼(輸入) 和編碼(輸出)。Field 組件做的編碼比解碼多得多,所以它的渲染器有許多編碼方法,而只有一個解碼方法。在清單 8 中,可以看到 Field 組件的渲染器:


    清單 8. FieldRenderer 擴展自 Renderer
    
    package com.arcmind.jsfquickstart;
    
    import java.io.IOException;
    import java.util.Iterator;
    import java.util.Map;
    
    import javax.faces.application.FacesMessage;
    import javax.faces.component.UIComponent;
    import javax.faces.component.UIInput;
    import javax.faces.context.FacesContext;
    import javax.faces.context.ResponseWriter;
    import javax.faces.convert.Converter;
    import javax.faces.convert.ConverterException;
    import javax.faces.el.ValueBinding;
    import javax.faces.render.Renderer;
    
    /**
     * @author Richard Hightower
     *
     */
    public class FieldRenderer extends Renderer {
    
    
      @Override 
       public Object getConvertedValue(FacesContext facesContext, UIComponent component, 
         Object submittedValue) throws ConverterException {
            
    
        //Try to find out by value binding
        ValueBinding valueBinding = component.getValueBinding("value");
        if (valueBinding == null) return null;
    
        Class valueType = valueBinding.getType(facesContext);
        if (valueType == null) return null;
    
        if (String.class.equals(valueType)) return submittedValue;    
        if (Object.class.equals(valueType)) return submittedValue;    
    
        Converter converter = ((UIInput) component).getConverter();
        converter =  facesContext.getApplication().createConverter(valueType);
        if (converter != null ) {
            return converter.getAsObject(facesContext, component, (String) submittedValue);
        }else {
            return submittedValue; 
        }
    		
        }
    
       @Override
        public void decode(FacesContext context, UIComponent component) {
            /* Grab the request map from the external context */
           Map requestMap = context.getExternalContext().getRequestParameterMap();
            /* Get client ID, use client ID to grab value from parameters */
           String clientId = component.getClientId(context);
           String value = (String) requestMap.get(clientId);
    		
            FieldComponent fieldComponent = (FieldComponent)component;
              /* Set the submitted value */
            ((UIInput)component).setSubmittedValue(value);
        }
    	
       @Override
        public void encodeBegin(FacesContext context, UIComponent component)
            throws IOException {
            FieldComponent fieldComponent = (FieldComponent) component;
            ResponseWriter writer = context.getResponseWriter();
            encodeLabel(writer,fieldComponent);
            encodeInput(writer,fieldComponent);
            encodeMessage(context, writer, fieldComponent);
            writer.flush();
        }
    
    	
    	
        private void encodeMessage(FacesContext context, ResponseWriter writer, 
          FieldComponent fieldComponent) throws IOException {
            Iterator iter = context.getMessages(fieldComponent.getClientId(context));
            while (iter.hasNext()){
               FacesMessage message = (FacesMessage) iter.next();
               writer.write(message.getDetail());
            }
        }
    
        private void encodeLabel(ResponseWriter writer, FieldComponent 
          fieldComponent) throws IOException{
            writer.startElement("label", fieldComponent);
            if (fieldComponent.isError()) {
                String errorStyleClass = (String) fieldComponent.getAttributes().get("errorStyleClass");
                String errorStyle = (String) fieldComponent.getAttributes().get("errorStyle");
    
                writer.writeAttribute("style", errorStyle, "style");
                writer.writeAttribute("class", errorStyleClass, "class");
            }
            writer.write("" + fieldComponent.getLabel());
            if (fieldComponent.isRequired()) {
                writer.write("*");
            }
           writer.endElement("label");
        }
    	
        private void encodeInput(ResponseWriter writer, FieldComponent 
          fieldComponent) throws IOException{
            FacesContext currentInstance = FacesContext.getCurrentInstance();
            writer.startElement("input", fieldComponent);
            writer.writeAttribute("type", "text", "type");
            writer.writeAttribute("id", fieldComponent.getClientId(currentInstance), "id");
    		writer.writeAttribute("name", fieldComponent.getClientId(currentInstance), "name");
            if(fieldComponent.getValue()!=null)
                writer.writeAttribute("value", fieldComponent.getValue().toString(), "value");
            writer.endElement("input");
        }
    
    }
    

    編碼和解碼

    正如前面提到的,渲染器做的主要工作就是解碼輸入和編碼輸出。我先從解碼開始,因為它是最容易的。 FieldRenderer 的 decode 方法如下所示:

    
    @Override
    public void decode(FacesContext context, UIComponent component) {
           /* Grab the request map from the external context */
         Map requestMap = context.getExternalContext().getRequestParameterMap();
           /* Get client ID, use client ID to grab value from parameters */
         String clientId = component.getClientId(context);
         String value = (String) requestMap.get(clientId);
    		
         FieldComponent fieldComponent = (FieldComponent)component;
           /* Set the submitted value */
         ((UIInput)component).setSubmittedValue(value);
    }
    

    Label 組件不需要進(jìn)行解碼,因為它是一個 UIOutput 組件。Field 組件是一個 UIInput 組件,這意味著它接受輸入,所以 必須 進(jìn)行解碼。decode 方法可以從會話、cookie、頭、請求等處讀取值。在大多數(shù)請問下,decode 方法只是像上面那樣從請求參數(shù)讀取值。Field 渲染器的 decode 方法從組件得到 clientId,以標(biāo)識要查找的請求參數(shù)。給定組件容器的路徑,clientId 被計算成為組件的全限定名稱。而且,因為示例組件在表單中(是個容器),所以它的 clientid 應(yīng)當(dāng)是 nameOfForm:nameOfComponent 這樣的,或者是示例中的 cdForm:artist、cdForm:price、cdForm:title。decode 方法的最后一步是把提交的值保存到組件(稍后會轉(zhuǎn)換并驗證它,請參閱 參考資料 獲取更多關(guān)于驗證和轉(zhuǎn)換的內(nèi)容)。

    編碼方法沒什么驚訝的。它們與 Label 組件中看到的類似。第一個方法 encodeBegin,委托給三個幫助器方法 encodeLabel、encodeInputencodeMessage,如下所示:

    
    @Override
    public void encodeBegin(FacesContext context, UIComponent component)
           throws IOException {
         FieldComponent fieldComponent = (FieldComponent) component;
         ResponseWriter writer = context.getResponseWriter();
         encodeLabel(writer,fieldComponent);
         encodeInput(writer,fieldComponent);
         encodeMessage(context, writer, fieldComponent);
         writer.flush();
    }
    

    encodeLabel 方法負(fù)責(zé)在出錯的時候,把標(biāo)簽的顏色改成紅色(或者在樣式表中指定的其他什么顏色),并用星號 (*) 標(biāo)出必需的字段,如下所示:

    
    private void encodeLabel(ResponseWriter writer, FieldComponent fieldComponent) throws IOException{
         writer.startElement("label", fieldComponent);
         if (fieldComponent.isError()) {
              String errorStyleClass = (String) fieldComponent.getAttributes().get("errorStyleClass");
              String errorStyle = (String) fieldComponent.getAttributes().get("errorStyle");
    
              writer.writeAttribute("style", errorStyle, "style");
              writer.writeAttribute("class", errorStyleClass, "class");
         }
         writer.write("" + fieldComponent.getLabel());
         if (fieldComponent.isRequired()) {
              writer.write("*");
         }
         writer.endElement("label");
    }
    

    首先,encodeLabel 方法檢查是否有錯誤,如果有就輸出 errorStyleerrorStyleClass(更好的版本是只有在它們不為空的時候才輸出 —— 但是我把它留給您做練習(xí)!)。然后幫助器方法會檢查組件是不是必需的字段,如果是,就輸出星號。encodeMessagesencodeInput 方法做的就是這件事,即輸出出錯消息并為 Field 組件生成 HTML 輸入的文本字段。

    注意,神秘方法!

    您可能已經(jīng)注意到,有一個方法我還沒有介紹。這個方法就是這個類中的“黑馬”方法。如果您閱讀 Renderer(所有渲染器都要擴展的抽象類)的 javadoc,您可能會感覺到這樣的方法是不需要的,現(xiàn)有的就足夠了:這就是我最開始時想的。但是,您和我一樣,都錯了!

    實際上,基類 Renderer 并不 自動調(diào)用 Renderer 子類的相關(guān)轉(zhuǎn)換器 —— 即使 Renderer 的 javadoc 和 JSF 規(guī)范建議它這樣做,它也沒做。MyFaces 和 JSF RI 擁有為它們的渲染器執(zhí)行這個魔術(shù)的類(特定于它們的實現(xiàn)),但是在核心 JSF API 中并沒有涉及這項功能。

    相反,需要使用方法 getConvertedValues 鎖定相關(guān)的轉(zhuǎn)換器并調(diào)用它。清單 9 顯示的方法根據(jù)值綁定的類型找到正確的轉(zhuǎn)換器:


    清單 9. getConvertedValues 方法
    
    @Override
     public Object getConvertedValue(FacesContext facesContext, 
       UIComponent component, Object submittedValue) throws ConverterException {
            
         //Try to find out by value binding
         ValueBinding valueBinding = component.getValueBinding("value");
         if (valueBinding == null) return null;
    
         Class valueType = valueBinding.getType(facesContext);
         if (valueType == null) return null;
    
         if (String.class.equals(valueType)) return submittedValue;    
         if (Object.class.equals(valueType)) return submittedValue;    
    
         Converter converter = ((UIInput) component).getConverter();
         converter =  facesContext.getApplication().createConverter(valueType);
         if (converter != null ) {
              return converter.getAsObject(facesContext, component, (String) submittedValue);
         }else {
              return submittedValue; 
         }
    		
    }
    

    清單 9 的代碼添加了 Render javadoc 和 JSF 規(guī)范都讓您相信應(yīng)當(dāng)是自動執(zhí)行的功能,而實際上并不是。另一方面,請注意如果沒有 獨立的 Renderer,就不需要 以上(getConvertedValues)方法。UIComponentBase 類(Field 組件的超類)在直接渲染器的情況下提供了這個功能。請接受我的建議,只在特別想嘗試或者在編寫商業(yè)框架的時候,才考慮采用渲染器。在其他情況下,它們不值得額外的付出。

    如果想知道如何把組件和渲染器關(guān)聯(lián),那么只要看看圖 6 即可。


    圖 6. 把渲染器映射到組件
    把渲染器映射到組件

    定制標(biāo)記有兩個方法,分別返回組件類型和渲染器類型。這些方法用于查找配置在 faces-config.xml 中的正確的渲染器和組件。請注意(雖然圖中沒有)組件必須返回正確的 family 類型。



    回頁首


    結(jié)束語

    通過這些內(nèi)容,您已經(jīng)切實地了解了 JSF 組件開發(fā)的核心。當(dāng)然,在這個領(lǐng)域還有許多其他主題需要涉及 —— 包括發(fā)出組件事件、國際化組件、創(chuàng)建 UICommand 樣式的組件,以及更多。請參閱 參考資料 獲得 JSF 的閱讀列表!

    在編寫這篇文章的過程中,我遇到了 Renderer 的一個技術(shù)障礙,它使我發(fā)現(xiàn)了 getConvertedValues 方法的工作方式。盡管我以前遇到過 Converter 問題并處理過它,但是那時我是在一個緊張的(生產(chǎn))日程中做這件事的。在生產(chǎn)工作中進(jìn)行的研究,不必像在 how-to 文章中做得那么詳細(xì);所以這一次,我必須不僅學(xué)習(xí)如何修補問題,還要學(xué)習(xí)弄清如何 做對。通過這整個過程,我最終在非常深的層次上學(xué)會并體驗了 JSF 組件處理工作的方式。所以,有時繞點彎路會看到優(yōu)美的風(fēng)景。

    我希望在這個由四部分組成的系列中,您已經(jīng)學(xué)到了關(guān)于使用 JSF 的優(yōu)勢的充足知識,以及它如何工作的基礎(chǔ)知識,還希望您會喜歡進(jìn)一步深入這項技術(shù)。而且當(dāng)您有時可能迷失方向的時候,請不要陷入 FUD。相反,請記住我說過的:彎路會看到優(yōu)美的風(fēng)景,請繼續(xù)前行。

    posted @ 2006-01-10 11:26 lbom 閱讀(576) | 評論 (0)編輯 收藏

    主站蜘蛛池模板: 免费观看大片毛片| 成年女人午夜毛片免费看| 免费人成在线观看69式小视频| 猫咪免费人成网站在线观看| 国产精品成人免费一区二区| 日韩电影免费在线| 亚洲日韩在线第一页| 亚洲AV美女一区二区三区| 亚洲成aⅴ人片在线观| 亚洲人成网站免费播放| 一边摸一边桶一边脱免费视频| 免费在线中文日本| 又粗又大又黑又长的免费视频| 国产免费人人看大香伊| 人人狠狠综合久久亚洲婷婷| 亚洲国产精品人久久电影| 国产成人 亚洲欧洲| 永久免费av无码入口国语片| 日韩精品福利片午夜免费观着 | 久久国产精品2020免费m3u8| 精品久久久久久久久免费影院| 免费看国产精品麻豆| 亚洲国产高清人在线| 精品久久久久久亚洲综合网| 少妇性饥渴无码A区免费| 国产福利在线观看免费第一福利| 伊在人亚洲香蕉精品区麻豆| 91精品国产亚洲爽啪在线影院 | 亚洲成电影在线观看青青| 亚洲AV电影天堂男人的天堂| 国产羞羞的视频在线观看免费| 女人18毛片水真多免费看| 亚洲精品无码久久久久| 亚洲人成77777在线播放网站不卡 亚洲人成77777在线观看网 | 99精品视频在线观看免费| 青青视频观看免费99| 中文字幕在亚洲第一在线| 亚洲人成网站色在线观看| 中文字幕在线免费播放| 成年女人视频网站免费m| 亚洲精品字幕在线观看|