PS.只針對社招人員
若您或您的朋友有這方面的意向,請?zhí)峁┖啔v到:yaominxi@huawei.com
Hibernate入門 - 基礎(chǔ)配置 | ||
thinking_org 原創(chuàng) 更新:2006-07-07 20:39:43 版本: 1.0 |
Hibernate配置文件可以有兩種格式,一種是 hibernate.properties ,另一種是 hibernate.cfg.xml 后者稍微方便一些,當增加hbm映射文件的時候,可以直接在 hibernate.cfg.xml 里面增加,不必像 hibernate.properties 必須在初始化代碼中加入。 但不管怎么說,兩種的配置項都是一樣的,下面詳細介紹: 在Hibernate的src目錄下有一個 hibernate.properties 模板,我們不必自己從頭寫,修改模板就可以了:) hibernate.query.substitutions true 1, false 0, yes 'Y', no 'N' 這個配置意思是當你在Hibernate里面輸入true的時候,Hibernate會轉(zhuǎn)化為1插入數(shù)據(jù)庫,當你在Hibernate里面輸入false的時候,Hibernate會轉(zhuǎn)化為0插入數(shù)據(jù)庫,后面的Y,N同理。 對于某些數(shù)據(jù)庫,例如Oracle來說,沒有boolean數(shù)據(jù)類型,就是采用1代表true,0代表false,因此使用這個配置在Hibernate里面直接用true/false會非常直觀。 hibernate.dialect net.sf.hibernate.dialect.MySQLDialect hibernate.connection.driver_class com.mysql.jdbc.Driver hibernate.connection.url jdbc:mysql:///test hibernate.connection.username root hibernate.connection.password 這是一個連接MySQL數(shù)據(jù)庫的例子,很直觀,不必解釋,不同的數(shù)據(jù)庫的連接參數(shù)模板中全部給出了。 hibernate.connection.pool_size 1 hibernate.statement_cache.size 25 這是Hibernate自帶的連接池的配置參數(shù),在默認情況下將采用。意義很直觀,不多解釋。 只是提醒一點,Hibernate這個連接池是非常原始非常簡單的連接池,如果你在項目中用Hibernate的話,建議你首選App Server的連接池,次選Hibernate帶的DBCP連接池。自帶的連接池應該做為末選。 如果你采用DBCP連接池,除了要配置DBCP連接池以外,還需要取消掉下行的注釋: hibernate.connection.provider_class net.sf.hibernate.connection.DBCPConnectionProvider 其它的連接池同理。 如果采用App Server的連接池,假設(shè)App Server連接池的DataSource的JNDI名稱為"mypool"的話,配置應該如下: hibernate.dialect net.sf.hibernate.dialect.MySQLDialect hibernate.connection.datasource mypool hibernate.connection.provider_class net.sf.hibernate.connection.DatasourceConnectionProvider 其它參數(shù)就不必寫了,因為已經(jīng)在App Server配置連接池的時候指定好了。 如果你不是在App Server環(huán)境中使用Hibernate,例如遠程客戶端程序,但是你又想用App Server的數(shù)據(jù)庫連接池,那么你還需要配置JNDI的參數(shù),例如Hibernate連接遠程Weblogic上的數(shù)據(jù)庫連接池: hibernate.dialect net.sf.hibernate.dialect.MySQLDialect hibernate.connection.datasource mypool hibernate.connection.provider_class net.sf.hibernate.connection.DatasourceConnectionProvider hibernate.jndi.class weblogic.jndi.WLInitialContextFactory hibernate.jndi.url t3://servername:7001/ 最后,如果你需要在EJB或者JTA中使用Hibernate,需要取消下行的注釋: hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory 雜項配置: hibernate.show_sql false 是否將Hibernate發(fā)送給數(shù)據(jù)庫的sql顯示出來,這是一個非常非常有用處的功能。當你在調(diào)試Hibernate的時候,讓Hibernate打印sql語句,可以幫助你迅速解決問題。 #hibernate.connection.isolation 4 指定數(shù)據(jù)庫的隔離級別,往往不同的數(shù)據(jù)庫有自己定義的隔離級別,未必是Hibernate的設(shè)置所能更改的,所以也不必去管它了。 hibernate.jdbc.fetch_size 50 hibernate.jdbc.batch_size 25 這兩個選項非常非常非常重要!!!將嚴重影響Hibernate的CRUD性能! C = create, R = read, U = update, D = delete Fetch Size 是設(shè)定JDBC的Statement讀取數(shù)據(jù)的時候每次從數(shù)據(jù)庫中取出的記錄條數(shù)。 例如一次查詢1萬條記錄,對于Oracle的JDBC驅(qū)動來說,是不會1次性把1萬條取出來的,而只會取出Fetch Size條數(shù),當紀錄集遍歷完了這些記錄以后,再去數(shù)據(jù)庫取Fetch Size條數(shù)據(jù)。 因此大大節(jié)省了無謂的內(nèi)存消耗。當然Fetch Size設(shè)的越大,讀數(shù)據(jù)庫的次數(shù)越少,速度越快;Fetch Size越小,讀數(shù)據(jù)庫的次數(shù)越多,速度越慢。 這有點像平時我們寫程序?qū)懹脖P文件一樣,設(shè)立一個Buffer,每次寫入Buffer,等Buffer滿了以后,一次寫入硬盤,道理相同。 Oracle數(shù)據(jù)庫的JDBC驅(qū)動默認的Fetch Size=10,是一個非常保守的設(shè)定,根據(jù)我的測試,當Fetch Size=50的時候,性能會提升1倍之多,當Fetch Size=100,性能還能繼續(xù)提升20%,F(xiàn)etch Size繼續(xù)增大,性能提升的就不顯著了。 因此我建議使用Oracle的一定要將Fetch Size設(shè)到50。 不過并不是所有的數(shù)據(jù)庫都支持Fetch Size特性,例如MySQL就不支持。 MySQL就像我上面說的那種最壞的情況,他總是一下就把1萬條記錄完全取出來,內(nèi)存消耗會非常非常驚人!這個情況就沒有什么好辦法了 :( Batch Size是設(shè)定對數(shù)據(jù)庫進行批量刪除,批量更新和批量插入的時候的批次大小,有點相當于設(shè)置Buffer緩沖區(qū)大小的意思。 Batch Size越大,批量操作的向數(shù)據(jù)庫發(fā)送sql的次數(shù)越少,速度就越快。我做的一個測試結(jié)果是當Batch Size=0的時候,使用Hibernate對Oracle數(shù)據(jù)庫刪除1萬條記錄需要25秒,Batch Size = 50的時候,刪除僅僅需要5秒!??! 可見有多么大的性能提升!很多人做Hibernate和JDBC的插入性能測試會奇怪的發(fā)現(xiàn)Hibernate速度至少是JDBC的兩倍,就是因為Hibernate使用了Batch Insert,而他們寫的JDBC沒有使用Batch的緣故。 以我的經(jīng)驗來看,Oracle數(shù)據(jù)庫 Batch Size = 30 的時候比較合適,50也不錯,性能會繼續(xù)提升,50以上,性能提升的非常微弱,反而消耗內(nèi)存更加多,就沒有必要了。 #hibernate.jdbc.use_scrollable_resultset true 設(shè)定是否可以使用JDBC2.0規(guī)范的可滾動結(jié)果集,這對Hibernate的分頁顯示有一定的作用,默認就好了。 #hibernate.cglib.use_reflection_optimizer false 默認打開,啟用cglib反射優(yōu)化。cglib是用來在Hibernate中動態(tài)生成PO字節(jié)碼的,打開優(yōu)化可以加快字節(jié)碼構(gòu)造的速度。 不過,當你在調(diào)試程序過程中,特別是和proxy,lazy loading相關(guān)的應用中,代碼出錯,但是出錯提示信息有語焉不詳,那么你可以把cglib優(yōu)化關(guān)掉,這樣Hibernate會輸出比較詳細的調(diào)試信息,幫助你debug |
2004 年11月30日,世界各國科學家投入研究已有近四十年歷史的電子紙領(lǐng)域,又傳來了一個好消息。日本日立公司新近成功開發(fā)出了一種超薄的電子紙,這種紙張顯示尺寸為16.2厘米×18.1厘米,厚度僅有3毫米,樣品重量100克。與一般競爭對手開發(fā)的只能顯示兩色的電子紙不同,日立的該款產(chǎn)品,其液晶顯示器已經(jīng)達到能同時顯示64色的水平。最令人驚訝的是,它可以直接貼在墻上,并且可以根據(jù)遙控器的指揮而隨意改變顯示的圖像和信息。日立公司稱,這款產(chǎn)品可以用于在墻上顯示各種內(nèi)容,比如家庭照片、工作計劃表和菜譜等。 技術(shù)流派殊途同歸 所謂"電子紙"(Electronic Papers),其實就是一種外觀像紙或像投影片的新型的超薄平面監(jiān)示器,在各種場合(尤其是戶外)的文字辨認性上,優(yōu)于常規(guī)的LCD,且能夠與報紙相比擬。 "電子紙"概念興起于1980年代前后,彼時,一大批科學家開始投入此領(lǐng)域的研究,在當時研究者的理想中,該種紙張將可以逐漸代替?zhèn)鹘y(tǒng)紙張,既便于文字閱讀,又可以改寫內(nèi)容,反復使用。到了本世紀初,隨著技術(shù)研究呈現(xiàn)出若干可喜的回報,有人開始大膽預測,電子紙會在未來三五年內(nèi)達到大規(guī)模應用階段,而10 年左右的時間,傳統(tǒng)平面媒體業(yè)將會因電子紙技術(shù)的普及而發(fā)生顛覆性的變革。 目前的電子紙大致可分液晶型以及非液晶型兩大類。液晶型產(chǎn)品多半是由LCD廠商所開發(fā)出,以不使用偏光片或彩色濾光片的方式降低監(jiān)視器厚度,或是采用特殊的液晶材料及顯示方式達到目標。其中代表廠商是Fuji Xerox和大日本INK公司。而非液晶型領(lǐng)域較知名者為E-Ink公司的電子墨水(Electronic Ink)監(jiān)視器,以及SONY的電解析出型電子監(jiān)視器。 在電子紙的研制領(lǐng)域,成立于1997年的美國E-Ink公司的地位顯得首屈一指,這家隸屬于麻省理工學院的公司的電子超薄顯示器技術(shù)代表著目前業(yè)內(nèi)的最高水準。公司最新的成果是一種應用于電子報紙、可穿戴式電腦屏幕、便攜信息終端屏幕、電子詞典、電子圖書和智慧型身份辨識卡的電子裝置。公司發(fā)言人表示:這是至今為止世界上最完美的電子紙張產(chǎn)品,只有0.3毫米厚,可以任意彎曲而不發(fā)生字面的扭曲;支持以無線的方式下載文本內(nèi)容,如果必要的話,可以隨時進行閱讀內(nèi)容的網(wǎng)絡(luò)刷新和內(nèi)容改寫。 E-Ink公司所研發(fā)的電子紙張,表面看起來與普通紙張十分相似,可以像報紙一樣被折疊卷起,但實際上卻有天壤之別。它上面涂有一種由無數(shù)微小的透明顆粒組成的電子墨水,顆粒直徑只有人的頭發(fā)絲的一半大小。這種微小顆粒內(nèi)包含著黑色的染料和一些更為微小的白色粒子,染料使包裹著它的透明顆粒呈黑色,那些更為微小的白色粒子能夠感應電荷而朝不同的方向運動,當它們集中向某一個方向運動時,就能使原本看起來呈黑色的顆粒的某一面變成白色。根據(jù)這一原理,當這種電子墨水被涂到紙、布或其他平面物體上后,人們只要適當?shù)貙λ枰噪姄簦湍苁箶?shù)以億計的顆粒變幻顏色,從而根據(jù)人們的設(shè)定不斷地改變所顯現(xiàn)的圖案和文字,這便是電子墨水的神奇功效。當然,電子墨水的顏色并不局限于黑白兩色,只要調(diào)整顆粒內(nèi)的染料和微型粒子的顏色,便能夠使電子墨水展現(xiàn)出五彩繽紛的色彩和圖案來。由于此種監(jiān)視器具有記憶性,因此只有畫素顏色變化時(例如從黑轉(zhuǎn)到白)才耗電,關(guān)電源后顯示幕上畫面仍可保留,因此非常省電。2顆AA電池即可供數(shù)周以上長期使用。 而SONY的電子紙張發(fā)展,則以顯示靜態(tài)畫面為主,主要是利用銀(Ag)在電子化學反應過程中,在透明電極上析出,或于固態(tài)電解質(zhì)中溶解的方式達到呈現(xiàn)黑與百的效果。 這一技術(shù)最主要的貢獻將在于提高電子紙的反射率。 雖然當前有許多廠商進行電子紙相關(guān)技術(shù)研發(fā),發(fā)展方向亦相當分歧,但我們已經(jīng)可以從中歸結(jié)出現(xiàn)代電子紙的產(chǎn)品特性:一為較輕、較薄,比當前通用TFT LCD、STN LCD模塊為薄。二為大多數(shù)具有資料保存性,只有畫面異動時(例如由黑轉(zhuǎn)到白)才耗電,電源關(guān)閉后信息仍可留存在監(jiān)視器上,因此比TFT LCD、STN LCD更為省電。三為反射率高于反射式LCD,更接近報紙水平,有些廠商的產(chǎn)品甚至可達影印用紙水平(因此肉眼對其所顯示的文字內(nèi)容更易辨識)。四為對比度優(yōu)于一般報紙。五為初期以黑白方式顯示文字內(nèi)容為主,較缺乏全彩或動畫功能,應答速度普遍較TFT LCD、STN LCD慢。六為部分電子紙監(jiān)視器具可撓性或是可以卷曲。 蘊含巨大商機? 電子紙張屬于一種新興技術(shù),各廠商皆在摸索之中,主要市場尚待確認。按照目前業(yè)界比較一致的觀點來說,接下來兩三年仍然屬于電子紙的技術(shù)成熟階段:更輕更薄,由單色到多色,由靜態(tài)到動態(tài)。其正式的市場起飛可能要等到2007年或更晚。屆時,信用卡、可貼附在衣服或公文包上、具PDA功能的電子紙張,可能是未來應用的發(fā)展方向。但初期應用主要還是以電子海報、超薄電子書為主。依照各廠商產(chǎn)品發(fā)展計劃,未來不但可以看到隨身攜帶的電子報紙、電子書、電子速記本外,電子紙張亦可能成為捷運、公車或一般商家的平面廣告載具。當前在上述場所見到的平面印刷廣告,將來有可能出現(xiàn)全新風貌。比如當你擁有一張報社發(fā)放的電子報紙閱讀器的話,那么每天的報紙內(nèi)容將會以無線的方式發(fā)送到你的面前. 未來對電子紙需求有正面效益的一個觀察重點,是全球用紙量在近十年來激增,背后因素當然是信息量產(chǎn)出的爆炸,除報紙以外,各式各樣的雜志、宣傳海報以及計算機印出數(shù)量均有大幅增加情形。而需求數(shù)量龐大的傳統(tǒng)紙張對森林的威脅使環(huán)保人士感到憤怒。此一背景對于電子紙監(jiān)視器有利,因為其有助于節(jié)約用紙量。但相應的問題也隨之而來,與報紙、雜志、海報等紙張類媒體相比,目前的電子紙因成本過高而缺乏長遠的競爭力。同時,大部分的電子紙還是不夠薄,反射率不夠高。另一方面,對于所有的顯示用電子紙來說,目前最致命的缺陷是無法表達足夠連貫的視頻畫面--市面上普通的LCD的最短畫面響應時間低于12ms,但即使如此,LCD仍然被指責為無法與CRT進行這方面的性能抗衡。而普通電子紙的畫面響應時間將超過100 ms。如果電子紙無法對動畫畫面的顯示有所突破,那么它被人們接受的可能就會受到極大限制。 諸如以上因素,因此雖然根據(jù)預測,2005年電子紙張潛在市場規(guī)模具有100億美元商機,不過因為相關(guān)技術(shù)不成熟,有待改善空間仍大,加上廠商生產(chǎn)成本下降速度以及產(chǎn)能是否能夠配合等多項問題,預估2005年實際市場規(guī)模只有預測的1/10左右。 幸而研究人員從未放棄過技術(shù)改善的腳步。今年3月,日本千葉大學已經(jīng)開發(fā)出了厚度只有0.1毫米的電子紙產(chǎn)品,這是人類首次將電子紙真正在厚度上接近到了紙的范疇。而早在2002年上半,SONY已展示了一款比報紙反射率(約60%)更高的電子紙張,反射率達到73%,純白表現(xiàn)程度與影印紙相當,有助提高消費者觀看意愿。至于動態(tài)圖像的支持,九州大學與普利斯通的研究小組開發(fā)的使用粉狀墨的電子紙,相應速度目前為世界最高,已經(jīng)到達0.2ms。 由此我們完全可以樂觀地推斷,隨著科學技術(shù)的不斷完善,電子紙時代也將很快到來。事實上,盡管目前普及顯得遙遠,但真實的應用的確已經(jīng)出現(xiàn)--SONY的 LIBRIe、Adobe的在線書籍商店,都是電子紙技術(shù)初期應用的最好體現(xiàn)。今年4月末,SONY推出了一種被稱為LIBRIe的電子書產(chǎn)品。 LIBRIe的大小和一本普通的書差不多,但是作為一種電子產(chǎn)品,LIBRIe配備了USB和耳機接口,同時內(nèi)置文字放大和字典查詢的功能。用戶可以憑借 LIBRIe提供的MS卡存儲數(shù)字化的文字,也可以通過SONY開設(shè)的電子書租賃服務(wù)"Timebook Town"以月租的方式從網(wǎng)上下載閱讀內(nèi)容。這樣的服務(wù)模式標志著多年來的電子紙及其下游產(chǎn)品已經(jīng)進入了真正的實用階段,人類的數(shù)字化生活也許要因此而翻開嶄新的一頁。 |
[前 言]:眾所皆知,項目管理要做的三件大事就是:計劃、組織和控制,然而如何計劃、組織和控制好一個項目,不僅要求項目經(jīng)理要有系統(tǒng)
[關(guān)健詞]:基準計劃、比較基準工期、比較基準成本、工期差異、成本差異、BCWS、ACWP、BCWP、SV、CV等。
一、 項目管理與Project2000的關(guān)系
在項目管理知識體系中,包括九大知識領(lǐng)域(范圍管理、時間管理、費用管理、質(zhì)量管理、人力資源管理、溝通管理、風險管理、采購管理、綜合管理)。但從項目管理輔助工具軟件Project2000來說,它包含了這九大知識領(lǐng)域中的5大核心領(lǐng)域,另外4個領(lǐng)域需要通過其它輔助工具或人工操作來完成。包括的5大領(lǐng)域如下所述:
1、 范圍管理
項目管理的第一個知識領(lǐng)域就是"范圍管理",在項目范圍中,包括兩層內(nèi)容:一是項
目范圍;二是產(chǎn)品范圍。項目范圍針對的是我們項目的目標,包括軟件開發(fā)、集成、培訓和項目實施等。產(chǎn)品范圍側(cè)重在軟件的需求范圍,可以理解為對項目范圍的一個重要補充。兩者有一定關(guān)聯(lián),但也各有側(cè)重,只有這兩者相加,才構(gòu)成了我們完整的項目范圍。然而在Project2000工具中,指的項目范圍是指第一種,結(jié)果輸出就是WBS分解。
2、 時間管理
時間管理也稱進度管理,在Project2000中,它提供了工期估計、工作搭接關(guān)系、進度安排、進度控制等基本功能。還能夠自動計算出關(guān)健路徑,可以很方便的設(shè)置我們的里程碑控制點,并能夠?qū)崿F(xiàn)項目的動態(tài)跟蹤。還提供了多種時間的管理方法,甘特圖、網(wǎng)絡(luò)圖、日歷圖等。應該說時間管理,是Project 2000中最強大的功能。
3、 費用管理
在費用管理中,Project2000中采用的是"自底向上費用估算"的技術(shù),由于它是依賴每個WBS任務(wù)的估算,所以使得費用估算更為準確。并且它還能與EXCEL等進行結(jié)合,生成費用曲線圖和掙得值趨勢圖。
4、 人力資源管理
在人力資源管理中,Project2000提供了人力資源的規(guī)劃、人力資源責任矩陣、資源需求直方圖、資源均衡等,它能幫我們做好資源的分配、進行資源的工作量、成本和工時的統(tǒng)計。
5、 整合管理
項目管理的整合管理就是對于整個項目的范圍、時間、費用、資源等進行綜合管理和協(xié)調(diào),在Project2000中,它能根據(jù)范圍、時間、資源的變化自動進行相應計算和調(diào)整。
二、 Project2000使用前的環(huán)境設(shè)置
在進行計劃編制前,需先設(shè)置好Project2000的使用環(huán)境,這樣可以更方便我們計劃編
制時的操作。環(huán)境設(shè)置一要根據(jù)自己的習慣,二是要根據(jù)項目的實際情況。下面介紹幾種常用的環(huán)境設(shè)置項。
* 首先,要設(shè)置項目摘要信息,在摘要信息中需輸入該項目的標題、項目經(jīng)理和單位等信息。主要是便于打印時顯示的信息。
操作方法:選中菜單 文件-》屬性-》摘要信息-》。
* 設(shè)置項目的日歷,默認從星期日開始,中國人的習慣一般是從周一開始。
操作方法:選中菜單 工具-》選項-》日歷-》每周開始于-》。
* 設(shè)置任務(wù)類型,默認為"固定工時",固定工時的含義是當一項任務(wù)分配給一個人做是10天,當增加一人時,則工期自動變?yōu)?天。我們的操作習慣應該是人員增加時,原工期一般要求仍不變。所以需選擇為"固定工期"。
操作方法:選中菜單 工具-》選項-》日程 -》默認任務(wù)類型-》。
* 設(shè)置WBS編號,默認無WBS編號,為了計劃閱讀清晰,建議設(shè)置大綱編號作為WBS編號。
操作方法:選中菜單 工具-》選項-》視圖-》選中顯示大綱編號。
* 設(shè)置工作時間,默認是按標準日,也即周六、周日休息。行政日指不但考慮周六、周日休息,而且考慮到中國的傳統(tǒng)節(jié)假日(如國慶、五一等)。我們一般要根據(jù)項目的具體情況,如該項目比較工期比較緊,項目組要求每周六加班,周日休息,那么就需將周六設(shè)置為"非默認工作時間"。
操作方法:選中菜單 工具-》更改工作時間-》選中對象-》非默認工作時間。
* 設(shè)置條形式樣式,可根據(jù)自己的習慣,設(shè)定關(guān)健任務(wù)、非關(guān)健任務(wù)、進度條、里程碑為不同的樣式和顏色。
操作方法:選中菜單 格式-》條形圖樣式-》。
說明:建議環(huán)境設(shè)置可以設(shè)置為一個模板,這樣就無需每個項目都進行設(shè)置一下,提高計劃編制效率。
三、 如何使用Project 2000來制定計劃
在項目管理知識體系中,項目的計劃包括4個核心計劃和4個輔助計劃,4個核心計劃為:范圍計劃、人力資源計劃、進度計劃和費用計劃;4個輔助計劃為:質(zhì)量計劃、溝通計劃、風險計劃和采購計劃。利用Project2000工具,能很方便的完成4個核心計劃的制定。
為了使我們能夠更好的掌握如何運用Project2000工具來做計劃的,在這里將上述講述的4個核心計劃,分解成8個步驟來講述,并在每個步驟當中,給予案例,這樣更便于我們的理解和操作。
案例背景描述:
某企業(yè)決定開發(fā)一套項目管理軟件。
該軟件的主要功能包括:項目及工作信息的錄入、項目網(wǎng)絡(luò)計劃圖的繪制、項目時間計劃的安排、甘特圖計劃的制定、項目執(zhí)行信息的錄入與分析及各種計劃報表的輸出等。該企業(yè)準備投入25萬元進行該系統(tǒng)的開發(fā),時間要求是20~25周。該軟件項目的計劃開始時間是2002.1.1日,企業(yè)要求軟件正式驗收前需要試運行4周以上的時間,并根據(jù)試運行情況進行適當修改。
1、 目標確定
項目目標就是實施項目所要達到的期望結(jié)果,是衡量項目成功與否的標
|
項目目標的描述必須明確、具體、盡量定量描述,需滿足Smart原則:
* Specific 明確
* Measurable 可衡量性
* Achievable 雖然極具挑戰(zhàn)性, 但是有計劃完成
* Result Driven 面向成果
* Time 具時間性
案例示范:目標描述:
a、 總費用:在25萬的費用預算內(nèi);
b、 時間:從2002年1月1日開始,至2002年6月27日完成,總工期24周;
c、 交付物:開發(fā)一套功能齊全的項目管理軟件、其中主要功能為:項目及工作信息的錄入;項目網(wǎng)絡(luò)計劃圖的繪制;項目時間計劃的安排;甘特圖計劃的制定;項目執(zhí)行信息的錄入與分析及各種計劃報表的輸出等。
說明:在Project2000中,沒有特定的項目目標書面位置,可以專門采用Word文檔進行描述,也可直接在Project2000中的備注欄中注明。
2、 范圍定義
范圍定義就是將項目可交付成果分成幾個小的、更易管理的單元。范圍定義的結(jié)果是
形成工作結(jié)構(gòu)分解圖(WBS)。WBS分解就是先把復雜的項目逐步分解成一層一層的要素(工作),直到具體明確為止。
WBS分解的步驟:
* 總項目
* 子項目或主體工作任務(wù)
* 主要工作任務(wù)
* 次要工作任務(wù)
* 具體工作包
WBS的表現(xiàn)形式:
* 樹形列表
* 鋸齒列表
WBS分解結(jié)果要求:
* 可管理、可定量測量、可獨立分配任務(wù)的;
* 可以進行費用和時間的估計;
* 不體現(xiàn)工期和活動的先后順序;
* 包括管理活動;
* 分解完后需進行核對。
說明:WBS分解是項目計劃的基礎(chǔ),也是最關(guān)健的。需要做的前期調(diào)研和需求分析工作。如果WBS偏差率較高,則整個計劃的基本上很難執(zhí)行。所以這塊基石一定要打好。
另外,在WBS分解過程當中,項目管理工作內(nèi)容不能漏掉。
案例示范:
在Project 2000中,WBS分解采用的是鋸齒形式,WBS編碼能自動生成,最多可分解
為500多層,100萬個WBS任務(wù)。如:
3、 工作排序
工作排序的確定涉及到各工作之間相互關(guān)系的識別和說明。任何工作的執(zhí)行必須依賴于一定工作的完成,也就是說它的執(zhí)行必須在某些工作完成之后才行,這就是工作的先后依賴關(guān)系。工作的先后依賴關(guān)系有兩種:一種是工作之間本身存在的、無法改變的邏輯關(guān)系。如設(shè)計與開發(fā)。還有一種是組織關(guān)系,一般由管理人員根據(jù)實際情況來確定。我們要在邏輯關(guān)系的基礎(chǔ)上再加以分析,考慮組織關(guān)系。
工作排序需要確定的內(nèi)容:
* 強制的邏輯關(guān)系的確定;
* 組織關(guān)系的確定;
* 外部制約關(guān)系的確定;
* 實際過程中的限制和假設(shè)。
工作排序常用的方法:
* 單代號法(AON法)
* 雙代號法(AOA法)
案例示范:
4、 工期估計
工時的估計是項目計劃制定的一項重要的基礎(chǔ)工作,它直接關(guān)系到項目的總工期。如果估計的太短,那么在工作中會造成被動局面;相反,如果估計的太長,那么整個工期延長。所以說在工時估計的時候,要在考慮到各種資源、人力、物力、財力的情況下,把工作置于獨立的正常狀態(tài)下進行估計,要做統(tǒng)盤考慮,不可顧此失彼。
工期估計的方法:
* 專家判斷。依賴于專家組成員的歷史經(jīng)驗。
* 類比估計法。依賴于同類型項目的歷史實際數(shù)據(jù)。
說明:在人力資源尚未分配時,進行工時估計,一般以按平均資源能力進行估算。
5、 進度安排
根據(jù)項目內(nèi)容的分解,找出各組成要素工作的先后順序,估計出各工作的延續(xù)時間之后,就要安排好項目的時間進度。因為在進度安排之前,我們的計劃都是假設(shè)在正常情況下的計劃,實際中我們的計劃會受到各種因素的影響和限制,所以需要根據(jù)這些限制重新對進度進行調(diào)整。進度安排主要是要根據(jù)實際情況來考慮我們的計劃。另外,在進度安排中,要將里程碑計劃和關(guān)健路徑計劃加入。
進度安排的方法:
* 關(guān)健路徑法。關(guān)健路徑是指機動時間為0的工作,如果延期,會導致總工期延期,需特別關(guān)注。
* 里程碑計劃法。為更好的對項目進度的進展測量進行測量,需設(shè)置合理的里程碑點,用于檢查階段性成果的輸出,以及實際進度與計劃的偏差。
* 計劃評審技術(shù)(PERT)。對于工作先后邏輯關(guān)系及活動不確的時間,可采用最最短時間a、最可能時間m、最長時間b,然后按照β分布計算該工作的期望時間t。
* 并行壓縮法。對于限定工期的項目,往往需采用并行處理技術(shù),保證項目在限定的工期內(nèi)完成。并行處理雖然壓縮了時間,但同時會引發(fā)人力資源和質(zhì)量的風險,需綜合考慮。
案例示范:
在該項目的Project甘特圖進度安排中
6、 人力資源安排
資源計劃涉及到?jīng)Q定什么樣的資源,以及多少資源將用于項目的每一工作的執(zhí)行過程之中。這里的資源包括人、設(shè)備和材料等。象我們的設(shè)備分解單也是屬于資源
|
人力資源計劃:
* 分析出人力資源需求
* 人力資源獲取
* 人力資源培訓
在Project2000中,先需建立資源庫,具體操作是:工具-》資源-》分配資源。將項目所需人力資源錄入,人力資源包括本部門、協(xié)作部門、用戶和第三方廠商等。資源庫建立完后,就可采用拖放的方式來對每條任務(wù)分配資源。
資源分配完畢后,項目計劃編制者需調(diào)整和優(yōu)化資源,如資源過度分配或資源剩余等。
說明:1、這里所指的資源,均指人力資源,其它如設(shè)備資源沒有包括在此中。
2、在第四步工期估計時,尚未分配資源,所以按平均資源能力估計,但資源分配后,對工期估計要做相應一些調(diào)整。
案例示范:
7、 費用估計
費用估計指的是預估完成項目各工作所需資源的費用的近似值。目前我們考慮的資源
主要是人力資源和差旅費用。而設(shè)備和材料資源暫未考慮。費用估計應該與工作質(zhì)量的結(jié)果相聯(lián)系。費用估計過程中亦應該考慮各種形式的費用交換。
費用估計的常用方法:
* 類比估計法。依賴于歷史數(shù)據(jù)的積累。
* 從上而下估計法。
* 從下到上估計法。
在Project2000中,采用的方法是"從下到上估計法",這種技術(shù)通常首先估計各個獨立工作的費用,然后再匯總從下往上估計出整個項目的總費用。估計相對會比較準確。
在Project2000預算中,我們首先要輸入人力資源的單位價格,在Project工具中,人力資源基本單位為:工時。在數(shù)據(jù)錄入時要進行換算,需將每天標價除以8,轉(zhuǎn)換為工時單價。人力單價估計完后,還要對差旅、招待、活動、通信費、辦公等其它費用進行單價估計,如差旅費平均每趟多少,招待費平均每次多少,活動費平均每次多少等,這些單價要依據(jù)項目的規(guī)模、復雜度和地域等因素來確定,有的還要參照公司財務(wù)制度的標準(如通信費用報銷規(guī)定、差旅補貼規(guī)定等)。在Proejct2000的差旅、招待費等的單價錄入中,類型選擇為"材料"。
案例示范:
8、 費用預算
費用的預算包括給每一項獨立工作分配全部費用,以獲取度量項目執(zhí)行的費用基線。
費用預算可以分為三部分,即人工費用預算、輔助服務(wù)費用預算和采購物品費用預算。但我們目前費用預算主要考慮的是人工費用預算和差旅等其它費用。
在Project2000中,當費用估計完成后,一般來說人力成本便自動計算出來了。但對于差旅等其它費用還需按里程碑或或主體任務(wù)進行分配,對于較小的項目也可就在總項目中分配(本例就是在總項目中分配)。分配方法與第六步的人力資源分配方法一樣。
案例示范:
四、 計劃的應用
計劃的編制,不是單獨由項目經(jīng)理來做,應該是要求項目成員或項目主要成員一起參與。
項目計劃制定完后,還要組織計劃的評審。計劃評審通過后,就形成了項目的基準計劃,這個基準計劃是日后項目控制的杠桿,也是項目績效考核的重要基礎(chǔ)數(shù)據(jù)。
應用一:里程碑計劃
里程碑,一般都是項目的關(guān)健控制點,里程碑的設(shè)置應滿足階段成果和易測量兩種屬性。對項目高層經(jīng)理或項目主管來說,他們進度控制的焦點往往就是里程碑計劃。
操作方法是,選中菜單的項目-》篩選-》里程碑。并插入列備注(輸出成果)。
案例示范:(藍色字體就是我們的里程碑點,共4個)
應用二:關(guān)健任務(wù)
關(guān)健任務(wù),也即機動時間為0的工作,只在關(guān)健任務(wù)上的工期延期一天,則總工期必將延期一天。所以關(guān)健任務(wù)對總工期的控制有關(guān)至關(guān)重要的作用。對項目經(jīng)理來說,進度控制的側(cè)重點應在關(guān)健路徑的任務(wù)上。
關(guān)健路徑顯示有兩種方法:一是在菜單的格式-》甘特圖向?qū)В逢P(guān)健路徑;另一種是在菜單的項目-》篩選-》關(guān)健路徑。第一種情況在前面計劃編制的第6步進度安排時有體現(xiàn)。下面以第二種為例。
案例示范:
應用三:任務(wù)責任分配
基準計劃形成后,項目經(jīng)理需將各任務(wù)分配給個每個項目成員。并要求每個項目成員簽署任務(wù)責任書或任務(wù)承諾書,一般在正式開工前的開工會議上進行。任務(wù)分派完后,這樣我們的計劃就開始正式進入執(zhí)行階段了。
在Project2000中的任務(wù)分配,操作過程是:資源使用狀況-》在列中加入開始時間、完成時間、完成百分比、備注(即輸出成果)等列,使得任務(wù)分配的信息更全面。
案
應用四:資源負荷分析 計劃完成后,還要檢查資源分配是否超負荷,如資源超負荷過多,則該計劃很難執(zhí)行。檢查資源超負荷的方法如下: 接著,超負荷資源找出來后,我們接著要將該資源超負荷分配的任務(wù)要找出來。操作方法:選中菜單的項目-》篩選-》使用資源,然后根據(jù)彈出的提示框,選擇資源"王五"。則可看出超負荷分配的任務(wù)。 對于人力資源分配時,必須掌握一個均衡分配的原則,不能某一段時間人力資源需求量驟增,某一段時間驟減。這樣對人力資源的調(diào)配和獲取帶來困難。項目經(jīng)理可以通過"人力資源工時曲線圖"幫助進行分析。 操作方法:選擇 視圖-》工具欄-》分析,則這是在Project2000工具中會出現(xiàn):"在EXCEL中分析時間刻度數(shù)據(jù)",點擊該快捷圖標-》選擇完整項目-》選擇導出的域為"工時"-》選擇時間單位為"周"-》導出數(shù)據(jù) 應用五:費用預算曲線圖 在費用預算,如按時間坐標來分析,有兩種表現(xiàn)方式,一是費用預算曲線圖,二是費用預算累計曲線圖。 對于費用預算累計曲線圖,同上述操作方法基本一致,就是在選擇導出的域為"累計成本"便可。 另外,在費用預算中,如從資源坐標來分析,費用來源分為兩大類,一是人力成本費用,二是差旅、交通、招待、會議、等費用。費用從資源角度顯示如下。(當然也可將人力資源成本倒出到EXCEL中進行小計。) 五、 如何使用Project 2000來控制計劃 1、 進度跟蹤 案例示范: 假如,實際工期花費了11工作日,則在實際工期中輸入11便可,完成百分比,則會自動計算,在下面進度控制中,便會體現(xiàn)實際工期比計劃工期多用了1天。 2、 未完成任務(wù)的查看 3、 進度和費用偏差 4、 項目跟蹤甘特圖 操作方法:選中"跟蹤甘特圖"便可。在下圖中,下面灰色部分表示原比較基準進度條,上面的藍色部分表示實際進度條。從該圖中可看出實際進度有后延。 案例示范: 5、 項目總體進展情況統(tǒng)計 |
操作方法:選中菜單 項目-》項目信息-》在對話框中點擊"統(tǒng)計信息"。例如從下圖中可以看出:該項目在當前狀態(tài)下,已完成總?cè)蝿?wù)的28%,費用花了¥112,034.81元,總工期延期了1天,費用超支了¥3904.00元。
案例示范:
6、 掙得值法分析
掙得值法實際上是一種分析目標實施與目標期望之間差異的方法,又稱偏差分析法。它控制的原理就是利用已完成工作的實際成本(ACWP)、計劃完成工作的預算成本(BCWS)、實際完成工作量的預算成本(BCWP)三個基礎(chǔ)數(shù)據(jù),來計算得出進度偏差(SV)和費用偏差(CV)。
假如,以第一個里程碑點200年1月21日作為檢查點,來計算該項目的進度和費用偏差值。
操作方法:選擇,項目-》項目信息-》在彈出的"項目信息"框中,將狀態(tài)日期選擇為:"2002年1月21日"。然后分別插入列"BCWS"、"ACWP"、"BCWP"、"SV"、"CV"等,從計算結(jié)果可得SV<0、CV<0,說明該項目在第一個里程碑點進度延期了,費用也超去了,必須采取控制措施或計劃變更。
案例示范:
說明:由于檢查點為2002年1月21日,而"需求分析"任務(wù)工期為5天,實際完成日期為2002年1月22日,所以的計劃工作量的實際成本為8000*4/5=6400;已完成工作量的預算成本為4000*4/5=3200。圖示如下:
六、 結(jié)束語
以上是本人根據(jù)對Project2000的一些粗略理解,并結(jié)合近5年來的項目管理實踐經(jīng)驗總結(jié)而成。謹以把此文獻給各項目經(jīng)理,以供參考。希望我們的項目經(jīng)理能掌握一些工具,來幫助我們更好的管理項目。另外,在后一段時間,我們將繼續(xù)推出基于WEB的團隊項目管理工具-"Project Central工具"的應用與實例
一.JAVA電子書
優(yōu)點:書籍量大,經(jīng)常更新,教育網(wǎng)下載速度超快
不足:每天只能下載4本
孫衛(wèi)琴感動了我!(我--張孝祥) | ||
thinking_org 轉(zhuǎn)貼 更新:2006-08-02 09:09:55 版本: 1.0 |
今天聽了孫衛(wèi)琴的講座,頗受感動。本來覺得孫衛(wèi)琴的成功是走了一些竅門,無非是綜合了國外多本書籍的成果,再用自己的語言描述出來而已,少有她自己摸索和實踐的東西。即便這般認為,但孫衛(wèi)琴也是令我非常尊敬和佩服的,因為有過類似寫作的經(jīng)歷,我深知只要不是攢書,只要是抱著對讀者負責、對自己的作品負責的心態(tài)來寫作,那么整個創(chuàng)作過程就會非常艱辛,需要毅力來堅持,何況孫衛(wèi)琴在短短幾年內(nèi)寫出了這么多受人喜歡的書籍,那寫書的效率和付出的辛勞是不言而喻的。對于孫衛(wèi)琴,我只能是佩服和尊敬,我沒有資格去挑剔人家書中的缺陷,因為在寫書效率上我不如人家,至少我不能在這么短的寫作周期內(nèi)寫出好過她的書。 前些天因為培訓合作事宜,與孫衛(wèi)琴通過電話,知道了她和我有一樣的憂患,那就是老了誰來養(yǎng),我們都是自由職業(yè),沒有國家皇糧,沒有養(yǎng)老保險,所以,現(xiàn)在只能比別人付出更多的努力,以便讓自己的未來有一定的安全感。她說有人指責她抄襲老外的作品,我跟她談到,不要理會那些人的言論,她把國外作者的經(jīng)驗按中國人的閱讀方式引入了中國,這作出的貢獻是值得肯定的,是有歷史意義的,不象國內(nèi)某些作者直接抄取其他國內(nèi)作者的書,重復別人的工作,那就談不上對社會有什么歷史貢獻和價值了,無非是給自己謀取了一些名利而已。我作為一個被人贊揚過的、也被人譏笑和嘲罵過的作者,我的感受是很深的,一些人看到別人的成果后,然后對別人的成果進行挑刺,這是一件很簡單的事情,大家都能做,但這不能說一個能挑刺的人水平就怎樣,這往往是那些自己找不到成就,而只能靠給被人挑刺來滿足自己虛榮心的人所為。如果那些人果真有本事的話,就先別急著給別人挑刺,而是自己也做點類似的東西出來,做完后就知道自己還不如人家的好呢!我有一個很大的創(chuàng)作計劃,本來如果我的臉皮厚,我也可以在孫衛(wèi)琴那幾本書的基礎(chǔ)上修修改改,稍作完善,然后再從別的書上整點資源進來,到時候還可以對大家說,我的書比孫衛(wèi)琴的好,因為站在孫衛(wèi)琴的基礎(chǔ)上創(chuàng)作,我想應該比她的好點吧!但我沒必要那么做,我不是為了經(jīng)濟效益和名聲而不擇手段的人!我把寫作當作了一種藝術(shù),我希望完全用自己的方式來寫作,寫出我想寫的那些東西,我希望做出對社會有歷史價值的貢獻,所以,我是不可能抄襲別人的,對我來說,即使在出版社多出了幾本書,只要不是我自己用心寫出來的,而是與別人寫得差不多,那我從中也根本就找不到任何成就感,基于這種寫作心態(tài),我自身寫作周期很漫長,所以,我希望孫衛(wèi)琴能夠結(jié)合培訓的特點,重新調(diào)整一下她的那些書籍內(nèi)容,以便我們作為全國范圍內(nèi)的培訓教材使用。 上次的電話僅僅是簡單問了一下她目前的情況和想法,并不知道她創(chuàng)作的經(jīng)歷??墒?,我今天聽完別人對孫衛(wèi)琴的介紹,我是真的感動了,孫衛(wèi)琴在懷孕4個月后開始寫struts,在小孩出生3月后就把孩子托付給了江蘇常州的父母,又只身一人回到上海,開始把自己封閉在一小屋里寫hibernate,最長時間是12天沒見到過一個人,可敬!我等有人洗衣做飯的大老爺們,在她面前還有什么苦可叫! 注:為了創(chuàng)作,我估計也能夠忍受12天不與外界接觸的寂寞, 但現(xiàn)在身體素質(zhì)跟不上了,每天只要在電腦前連續(xù)工作8個小時以上,就會頭暈、惡心,渾身乏力,胃病復發(fā),所以,我原來靠個人英雄主義的寫作思想開始逐步轉(zhuǎn)向了團對協(xié)作,我佩服孫衛(wèi)琴哪來這么好的體力! 看了下面一些人的評論,想想這個世間還真好笑,看來還是有許多對我沒有好感的人在經(jīng)常關(guān)注我的blog啊,不知這些人是一種什么樣的看客心態(tài),在滿篇文章中揪人家的小辮子,然后就開始發(fā)揮自己無限的遐想了,為了讓這些人明白自己是多么"聰明",特作如下解釋: 1.孫衛(wèi)琴老師的書中確實很多代碼都是直接來自一些現(xiàn)有外版書籍,已有數(shù)人親自給我這么說過,但我并沒有私下向別人說過,因為我理解孫衛(wèi)琴老師,能做成這樣已經(jīng)非常不容易,不能要求別人十全十美。我親自與孫衛(wèi)琴交流時就是這么說的。 2.這些發(fā)表評論的人誰寫過書,誰想堅持不懈地好好寫本書過,沒有!那就不要站著說話不腰疼,我一直在努力寫書,我寫的內(nèi)容到底有多大價值,以后會有人給出恰當評價的。正因為我太想寫成一系列的好書了,所以,花費的功夫非常之多,加上這么多年的身體透支,感覺寫書就是心有余而力不足,這個力不足不是學不會知識,而是沒有體力去鉆研和細化每個知識細節(jié),所以,發(fā)出了"我佩服孫衛(wèi)琴哪來這么好的體力!"的慨嘆。我就是認為struts,hibernate,spring從學習的角度來說,一點也不難,但要扣細,確實要花費大量的時間和體力,如果你的java基礎(chǔ)和java web不是很好,覺得struts,hibernate,spring很難,那是情理之中的事,但不要以己度人,對你難的事,對別人來說未必就難! 3.我從來不怕解剖我自己,我就是一個非常非常普通的人,只是我有理想,有目標,我為了理想一直在奮斗。我根本不在意別人的評論,只是嘆息那些自以為是的人,怎么對在別人的字里行間挑話題這么有興趣,真不知道這些人平常的工作是什么。(完) 我(張孝祥)的技術(shù)學習觀念: 我一直認為基礎(chǔ)知識最重要,無論是對國家,還是對個人的后期發(fā)展,都是最重要的.有些人自以為是,以為會玩玩struts,hibernate之類的工具,就覺得自己不得了,其實,那算什么,一個用高級工具的用戶而已,如果中國全是這樣的高級用戶,中國軟件永遠不會有出頭之日,永遠只能用別人做好的工具!非常遺憾的是,我搞這些基礎(chǔ)知識的"研究",常常引來一些譏諷聲和嘲笑聲,不過,這些譏諷聲和嘲笑聲并不能左右我的思想!我沒必要為去迎合那些無知和沒有遠見的人(不是攻擊別人,而我就是這么想的)而改變自己的立場和理念! 我現(xiàn)在不算精通struts,hibernate,spring,但是,還算學得明白,照著一些現(xiàn)有的書籍和別人的思路講講課,應該不會有什么問題.我并不覺得這樣就有什么資本,我從未欽佩過那些使用struts,hibernate,spring的大蝦們,而是只佩服當初開發(fā)struts,hibernate,spring這些框架的大俠們.佩服那些對這些框架的內(nèi)部原理有深入研究的技術(shù)牛人們!我在學習struts和spring時,發(fā)現(xiàn)這些框架的設(shè)計師們對html,css,javascript,http協(xié)議,servlet,jsp,java等基礎(chǔ)性知識掌握得都非常全面,并且細節(jié)都非常清楚,敢問國內(nèi)那些看不上這些基礎(chǔ)知識的人們,為何struts和spring設(shè)計師們都覺得這些知識重要,而你卻認為不重要,說句不客氣的話,因為你還連一點概念都沒有,你永遠到不了struts和spring設(shè)計師們的水平,我雖達不到他們的水平,至少我可以追隨他們的思想,讀懂他們的源碼,知道他們?yōu)楹我@么做! 每個人都可以有自己的想法,但沒必要把自己的想法強加給其他人! |
![]() 圖 1 MVC和J2EE技術(shù) |
![]() 圖 2 Struts MVC實現(xiàn) |
![]() 圖 3 Struts接受并返回響應的中間過程 Struts1.1新增功能 1、多模塊的支持 我們知道,在Struts 1.0中,只能在web.xml中為ActionServlet指定一個Struts配置文件(struts-config.xml),這對一個只需一兩個人開發(fā)的小系統(tǒng)當然沒有任何問題,但如果一個多人開發(fā)的大中型應用程序,問題就產(chǎn)生了。因為許多開發(fā)人員可能同時都需要修改Struts配置文件,這樣肯定會造成一定程度的資源爭奪,可能會出現(xiàn)彼此覆蓋的情況,這樣勢必會影響開發(fā)效率并引起開發(fā)人員的抱怨。 在Struts 1.1中,為了解決這個并行開發(fā)的問題,提出了兩種解決方案: ·多個配置文件 支持多個配置文件,是指你能夠為ActionServlet同時指定多個xml配置文件,文件之間以逗號分隔,請看下面web.xml中關(guān)于多個struts配置文件的聲明示例: 代碼清單 1 多個struts配置文件
通過這種方法,你可以為每一個模塊定義一個配置文件,由于項目一般按模塊劃分工作,這樣就大大地減小了沖突的概率。 ·獨立的模塊 但是,多個配置文件存在一個潛在的問題:不同的配置文件之間會產(chǎn)生沖突,因為在ActionServlet初始化的時候多個配置文件還是要合并到一起。比如,在struts-config.xml中配置了一個名為errorDbAccess的<exception>,而在book-struts-config.xml中也配置了一個同樣的<exception>,這樣就產(chǎn)生沖突了。 為了徹底解決這種沖突,Struts 1.1中引進了模塊(Module)的概念。一個模塊就是一個獨立的子系統(tǒng),對應一個獨立的配置文件,ActionServlet將不同模塊的配置文件保存在各自獨立的ModuleConfig對象中的。 下面是兩個獨立模塊的配置方式: 代碼清單 2 多模塊配置方式
通過這種方式,我們配置了兩個模塊,一個模塊名為config,而另一個名為config/book。 ·動態(tài)ActionForm支持 ActionForm表示HTTP頁面表單的數(shù)據(jù),可以將其看成視圖頁面數(shù)據(jù)的服務(wù)器映射,它負責保存視圖中的數(shù)據(jù)供控制器或者其他視圖使用。此外,它還負責數(shù)據(jù)有效性的驗證,所以Struts 1.1文檔把它比作HTTP和Action之間的防火墻,這足以體現(xiàn)ActionForm在視圖和控制器之間的過濾器作用。 由于ActionForm對應于HTTP頁面表單,所以隨著頁面的增多,你的ActionForm將會急聚增加。動態(tài)ActionForm(DynaActionForm)即為減少ActionForm的數(shù)目被設(shè)計出來,利用它你不必創(chuàng)建一個個具體的ActionForm類,只需要在配置文件中配置出所需的虛擬ActionForm,而由Struts框架通過配置文件動態(tài)創(chuàng)建這個ActionForm。例如,代碼清單 3通過指定<form-bean>的type為"org.apache.struts.action.DynaActionForm"來創(chuàng)建一個動態(tài)的ActionForm--loginForm。 代碼清單 3 配置一個動態(tài)ActionForm
DynaActionForm將屬性保存在一個Map對象中,同時提供相應的get(name)和set(name,value)方法,其中參數(shù)name是要訪問的屬性名,而value是一個Object。例如要訪問DynaActionForm中bookName的值,可以采用String bookName = (String)get("bookName")方法,由于bookName存儲在Map中,所以要進行強制轉(zhuǎn)換。 由于DynaActionForm通過配置文件產(chǎn)生,并沒有一個實體對象類,如果要對動態(tài)ActionForm對象進行校驗需要使用DynaValidatorForm,它是DynaActionForm的子類,它能夠提供動態(tài)ActionForm和動態(tài)表單輸入驗證的功能。檢驗規(guī)則在validation.xml配置文件中定義,而這些規(guī)則的所對應的實現(xiàn)函數(shù)在validator-rules.xml文件中定義。 ·通過配置方式實現(xiàn)異常處理 Struts1.1允許以配置方式進行異常處理,配置方式可以避免在Action中通過硬編碼來處理異常,從而提高應用程序異常處理的靈活性和可維護性。一般情況下,一個異常處理對象可以通過以下步驟實現(xiàn): 1.實現(xiàn)org.apache.struts.action.ExceptionHandler的子類,覆蓋execute()方法,在該方法中處理異常并且返回一個ActionForward對象。 2.在配置文件中配置異常處理對象,你可以配置一個全局的處理類或者單獨為每個Action配置處理類。 代碼清單 4定義了一個全局的處理類TestExceptionHandler,它被用來處理所有的異常。 代碼清單 4 一個全局宣告式異常處理的配置
type屬性定義了匹配的異常,path定義了異常發(fā)生后轉(zhuǎn)發(fā)的地址,而handler指定在轉(zhuǎn)發(fā)前對異常的特殊處理,如果沒有提供handler,默認的處理類org.apache.struts.action.ExceptionHandler。 |
開發(fā)環(huán)境:? Java?SDK?(I?am?currently?using?version?1.4.1)? Ant?(using?version?1.5.3) Apache?Tomcat?(using?version?4.1.24) 您可以用功能相同的任何容器或者java運行環(huán)境? 第1步:開發(fā)路徑? 為了保留我們的開發(fā)中每一步的流程,我們將保存所有的源碼和文件。? 首先,我們創(chuàng)建一個springapp的目錄(你可以將這個目錄建在任何地方),然后,在springapp目錄下創(chuàng)建子目錄src,用來保存java資源文件。然后我們建立另一個子目錄war,這個目錄將保存生成的war文件。? 建立WEB-INF子目錄,和它的classes,lib子目錄。? OK,你的目錄應該這個樣子:? 代碼:? -spirngapp? ??-WEB-INF? ??????-classes? ??????-lib? ??-src? ??-war? 第2步:創(chuàng)建jsp? 我們創(chuàng)建一個jsp文件-index.jsp在springapp目錄下,這將是我們應用程序的入口.? 代碼:? springapp/index.jsp? <html>? <head><title>Example?::?Spring?Application</title></head>? <body>? <h1>Example?-?Spring?Application</h1>? <p>This?is?my?test.</p>? </body>? </html>?????? 現(xiàn)在,我們來完成這個web應用,在WEB-INF下建立web.xml文件? 代碼:? springapp/WEB-INF/web.xml? <?xml?version="1.0"?encoding="UTF-8"?>? <!DOCTYPE?web-app?PUBLIC?'-//Sun?Microsystems,?Inc.//DTD?Web?Application?2.3//EN'?'http://java.sun.com/dtd/web-app_2_3.dtd'>? <web-app>? ??<welcome-file-list>? ????<welcome-file>? ??????index.jsp? ????</welcome-file>? ??</welcome-file-list>? </web-app>? 第3步:部署這個應用到Tomcat? 現(xiàn)在我們來寫Ant腳本文件,用于建立,部署,控制這個應用.? 代碼:? springapp/build.xml? <?xml?version="1.0"?encoding="gb2312"?>? <project?name="springapp"?basedir="."?default="usage">? ????<property?file="build.properties"/>? ????<property?name="src.dir"?value="src"/>? ????<property?name="web.dir"?value="war"/>? ????<property?name="build.dir"?value="${web.dir}/WEB-INF/classes"/>? ????<property?name="name"?value="springapp"/>? ????<path?id="master-classpath">? ????????<fileset?dir="${web.dir}/WEB-INF/lib">? ????????????<include?name="*.jar"/>? ????????</fileset>? ????????<fileset?dir="${tomcat.home}/common/lib">? ????????????<include?name="servlet.jar"/>? ????????</fileset>? ????</path>? ????<target?name="usage">? ????????<echo?message=""/>? ????????<echo?message="${name}?build?file"/>? ????????<echo?message="-----------------------------------"/>? ????????<echo?message=""/>? ????????<echo?message="Available?targets?are:"/>? ????????<echo?message=""/>? ????????<echo?message="build???????-->?建立應用"/>? ????????<echo?message="deploy?????-->?部署應用"/>? ????????<echo?message="deploywar?-->?部署war文件"/>? ????????<echo?message="install???-->?安裝應用"/>? ????????<echo?message="reload???-->?重載應用"/>? ????????<echo?message="start??????-->?啟動Tomcat?application"/>? ????????<echo?message="stop??????-->?停止?Tomcat?application"/>? ????????<echo?message="list????????-->??列表?Tomcat?applications"/>? ????????<echo?message=""/>? ????</target>? <!--?===========================================================?-->? <!--?spring?tasks?by?yanger?2003-11?-->? <!--?===========================================================?-->? ????<target?name="build"?description="Compile?main?source?tree?java?files">? ????????<mkdir?dir="${build.dir}"/>? ????????<javac?destdir="${build.dir}"?target="1.3"?debug="true"? ???????????????deprecation="false"?optimize="false"?failonerror="true">? ????????????<src?path="${src.dir}"/>? ????????????<classpath?refid="master-classpath"/>? ????????</javac>? ????</target>? ????<target?name="deploy"?depends="build"?description="Deploy?application">? ????????<copy?todir="${tomcat.home}/webapps/${name}"?preservelastmodified="true">? ????????????<fileset?dir="${web.dir}">? ????????????????<include?name="**/*.*"/>? ????????????</fileset>? ????????</copy>? ????</target>? ????<target?name="deploywar"?depends="build"?description="Deploy?application?as?a?WAR?file">? ????????<war?destfile="${name}.war"? ?????????????webxml="${web.dir}/WEB-INF/web.xml">? ????????????<fileset?dir="${web.dir}">? ????????????????<include?name="**/*.*"/>? ????????????</fileset>? ????????</war>? ????????<copy?todir="${deploy.path}"?preservelastmodified="true">? ????????????<fileset?dir=".">? ????????????????<include?name="*.war"/>? ????????????</fileset>? ????????</copy>? ????</target>? <!--?============================================================?-->? <!--?Tomcat?tasks?-?remove?these?if?you?don't?have?Tomcat?installed?-->? <!--?============================================================?-->? ????<taskdef?name="install"?classname="org.apache.catalina.ant.InstallTask">? ????????<classpath>? ????????????<path?location="${tomcat.home}/server/lib/catalina-ant.jar"/>? ????????</classpath>? ????</taskdef>? ????<taskdef?name="reload"?classname="org.apache.catalina.ant.ReloadTask">? ????????<classpath>? ????????????<path?location="${tomcat.home}/server/lib/catalina-ant.jar"/>? ????????</classpath>? ????</taskdef>? ????<taskdef?name="list"?classname="org.apache.catalina.ant.ListTask">? ????????<classpath>? ????????????<path?location="${tomcat.home}/server/lib/catalina-ant.jar"/>? ????????</classpath>? ????</taskdef>? ????<taskdef?name="start"?classname="org.apache.catalina.ant.StartTask">? ????????<classpath>? ????????????<path?location="${tomcat.home}/server/lib/catalina-ant.jar"/>? ????????</classpath>? ????</taskdef>? ????<taskdef?name="stop"?classname="org.apache.catalina.ant.StopTask">? ????????<classpath>? ????????????<path?location="${tomcat.home}/server/lib/catalina-ant.jar"/>? ????????</classpath>? ????</taskdef>? ????<target?name="install"?description="Install?application?in?Tomcat">? ????????<install?url="${tomcat.manager.url}"? ?????????????????username="${tomcat.manager.username}"? ?????????????????password="${tomcat.manager.password}"? ?????????????????path="/${name}"? ?????????????????war="${name}"/>? ????</target>? ????<target?name="reload"?description="Reload?application?in?Tomcat">? ????????<reload?url="${tomcat.manager.url}"? ?????????????????username="${tomcat.manager.username}"? ?????????????????password="${tomcat.manager.password}"? ?????????????????path="/${name}"/>? ????</target>? <target?name="start"?description="Start?Tomcat?application">? ????????<start?url="${tomcat.manager.url}"? ?????????????????username="${tomcat.manager.username}"? ?????????????????password="${tomcat.manager.password}"? ?????????????????path="/${name}"/>? ????</target>? ????<target?name="stop"?description="Stop?Tomcat?application">? ????????<stop?url="${tomcat.manager.url}"? ?????????????????username="${tomcat.manager.username}"? ?????????????????password="${tomcat.manager.password}"? ?????????????????path="/${name}"/>? ????</target>? ????<target?name="list"?description="List?Tomcat?applications">? ????????<list?url="${tomcat.manager.url}"? ?????????????????username="${tomcat.manager.username}"? ?????????????????password="${tomcat.manager.password}"/>? ????</target>? <!--?End?Tomcat?tasks?-->? </project>? 這個Ant腳本包含了建立應用主要的工具命令,但是,這個腳本要配合build.properties使用.? 代碼:? springapp/build.properties? #?Ant?properties?for?building?the?springapp? deploy.path=/home/trisberg/jakarta-tomcat-4.1.24/webapps? #deploy.path=c:/Tomcat?4.1/webapps? #deploy.path=c:/bea/user_projects/domains/mydomain/applications? tomcat.home=/home/trisberg/jakarta-tomcat-4.1.24? #tomcat.home=?c:/Tomcat?4.1? tomcat.manager.url=http://localhost:8080/manager? tomcat.manager.username=admin? tomcat.manager.password=tomcat? deploy.path?是tomcat的應用目錄? tomcat.path?是tomcat的主目錄? tomcat.manager.url是管理訪問路徑,注意你的端口是否正確? tomcat.manager.username,tomcat.manager.password?我就不用說了吧? 如果你執(zhí)行install命令,將在tomcat?webapps目錄下建立springapp目錄。? 如果你用其他的web應用服務(wù)器,那么你可以刪除tomcat指定的命令集,你可以用server提供的熱部署進行啟動和停止你的應用.? 現(xiàn)在我們來看一下ant提供的每個命令,在你的springapp目錄下執(zhí)行ant? 代碼:? C:\projects\springapp>ant? Buildfile:?build.xml? usage:? ?????[echo]?springapp?build?file? ?????[echo]?-----------------------------------? ?????[echo]?Available?targets?are:? ?????[echo]?build?????????????????-->?建立應用? ?????[echo]?deploy???????????????-->?部署應用? ?????[echo]?deploywar?????????-->?部署war文件? ?????[echo]?install????????????????-->?安裝應用? ?????[echo]?reload????????????????-->?重載應用? ?????[echo]?start???????????????????-->?啟動?springapp? ?????[echo]?stop???????????????????-->?停止?springapp? ?????[echo]?list?????????????????????-->?列表?Tomcat?applications? BUILD?SUCCESSFUL? Total?time:?5?seconds? 現(xiàn)在,我們來部署應用,執(zhí)行ant?deploy? 代碼:? Ant?deploy? e:\projects\springapp>ant?deploy? Buildfile:?build.xml? ?? deploy:? ?????[copy]?Copying?1?file?to?C:\Tomcat?4.1\webapps\springapp? ?? BUILD?SUCCESSFUL? Total?time:?1?seconds? 第4步:測試應用? 先看一下我們是否把應用部署成功? 代碼:? Ant?list? E:\projects\springapp>ant?list? Buildfile:?build.xml? list:? ?????[list]?OK?-?Listed?applications?for?virtual?host?localhost? ?????[list]?/admin:running:0:../server/webapps/admin? ?????[list]?/webdav:running:0:C:\Tomcat?4.1\webapps\webdav? ?????[list]?/springapp:running:1:C:\Tomcat?4.1\webapps\springapp? ?????[list]?/examples:running:0:examples? ?????[list]?/ofproject:running:0:C:\Tomcat?4.1\webapps\ofproject? ?????[list]?/tomcat-docs:running:0:C:\Tomcat?4.1\webapps\tomcat-docs? ?????[list]?/:running:0:C:\Tomcat?4.1\webapps\ROOT? ?????[list]?/manager:running:0:../server/webapps/manager? BUILD?SUCCESSFUL? Total?time:?5?seconds? 如果你還沒有安裝,請執(zhí)行ant?install? 代碼:? Ant?install? E:\projects\springapp>ant?install? Buildfile:?build.xml? ?? install:? ??[install]?OK?-?Installed?application?at?context?path?/springapp? ?? ?? BUILD?SUCCESSFUL? Total?time:?2?seconds? 現(xiàn)在,讓我們打開瀏覽器看一下結(jié)果http://localhost:8080/springapp/index.jsp? 第5步:下載spring?framework?package? 如果你還沒有下在spring,請到www.springframework.org/download.html.?尋找最新版本.? 下面我們將完成利用spring?framework?進行開發(fā)MVC?應用程序.? 第6步:修改web.xml? 進入WEB-INF目錄編輯web.xml? 代碼:? WEB-INF/web.xml? <?xml?version="1.0"?encoding="UTF-8"?>? <!DOCTYPE?web-app?PUBLIC?'-//Sun?Microsystems,?Inc.//DTD?Web?Application?2.3//EN'?'http://java.sun.com/dtd/web-app_2_3.dtd'>? <web-app>? ?<servlet>? ????<servlet-name>springapp</servlet-name>? ????<servlet-class>? ???????org.springframework.web.servlet.DispatcherServlet? ????</servlet-class>? ????<load-on-startup>1</load-on-startup>? ??</servlet>? ??<servlet-mapping>? ????<servlet-name>springapp</servlet-name>? ????<url-pattern>*.htm</url-pattern>? ??</servlet-mapping>? ??<welcome-file-list>? ????<welcome-file>? ??????index.jsp? ????</welcome-file>? ??</welcome-file-list>? </web-app>? 在WEB-INF目錄下創(chuàng)建一個springapp-servlet.xml文件,它的命名規(guī)則是web.xml中的servlet-name?加上'-servlet'后綴,這是在springframework中的標準命名法則.? 現(xiàn)在,我們聲明一個bean?:springappController?他對應的類是SpringappController.class? 這個定義用于我們控制業(yè)務(wù)邏輯。我們還需要定義一個url?mapping作為http調(diào)用的路徑.? 代碼:? springapp/WEB-INF/springapp-servlet.xml? <?xml?version="1.0"?encoding="UTF-8"?>? <!DOCTYPE?beans?PUBLIC?"-//SPRING//DTD?BEAN//EN"?"http://www.springframework.org/dtd/spring-beans.dtd">? <!--? ??-?Application?context?definition?for?"springapp"?DispatcherServlet.? ??-->? <beans>? ????<bean?id="springappController"?class="SpringappController"/>? ????<bean?id="urlMapping"?class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">? ????????<property?name="mappings">? ????????????<props>? ????????????????<prop?key="/hello.htm">springappController</prop>? ????????????</props>? ????????</property>? ????</bean>? </beans>? 第7步:添加支持包? 從spring的下載文件包中找到,spring.jar?(spring-framework-1.0-m1/dist/spring.jar)?拷貝到WEB-INF/lib下面。? 拷貝spring-framework-1.0-m1/lib/log4j/log4j-1.2.8.jar?和?spring-framework-1.0-m1/lib/jakarta-commons/commons-logging.jar到WEB-INF/lib下面。? 第8步:創(chuàng)建springappController? 代碼:? springapp/src/SpringappController.java? import?org.springframework.web.servlet.mvc.Controller;? import?org.springframework.web.servlet.ModelAndView;? import?javax.servlet.ServletException;? import?javax.servlet.http.HttpServletRequest;? import?javax.servlet.http.HttpServletResponse;? import?java.io.IOException;? public?class?SpringappController?implements?Controller?{? ????public?ModelAndView?handleRequest(HttpServletRequest?request,?HttpServletResponse?response)? ????????????throws?ServletException,?IOException?{? ????????return?new?ModelAndView("");? ????}? }? 這只是一個基礎(chǔ)控制框架,稍候我們完成它.? 第9步:建立應用? 代碼:? Ant?build? E:\projects\springapp>ant?build? Buildfile:?build.xml? build:? ????[javac]?Compiling?1?source?file?to?E:\projects\springapp\WEB-INF\classes? BUILD?SUCCESSFUL? Total?time:?2?seconds? 第10步:建立日志系統(tǒng)? spring利用log4j來管理日志,在classes目錄下建立log4j.properties? 代碼:? springapp/war/WEB-INF/classes/log4j.properties? log4j.rootCategory=INFO,?stdout,?logfile? log4j.appender.stdout=org.apache.log4j.ConsoleAppender? log4j.appender.stdout.layout=org.apache.log4j.PatternLayout? log4j.appender.stdout.layout.ConversionPattern=%d?%p?[%c]?-?<%m>%n? log4j.appender.logfile=org.apache.log4j.RollingFileAppender? log4j.appender.logfile.File=e:/projects/springapp/springapp.log? log4j.appender.logfile.MaxFileSize=512KB? #?Keep?three?backup?files? log4j.appender.logfile.MaxBackupIndex=3? log4j.appender.logfile.layout=org.apache.log4j.PatternLayout? #Pattern?to?output?:?date?priority?[category]?-?<message>line_separator? log4j.appender.logfile.layout.ConversionPattern=%d?%p?[%c]?-?<%m>%n? 第11步:部署應用? 運行ant?deploy? 第12步:創(chuàng)建視圖? 代碼:? springapp/war/hello.jsp? <html>? <head><title>Example?::?Spring?Application</title></head>? <body>? <h1>Hello?-?Spring?Application</h1>? <p>Greetings.</p>? </body>? </html>? 下面我們修改SpringappController.java? 代碼:? springapp/src/SpringappController.java? import?org.springframework.web.servlet.mvc.Controller;? import?org.springframework.web.servlet.ModelAndView;? import?javax.servlet.ServletException;? import?javax.servlet.http.HttpServletRequest;? import?javax.servlet.http.HttpServletResponse;? import?java.io.IOException;? import?org.apache.commons.logging.Log;? import?org.apache.commons.logging.LogFactory;? public?class?SpringappController?implements?Controller?{? ???/**?Logger?for?this?class?and?subclasses?*/? ????protected?final?Log?logger?=?LogFactory.getLog(getClass());? ????public?ModelAndView?handleRequest(HttpServletRequest?request,?HttpServletResponse?response)? ????????????throws?ServletException,?IOException?{? ???????logger.info("SpringappController?-?returning?hello?view");? ????????return?new?ModelAndView("hello.jsp");? ????}? }? 現(xiàn)在我們運行build,?deploy,?stop,?start?命令.? 這樣我們就成功地建立了一個mvc應用,訪問http://loaclhost:8080/springapp/hello.htm? 小結(jié)? 以上,我們快速地利用spring?framework建立了MVC應用程序,? 1、建立index.jsp,測試管理工具和開發(fā)環(huán)境? 2、編寫springapp-servlet.xml配置文件。? 3、編寫控制器代碼,SpringappController.java結(jié)合springapp-servlet中的定義進行工作.? 4、編寫、展示hello.jsp,完成MVC的應用程序.? |
第一部分:選擇題
QUESTION NO: 1
1、public class Test {
public static void changeStr(String str){
str="welcome";
}
public static void main(String[] args) {
String str="1234";
changeStr(str);
System.out.println(str);
}
}
Please write the output result :
QUESTION NO:2
1. public class Test {
2. static boolean foo(char c) {
3. System.out.print(c);
4. return true;
5. }
6. public static void main( String[] argv ) {
7. int i =0;
8. for ( foo('A'); foo('B')&&(i<2); foo('C')){
9. i++ ;
10. foo('D');
12. }
13. }
14. }
What is the result?
A. ABDCBDCB
B. ABCDABCD
C. Compilation fails.
D. An exception is thrown at runtime.
QUESTION NO: 3
1. class A {
2. protected int method1(int a, int b) { return 0; }
3. }
Which two are valid in a class that extends class A? (Choose two)
A. public int method1(int a, int b) { return 0; }
B. private int method1(int a, int b) { return 0; }
C. private int method1(int a, long b) { return 0; }
D. public short method1(int a, int b) { return 0; }
E. static protected int method1(int a, int b) { return 0; }
QUESTION NO: 4
1. public class Outer{
2. public void someOuterMethod() {
3. // Line 3
4. }
5. public class Inner{}
6. public static void main( String[]argv ) {
7. Outer o = new Outer();
8. // Line 8
9. }
10. }
Which instantiates an instance of Inner?
A. new Inner(); // At line 3
B. new Inner(); // At line 8
C. new o.Inner(); // At line 8
D. new Outer.Inner(); // At line 8//new Outer().new Inner()
QUESTION NO: 5
Which method is used by a servlet to place its session ID in a URL that is written to the servlet's response output stream?
A. The encodeURL method of the HttpServletRequest interface.
B. The encodeURL method of the HttpServletResponse interface.
C. The rewriteURL method of the HttpServletRequest interface.
D. The rewriteURL method of the HttpServletResponse interface.
QUESTION NO: 6
Which two are equivalent? (Choose two)
A. <%= YoshiBean.size%>
B. <%= YoshiBean.getSize()%>
C. <%= YoshiBean.getProperty("size")%>
D. <jsp:getProperty id="YoshiBean" param="size"/>
E. <jsp:getProperty name="YoshiBean" param="size"/>
F. <jsp:getProperty id="YoshiBean" property="size"/>
G. <jsp:getProperty name="YoshiBean" property="size"/>
QUESTION NO: 7
Which of the following statements regarding the lifecycle of a session bean are correct?
1. java.lang.IllegalStateException is thrown if SessionContext.getEJBObject() is invoked when a stateful session bean instance is passivated.
2. SessionContext.getRollbackOnly() does not throw an exception when a session bean with bean-managed transaction demarcation is activated.
3. An exception is not thrown when SessionContext.getUserTransaction() is called in the afterBegin method of a bean with container-managed transactions.
4. JNDI access to java:comp/env is permitted in all the SessionSynchronization methods of a stateful session bean with container-managed transaction demarcation.
5. Accessing resource managers in the SessionSynchronization.afterBegin method of a stateful session bean with bean-managed transaction does not throw an exception.
第二部分:概念題
1. 描述Struts體系結(jié)構(gòu)?對應各個部分的開發(fā)工作主要包括哪些?
2. XML包括哪些解釋技術(shù),區(qū)別是什么?
3. JSP有哪些內(nèi)置對象和動作?它們的作用分別是什么?
4、SQL問答題
SELECT * FROM TABLE
和
SELECT * FROM TABLE
WHERE NAME LIKE '%%' AND ADDR LIKE '%%'
AND (1_ADDR LIKE '%%' OR 2_ADDR LIKE '%%'
OR 3_ADDR LIKE '%%' OR 4_ADDR LIKE '%%' )
的檢索結(jié)果為何不同?
5、SQL問答題
表結(jié)構(gòu):
1、 表名:g_cardapply
字段(字段名/類型/長度):
g_applyno varchar 8;//申請單號(關(guān)鍵字)
g_applydate bigint 8;//申請日期
g_state varchar 2;//申請狀態(tài)
2、 表名:g_cardapplydetail
字段(字段名/類型/長度):
g_applyno varchar 8;//申請單號(關(guān)鍵字)
g_name varchar 30;//申請人姓名
g_idcard varchar 18;//申請人身份證號
g_state varchar 2;//申請狀態(tài)
其中,兩個表的關(guān)聯(lián)字段為申請單號。
題目:
1、 查詢身份證號碼為440401430103082的申請日期
2、 查詢同一個身份證號碼有兩條以上記錄的身份證號碼及記錄個數(shù)
3、 將身份證號碼為440401430103082的記錄在兩個表中的申請狀態(tài)均改為07
4、 刪除g_cardapplydetail表中所有姓李的記錄
在應用程序中添加日志記錄總的來說基于三個目的:監(jiān)視代碼中變量的變化情況,周期性的記錄到文件中供其他應用進行統(tǒng)計分析工作;跟蹤代碼運行時軌跡,作為日后審計的依據(jù);擔當集成開發(fā)環(huán)境中的調(diào)試器的作用,向文件或控制臺打印代碼的調(diào)試信息。
最普通的做法就是在代碼中嵌入許多的打印語句,這些打印語句可以輸出到控制臺或文件中,比較好的做法就是構(gòu)造一個日志操作類來封裝此類操作,而不是讓一系列的打印語句充斥了代碼的主體。
在強調(diào)可重用組件開發(fā)的今天,除了自己從頭到尾開發(fā)一個可重用的日志操作類外,Apache為我們提供了一個強有力的日志操作包-Log4j。
Log4j是Apache的一個開放源代碼項目,通過使用Log4j,我們可以控制日志信息輸送的目的地是控制臺、文件、GUI組件、甚至是套接口服務(wù)器、NT的事件記錄器、UNIX Syslog守護進程等;我們也可以控制每一條日志的輸出格式;通過定義每一條日志信息的級別,我們能夠更加細致地控制日志的生成過程。最令人感興趣的就是,這些可以通過一個配置文件來靈活地進行配置,而不需要修改應用的代碼。
此外,通過Log4j其他語言接口,您可以在C、C++、.Net、PL/SQL程序中使用Log4j,其語法和用法與在Java程序中一樣,使得多語言分布式系統(tǒng)得到一個統(tǒng)一一致的日志組件模塊。而且,通過使用各種第三方擴展,您可以很方便地將Log4j集成到J2EE、JINI甚至是SNMP應用中。
本文介紹的Log4j版本是1.2.3。作者試圖通過一個簡單的客戶/服務(wù)器Java程序例子對比使用與不使用Log4j 1.2.3的差別,并詳細講解了在實踐中最常使用Log4j的方法和步驟。在強調(diào)可重用組件開發(fā)的今天,相信Log4j將會給廣大的設(shè)計開發(fā)人員帶來方便。加入到Log4j的隊伍來吧!
我們先來看一個簡單的例子,它是一個用Java實現(xiàn)的客戶/服務(wù)器網(wǎng)絡(luò)程序。剛開始我們不使用Log4j,而是使用了一系列的打印語句,然后我們將使用Log4j來實現(xiàn)它的日志功能。這樣,大家就可以清楚地比較出前后兩個代碼的差別。
2.1.1. 客戶程序
package log4j ;
import java.io.* ;
import java.net.* ;
/**
*
* <p> Client Without Log4j </p>
* <p> Description: a sample with log4j</p>
* @version 1.0
*/
public class ClientWithoutLog4j {
/**
*
* @param args
*/
public static void main ( String args [] ) {
String welcome = null;
String response = null;
BufferedReader reader = null;
PrintWriter writer = null;
InputStream in = null;
OutputStream out = null;
Socket client = null;
try {
client = new Socket ( "localhost", 8001 ) ;
System.out.println ( "info: Client socket: " + client ) ;
in = client.getInputStream () ;
out = client.getOutputStream () ;
} catch ( IOException e ) {
System.out.println ( "error: IOException : " + e ) ;
System.exit ( 0 ) ;
}
try{
reader = new BufferedReader( new InputStreamReader ( in ) ) ;
writer = new PrintWriter ( new OutputStreamWriter ( out ), true ) ;
welcome = reader.readLine () ;
System.out.println ( "debug: Server says: '" + welcome + "'" ) ;
System.out.println ( "debug: HELLO" ) ;
writer.println ( "HELLO" ) ;
response = reader.readLine () ;
System.out.println ( "debug: Server responds: '" + response + "'") ;
System.out.println ( "debug: HELP" ) ;
writer.println ( "HELP" ) ;
response = reader.readLine () ;
System.out.println ( "debug: Server responds: '" + response + "'" ) ;
System.out.println ( "debug: QUIT" ) ;
writer.println ( "QUIT" ) ;
} catch ( IOException e ) {
System.out.println ( "warn: IOException in client.in.readln()" ) ;
System.out.println ( e ) ;
}
try{
Thread.sleep ( 2000 ) ;
} catch ( Exception ignored ) {}
}
}
2.1.2. 服務(wù)器程序
package log4j ;
import java.util.* ;
import java.io.* ;
import java.net.* ;
/**
*
* <p> Server Without Log4j </p>
* <p> Description: a sample with log4j</p>
* @version 1.0
*/
public class ServerWithoutLog4j {
final static int SERVER_PORT = 8001 ; // this server's port
/**
*
* @param args
*/
public static void main ( String args [] ) {
String clientRequest = null;
BufferedReader reader = null;
PrintWriter writer = null;
ServerSocket server = null;
Socket socket = null;
InputStream in = null;
OutputStream out = null;
try {
server = new ServerSocket ( SERVER_PORT ) ;
System.out.println ( "info: ServerSocket before accept: " + server ) ;
System.out.println ( "info: Java server without log4j, on-line!" ) ;
// wait for client's connection
socket = server.accept () ;
System.out.println ( "info: ServerSocket after accept: " + server ) ;
in = socket.getInputStream () ;
out = socket.getOutputStream () ;
} catch ( IOException e ) {
System.out.println( "error: Server constructor IOException: " + e ) ;
System.exit ( 0 ) ;
}
reader = new BufferedReader ( new InputStreamReader ( in ) ) ;
writer = new PrintWriter ( new OutputStreamWriter ( out ) , true ) ;
// send welcome string to client
writer.println ( "Java server without log4j, " + new Date () ) ;
while ( true ) {
try {
// read from client
clientRequest = reader.readLine () ;
System.out.println ( "debug: Client says: " + clientRequest ) ;
if ( clientRequest.startsWith ( "HELP" ) ) {
System.out.println ( "debug: OK!" ) ;
writer.println ( "Vocabulary: HELP QUIT" ) ;
}
else {
if ( clientRequest.startsWith ( "QUIT" ) ) {
System.out.println ( "debug: OK!" ) ;
System.exit ( 0 ) ;
}
else{
System.out.println ( "warn: Command '" +
clientRequest + "' not understood." ) ;
writer.println ( "Command '" + clientRequest
+ "' not understood." ) ;
}
}
} catch ( IOException e ) {
System.out.println ( "error: IOException in Server " + e ) ;
System.exit ( 0 ) ;
}
}
}
}
2.2.1. 客戶程序
package log4j ;
import java.io.* ;
import java.net.* ;
// add for log4j: import some package
import org.apache.log4j.PropertyConfigurator ;
import org.apache.log4j.Logger ;
import org.apache.log4j.Level ;
/**
*
* <p> Client With Log4j </p>
* <p> Description: a sample with log4j</p>
* @version 1.0
*/
public class ClientWithLog4j {
/*
add for log4j: class Logger is the central class in the log4j package.
we can do most logging operations by Logger except configuration.
getLogger(...): retrieve a logger by name, if not then create for it.
*/
static Logger logger = Logger.getLogger
( ClientWithLog4j.class.getName () ) ;
/**
*
* @param args : configuration file name
*/
public static void main ( String args [] ) {
String welcome = null ;
String response = null ;
BufferedReader reader = null ;
PrintWriter writer = null ;
InputStream in = null ;
OutputStream out = null ;
Socket client = null ;
/*
add for log4j: class BasicConfigurator can quickly configure the package.
print the information to console.
*/
PropertyConfigurator.configure ( "ClientWithLog4j.properties" ) ;
// add for log4j: set the level
// logger.setLevel ( ( Level ) Level.DEBUG ) ;
try{
client = new Socket( "localhost" , 8001 ) ;
// add for log4j: log a message with the info level
logger.info ( "Client socket: " + client ) ;
in = client.getInputStream () ;
out = client.getOutputStream () ;
} catch ( IOException e ) {
// add for log4j: log a message with the error level
logger.error ( "IOException : " + e ) ;
System.exit ( 0 ) ;
}
try{
reader = new BufferedReader ( new InputStreamReader ( in ) ) ;
writer = new PrintWriter ( new OutputStreamWriter ( out ), true ) ;
welcome = reader.readLine () ;
// add for log4j: log a message with the debug level
logger.debug ( "Server says: '" + welcome + "'" ) ;
// add for log4j: log a message with the debug level
logger.debug ( "HELLO" ) ;
writer.println ( "HELLO" ) ;
response = reader.readLine () ;
// add for log4j: log a message with the debug level
logger.debug ( "Server responds: '" + response + "'" ) ;
// add for log4j: log a message with the debug level
logger.debug ( "HELP" ) ;
writer.println ( "HELP" ) ;
response = reader.readLine () ;
// add for log4j: log a message with the debug level
logger.debug ( "Server responds: '" + response + "'") ;
// add for log4j: log a message with the debug level
logger.debug ( "QUIT" ) ;
writer.println ( "QUIT" ) ;
} catch ( IOException e ) {
// add for log4j: log a message with the warn level
logger.warn ( "IOException in client.in.readln()" ) ;
System.out.println ( e ) ;
}
try {
Thread.sleep ( 2000 ) ;
} catch ( Exception ignored ) {}
}
}
2.2.2. 服務(wù)器程序
package log4j;
import java.util.* ;
import java.io.* ;
import java.net.* ;
// add for log4j: import some package
import org.apache.log4j.PropertyConfigurator ;
import org.apache.log4j.Logger ;
import org.apache.log4j.Level ;
/**
*
* <p> Server With Log4j </p>
* <p> Description: a sample with log4j</p>
* @version 1.0
*/
public class ServerWithLog4j {
final static int SERVER_PORT = 8001 ; // this server's port
/*
add for log4j: class Logger is the central class in the log4j package.
we can do most logging operations by Logger except configuration.
getLogger(...): retrieve a logger by name, if not then create for it.
*/
static Logger logger = Logger.getLogger
( ServerWithLog4j.class.getName () ) ;
/**
*
* @param args
*/
public static void main ( String args[]) {
String clientRequest = null ;
BufferedReader reader = null ;
PrintWriter writer = null ;
ServerSocket server = null ;
Socket socket = null ;
InputStream in = null ;
OutputStream out = null ;
/*
add for log4j: class BasicConfigurator can quickly configure the package.
print the information to console.
*/
PropertyConfigurator.configure ( "ServerWithLog4j.properties" ) ;
// add for log4j: set the level
// logger.setLevel ( ( Level ) Level.DEBUG ) ;
try{
server = new ServerSocket ( SERVER_PORT ) ;
// add for log4j: log a message with the info level
logger.info ( "ServerSocket before accept: " + server ) ;
// add for log4j: log a message with the info level
logger.info ( "Java server with log4j, on-line!" ) ;
// wait for client's connection
socket = server.accept() ;
// add for log4j: log a message with the info level
logger.info ( "ServerSocket after accept: " + server ) ;
in = socket.getInputStream() ;
out = socket.getOutputStream() ;
} catch ( IOException e ) {
// add for log4j: log a message with the error level
logger.error ( "Server constructor IOException: " + e ) ;
System.exit ( 0 ) ;
}
reader = new BufferedReader ( new InputStreamReader ( in ) ) ;
writer = new PrintWriter ( new OutputStreamWriter ( out ), true ) ;
// send welcome string to client
writer.println ( "Java server with log4j, " + new Date () ) ;
while ( true ) {
try {
// read from client
clientRequest = reader.readLine () ;
// add for log4j: log a message with the debug level
logger.debug ( "Client says: " + clientRequest ) ;
if ( clientRequest.startsWith ( "HELP" ) ) {
// add for log4j: log a message with the debug level
logger.debug ( "OK!" ) ;
writer.println ( "Vocabulary: HELP QUIT" ) ;
}
else {
if ( clientRequest.startsWith ( "QUIT" ) ) {
// add for log4j: log a message with the debug level
logger.debug ( "OK!" ) ;
System.exit ( 0 ) ;
}
else {
// add for log4j: log a message with the warn level
logger.warn ( "Command '"
+ clientRequest + "' not understood." ) ;
writer.println ( "Command '"
+ clientRequest + "' not understood." ) ;
}
}
} catch ( IOException e ) {
// add for log4j: log a message with the error level
logger.error( "IOException in Server " + e ) ;
System.exit ( 0 ) ;
}
}
}
}
2.2.3. 配置文件
2.2.3.1. 客戶程序配置文件
log4j.rootLogger=INFO, A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
2.2.3.2. 服務(wù)器程序配置文件
log4j.rootLogger=INFO, A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
比較這兩個應用可以看出,采用Log4j進行日志操作的整個過程相當簡單明了,與直接使用System.out.println語句進行日志信息輸出的方式相比,基本上沒有增加代碼量,同時能夠清楚地理解每一條日志信息的重要程度。通過控制配置文件,我們還可以靈活地修改日志信息的格式,輸出目的地等等方面,而單純依靠System.out.println語句,顯然需要做更多的工作。
下面我們將以前面使用Log4j的應用作為例子,詳細講解使用Log4j的主要步驟。
Log4j由三個重要的組件構(gòu)成:日志信息的優(yōu)先級,日志信息的輸出目的地,日志信息的輸出格式。日志信息的優(yōu)先級從高到低有ERROR、WARN、INFO、DEBUG,分別用來指定這條日志信息的重要程度;日志信息的輸出目的地指定了日志將打印到控制臺還是文件中;而輸出格式則控制了日志信息的顯示內(nèi)容。
其實您也可以完全不使用配置文件,而是在代碼中配置Log4j環(huán)境。但是,使用配置文件將使您的應用程序更加靈活。
Log4j支持兩種配置文件格式,一種是XML格式的文件,一種是Java特性文件(鍵=值)。下面我們介紹使用Java特性文件做為配置文件的方法:
log4j.rootLogger = [ level ] , appenderName, appenderName, …其中,level 是日志記錄的優(yōu)先級,分為OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定義的級別。Log4j建議只使用四個級別,優(yōu)先級從高到低分別是ERROR、WARN、INFO、DEBUG。通過在這里定義的級別,您可以控制到應用程序中相應級別的日志信息的開關(guān)。比如在這里定義了INFO級別,則應用程序中所有DEBUG級別的日志信息將不被打印出來。
log4j.appender.appenderName = fully.qualified.name.of.appender.class log4j.appender.appenderName.option1 = value1 … log4j.appender.appenderName.option = valueN其中,Log4j提供的appender有以下幾種:
log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class log4j.appender.appenderName.layout.option1 = value1 … log4j.appender.appenderName.layout.option = valueN其中,Log4j提供的layout有以下幾種:
下面將講述在程序代碼中怎樣使用Log4j。
3.2.1.得到記錄器
使用Log4j,第一步就是獲取日志記錄器,這個記錄器將負責控制日志信息。其語法為:
public static Logger getLogger( String name),通過指定的名字獲得記錄器,如果必要的話,則為這個名字創(chuàng)建一個新的記錄器。Name一般取本類的名字,比如:
static Logger logger = Logger.getLogger ( ServerWithLog4j.class.getName () ) ;
3.2.2.讀取配置文件
當獲得了日志記錄器之后,第二步將配置Log4j環(huán)境,其語法為:
BasicConfigurator.configure (): 自動快速地使用缺省Log4j環(huán)境。
PropertyConfigurator.configure ( String configFilename) :讀取使用Java的特性文件編寫的配置文件。
DOMConfigurator.configure ( String filename ) :讀取XML形式的配置文件。
3.2.3.插入記錄信息(格式化日志信息)
當上兩個必要步驟執(zhí)行完畢,您就可以輕松地使用不同優(yōu)先級別的日志記錄語句插入到您想記錄日志的任何地方,其語法如下:
Logger.debug ( Object message ) ; Logger.info ( Object message ) ; Logger.warn ( Object message ) ; Logger.error ( Object message ) ;
如果您想更深入地了解Log4j,請經(jīng)常訪問下面提及的相關(guān)鏈接。
Log4j項目主頁------------------------------------------------------http://www.log4j.org/
Log4j FAQ -------------------------------------------------------http://www-900.ibm.com/developerWorks/cn/java/l-log4j/www.log4j.org/log4j/faq.html
1 適合讀者
本文針對有一定的web基礎(chǔ),webwork基礎(chǔ),對spring有一定的了解。
http://www.springframework.org/ 站點可以了解更多關(guān)于spring的詳細信息. Spring是一個很好的AOP框架,能提供自動的事務(wù)管理。
http://www.opensymphony.com/webwork/ 站點可以了解更多的webwork . Webwork是一個很好的 MVC 框架,以下簡單介紹,webwork 和 spring 的融合,以用戶注冊為例。
2 整合步驟
2 .1使用 SpringObjectFactory
dev.java.net上的 xwork-optional 包括了對 xwork-spring 的支持,可以下載些包。包中只有4個類,可以根據(jù)具體情況使用。我在例子中使用了SpringObjectFactory類和SpringObjectFactoryListener 類,并安照webwork的文件在web.xml加入了,以下節(jié)點
<!-- This needs to be after Spring ContextLoaderListener -->
<listener>
<listener-class>com.opensymphony.xwork.spring.SpringObjectFactoryListener</listener-class>
</listener>
但在實際工作中不能使用,回為在SpringObjectFactoryListener類中寫的,加載些類必須要先加載org.springframework.web.context.ContextLoaderListener類,由于些類在web.xml配置如下,后于listener的執(zhí)行。
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
ContextLoaderServlet 的作用是加載 spring配置信息(在int方法中),SpringObjectFactoryListener 的作用是設(shè)置 XWork 和 Webwork 的環(huán)境,使這能從spring 中加載數(shù)據(jù)和信息(在contextInitialized(ServletContextEvent event)方法中,當啟動web應用程序是調(diào)用).
要使ContextLoaderServlet比SpringObjectFactoryListener類更早執(zhí)行,我使用的方法是重載ContextLoaderServlet,在中子類的int方法中設(shè)置XWork 和 Webwork 的環(huán)境,去掉SpringObjectFactoryListener 監(jiān)聽器,并整改web.xml中的spring配置,如下:
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>spring.server.ContextLoaderServletServer</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
2 .2 配置webwork
在webwork.xml中增加如下節(jié)點
<action name="registerSupport-spring" class="registerSupportBean" >
<result name="success" type="dispatcher">
<param name="location">/register-result.jsp</param>
</result>
<result name="input" type="dispatcher">
<param name="location">/registerSupport.jsp</param>
</result>
<interceptor-ref name="validationWorkflowStack"/>
</action>
其中的registerSupportBean在spring中配置
2 .3 配置spring
在spring中加入action 配置如下
<!-- action -->
<bean name="registerSupportBean" class="spring.action.RegisterActionSupport"
singleton="false" >
<property name="userBean">
<ref bean="userBean"/>
</property>
</bean>
些處的registerSupportBean 即為在webwork中要調(diào)用的類名。
匹配中文字符的正則表達式: [\u4e00-\u9fa5]
匹配雙字節(jié)字符(包括漢字在內(nèi)):[^\x00-\xff]
應用:計算字符串的長度(一個雙字節(jié)字符長度計2,ASCII字符計1)
String.prototype.len=function(){return this.replace([^\x00-\xff]/g,"aa").length;}
匹配空行的正則表達式:\n[\s| ]*\r
匹配HTML標記的正則表達式:/<(.*)>.*<\/\1>|<(.*) \/>/
匹配首尾空格的正則表達式:(^\s*)|(\s*$)
應用:javascript中沒有像vbscript那樣的trim函數(shù),我們就可以利用這個表達式來實現(xiàn),如下:
應用:javascript中沒有像vbscript那樣的trim函數(shù),我們就可以利用這個表達式來實現(xiàn),如下:String.prototype.trim = function()
{
return this.replace(/(^\s*)|(\s*$)/g, "");
}
利用正則表達式分解和轉(zhuǎn)換IP地址:
下面是利用正則表達式匹配IP地址,并將IP地址轉(zhuǎn)換成對應數(shù)值的Javascript程序:
function IP2V(ip)
{
re=/(\d+)\.(\d+)\.(\d+)\.(\d+)/g //匹配IP地址的正則表達式
if(re.test(ip))
{
return RegExp.$1*Math.pow(255,3))+RegExp.$2*Math.pow(255,2))+RegExp.$3*255+RegExp.$4*1
}
else
{
throw new Error("Not a valid IP address!")
}
}
不過上面的程序如果不用正則表達式,而直接用split函數(shù)來分解可能更簡單,程序如下:
var ip="10.100.20.168"
ip=ip.split(".")
alert("IP值是:"+(ip[0]*255*255*255+ip[1]*255*255+ip[2]*255+ip[3]*1))
匹配Email地址的正則表達式:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
匹配網(wǎng)址URL的正則表達式:http://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?
利用正則表達式去除字串中重復的字符的算法程序:[注:此程序不正確,原因見本貼回復]
var s="abacabefgeeii"
var s1=s.replace(/(.).*\1/g,"$1")
var re=new RegExp("["+s1+"]","g")
var s2=s.replace(re,"")
alert(s1+s2) //結(jié)果為:abcefgi
我原來在CSDN上發(fā)貼尋求一個表達式來實現(xiàn)去除重復字符的方法,最終沒有找到,這是我能想到的最簡單的實現(xiàn)方法。思路是使用后向引用取出包括重復的字符,再以重復的字符建立第二個表達式,取到不重復的字符,兩者串連。這個方法對于字符順序有要求的字符串可能不適用。
得用正則表達式從URL地址中提取文件名的javascript程序,如下結(jié)果為page1
s="http://www.9499.net/page1.htm"
s=s.replace(/(.*\/){0,}([^\.]+).*/ig,"$2")
alert(s)
利用正則表達式限制網(wǎng)頁表單里的文本框輸入內(nèi)容:
用正則表達式限制只能輸入中文:onkeyup="value=value.replace(/[^\u4E00-\u9FA5]/g,'')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\u4E00-\u9FA5]/g,''))"
用正則表達式限制只能輸入全角字符: onkeyup="value=value.replace(/[^\uFF00-\uFFFF]/g,'')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\uFF00-\uFFFF]/g,''))"
用正則表達式限制只能輸入數(shù)字:onkeyup="value=value.replace(/[^\d]/g,'') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))"
用正則表達式限制只能輸入數(shù)字和英文:onkeyup="value=value.replace(/[\W]/g,'') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))"
正則表達式,正規(guī)表達式,正則表達式匹配,正則表達式語法,模式匹配,正規(guī)表達式匹配 javascript正則表達式 ASP正則表達式 ASP.NET正則表達式 C#正則表達式 JSP正則表達式 PHP正則表達式 VB.NET正則表達式 VBSCript正則表達式編程 delphi正則表達式 jscript
正則表達式 regular expression
正則表達式 RegExp
模式 pattern
匹配 Match
.NET命名空間: System.Text.RegularExpression
補充:
^\d+$ //匹配非負整數(shù)(正整數(shù) + 0)
^[0-9]*[1-9][0-9]*$ //匹配正整數(shù)
^((-\d+)|(0+))$ //匹配非正整數(shù)(負整數(shù) + 0)
^-[0-9]*[1-9][0-9]*$ //匹配負整數(shù)
^-?\d+$ //匹配整數(shù)
^\d+(\.\d+)?$ //匹配非負浮點數(shù)(正浮點數(shù) + 0)
^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$ //匹配正浮點數(shù)
^((-\d+(\.\d+)?)|(0+(\.0+)?))$ //匹配非正浮點數(shù)(負浮點數(shù) + 0)
^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$ //匹配負浮點數(shù)
^(-?\d+)(\.\d+)?$ //匹配浮點數(shù)
^[A-Za-z]+$ //匹配由26個英文字母組成的字符串
^[A-Z]+$ //匹配由26個英文字母的大寫組成的字符串
^[a-z]+$ //匹配由26個英文字母的小寫組成的字符串
^[A-Za-z0-9]+$ //匹配由數(shù)字和26個英文字母組成的字符串
^\w+$ //匹配由數(shù)字、26個英文字母或者下劃線組成的字符串
^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$ //匹配email地址
^[a-zA-z]+://匹配(\w+(-\w+)*)(\.(\w+(-\w+)*))*(\?\S*)?$ //匹配url
利用正則表達式去除字串中重復的字符的算法程序:
var s="abacabefgeeii"
var s1=s.replace(/(.).*\1/g,"$1")
var re=new RegExp("["+s1+"]","g")
var s2=s.replace(re,"")
alert(s1+s2) //結(jié)果為:abcefgi
===============================
如果var s = "abacabefggeeii"
結(jié)果就不對了,結(jié)果為:abeicfgg
正則表達式的能力有限
RE: totoro
謝謝你的指點,這個javascript正則表達式程序算法確實有問題,我會試著找更好的辦法!!!
1.確認有效電子郵件格式
下面的代碼示例使用靜態(tài) Regex.IsMatch 方法驗證一個字符串是否為有效電子郵件格式。如果字符串包含一個有效的電子郵件地址,則 IsValidEmail 方法返回 true,否則返回 false,但不采取其他任何操作。您可以使用 IsValidEmail,在應用程序?qū)⒌刂反鎯υ跀?shù)據(jù)庫中或顯示在 ASP.NET 頁中之前,篩選出包含無效字符的電子郵件地址。
[Visual Basic]
Function IsValidEmail(strIn As String) As Boolean
' Return true if strIn is in valid e-mail format.
Return Regex.IsMatch(strIn, ("^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$")
End Function
[C#]
bool IsValidEmail(string strIn)
{
// Return true if strIn is in valid e-mail format.
return Regex.IsMatch(strIn, @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$");
}
2.清理輸入字符串
下面的代碼示例使用靜態(tài) Regex.Replace 方法從字符串中抽出無效字符。您可以使用這里定義的 CleanInput 方法,清除掉在接受用戶輸入的窗體的文本字段中輸入的可能有害的字符。CleanInput 在清除掉除 @、-(連字符)和 .(句點)以外的所有非字母數(shù)字字符后返回一個字符串。
[Visual Basic]
Function CleanInput(strIn As String) As String
' Replace invalid characters with empty strings.
Return Regex.Replace(strIn, "[^\w\.@-]", "")
End Function
[C#]
String CleanInput(string strIn)
{
// Replace invalid characters with empty strings.
return Regex.Replace(strIn, @"[^\w\.@-]", "");
}
3.更改日期格式
以下代碼示例使用 Regex.Replace 方法來用 dd-mm-yy 的日期形式代替 mm/dd/yy 的日期形式。
[Visual Basic]
Function MDYToDMY(input As String) As String
Return Regex.Replace(input, _
"\b(?<month>\d{1,2})/(?<day>\d{1,2})/(?<year>\d{2,4})\b", _
"${day}-${month}-${year}")
End Function
[C#]
String MDYToDMY(String input)
{
return Regex.Replace(input,
"\\b(?<month>\\d{1,2})/(?<day>\\d{1,2})/(?<year>\\d{2,4})\\b",
"${day}-${month}-${year}");
}
Regex 替換模式
本示例說明如何在 Regex.Replace 的替換模式中使用命名的反向引用。其中,替換表達式 ${day} 插入由 (?<day>...) 組捕獲的子字符串。
有幾種靜態(tài)函數(shù)使您可以在使用正則表達式操作時無需創(chuàng)建顯式正則表達式對象,而 Regex.Replace 函數(shù)正是其中之一。如果您不想保留編譯的正則表達式,這將給您帶來方便
4.提取 URL 信息
以下代碼示例使用 Match.Result 來從 URL 提取協(xié)議和端口號。例如,"http://www.contoso.com:8080/letters/readme.html"將返回"http:8080"。
[Visual Basic]
Function Extension(url As String) As String
Dim r As New Regex("^(?<proto>\w+)://[^/]+?(?<port>:\d+)?/", _
RegexOptions.Compiled)
Return r.Match(url).Result("${proto}${port}")
End Function
[C#]
String Extension(String url)
{
Regex r = new Regex(@"^(?<proto>\w+)://[^/]+?(?<port>:\d+)?/",
RegexOptions.Compiled);
return r.Match(url).Result("${proto}${port}");
}
普通字符由所有那些未顯式指定為元字符的打印和非打印字符組成。這包括所有的大寫和小寫字母字符,所有數(shù)字,所有標點符號以及一些符號。
最簡單的正則表達式是一個單獨的普通字符,可以匹配所搜索字符串中的該字符本身。例如,單字符模式 'A' 可以匹配所搜索字符串中任何位置出現(xiàn)的字母 'A'。這里有一些單字符正則表達式模式的示例:
/a/ /7/ /M/
等價的 VBScript 單字符正則表達式為:
"a" "7" "M"
可以將多個單字符組合在一起得到一個較大的表達式。例如,下面的 JScript 正則表達式不是別的,就是通過組合單字符表達式 'a'、'7'以及 'M' 所創(chuàng)建出來的一個表達式。
/a7M/
等價的 VBScript 表達式為:
"a7M"
請注意這里沒有連接操作符。所需要做的就是將一個字符放在了另一個字符后面。
有不少元字符在試圖對其進行匹配時需要進行特殊的處理。要匹配這些特殊字符,必須首先將這些字符轉(zhuǎn)義,也就是在前面使用一個反斜杠 (\)。下表給出了這些特殊字符及其含義:
特殊字符 | 說明 |
---|---|
$ | 匹配輸入字符串的結(jié)尾位置。如果設(shè)置了 RegExp 對象的 Multiline 屬性,則 $ 也匹配 '\n' 或 '\r'。要匹配 $ 字符本身,請使用 \$。 |
( ) | 標記一個子表達式的開始和結(jié)束位置。子表達式可以獲取供以后使用。要匹配這些字符,請使用 \( 和 \)。 |
* | 匹配前面的子表達式零次或多次。要匹配 * 字符,請使用 \*。 |
+ | 匹配前面的子表達式一次或多次。要匹配 + 字符,請使用 \+。 |
. | 匹配除換行符 \n之外的任何單字符。要匹配 .,請使用 \。 |
[ | 標記一個中括號表達式的開始。要匹配 [,請使用 \[。 |
? | 匹配前面的子表達式零次或一次,或指明一個非貪婪限定符。要匹配 ? 字符,請使用 \?。 |
\ | 將下一個字符標記為或特殊字符、或原義字符、或后向引用、或八進制轉(zhuǎn)義符。例如, 'n' 匹配字符 'n'。'\n' 匹配換行符。序列 '\\' 匹配 "\",而 '\(' 則匹配 "("。 |
^ | 匹配輸入字符串的開始位置,除非在方括號表達式中使用,此時它表示不接受該字符集合。要匹配 ^ 字符本身,請使用 \^。 |
{ | 標記限定符表達式的開始。要匹配 {,請使用 \{。 |
| | 指明兩項之間的一個選擇。要匹配 |,請使用 \|。 |
有不少很有用的非打印字符,偶爾必須使用。下表顯示了用來表示這些非打印字符的轉(zhuǎn)義序列:
字符 | 含義 |
---|---|
\cx | 匹配由x指明的控制字符。例如, \cM 匹配一個 Control-M 或回車符。 x 的值必須為 A-Z 或 a-z 之一。否則,將 c 視為一個原義的 'c' 字符。 |
\f | 匹配一個換頁符。等價于 \x0c 和 \cL。 |
\n | 匹配一個換行符。等價于 \x0a 和 \cJ。 |
\r | 匹配一個回車符。等價于 \x0d 和 \cM。 |
\s | 匹配任何空白字符,包括空格、制表符、換頁符等等。等價于 [ \f\n\r\t\v]。 |
\S | 匹配任何非空白字符。等價于 [^ \f\n\r\t\v]。 |
\t | 匹配一個制表符。等價于 \x09 和 \cI。 |
\v | 匹配一個垂直制表符。等價于 \x0b 和 \cK。 |
句點 (.) 匹配一個字符串中任何單個的打印或非打印字符,除了換行符 (\n) 之外。下面的 JScript 正則表達式可以匹配 'aac'、'abc'、'acc'、'adc'如此等等,同樣也可以匹配 'a1c'、'a2c'、a-c'以及 a#c':
/a.c/
等價的 VBScript 正則表達式為:
"a.c"
如果試圖匹配一個包含文件名的字符串,其中句點 (.) 是輸入字符串的一部分,則可以在正則表達式中的句點前面加上一個反斜杠 (\) 字符來實現(xiàn)這一要求。舉例來說,下面的 JScript 正則表達式就能匹配 'filename.ext':
/filename\.ext/
對 VBScript 而言,等價的表達式如下所示:
"filename\.ext"
這些表達式仍然是相當有限的。它們只允許匹配任何單字符。很多情況下,對從列表中匹配特殊字符十分有用。例如,如果輸入文字中包含用數(shù)字表示為Chapter 1, Chapter 2諸如此類的章節(jié)標題,你可能需要找到這些章節(jié)標題。
可以在一個方括號 ([ 和 ]) 中放入一個或多個單字符,來創(chuàng)建一個待匹配的列表。如果字符被放入括號中括起來,則該列表稱為括號表達式。括號內(nèi)和其他任何地方一樣,普通字符代表其本身,也就是說,它們匹配輸入文字中出現(xiàn)的一處自己。大多數(shù)特殊字符在位于括號表達式中時都將失去其含義。這里有一些例外:
括號表達式中所包含的字符只匹配該括號表達式在正則表達式中所處位置的一個單字符。下面的 JScript 正則表達式可以匹配 'Chapter 1'、'Chapter 2'、'Chapter 3'、'Chapter 4' 以及 'Chapter 5':
/Chapter [12345]/
在 VBScript 中要匹配同樣的章節(jié)標題,請使用下面的表達式:
"Chapter [12345]"
請注意單詞 'Chapter' 及后面的空格與括號內(nèi)的字符的位置關(guān)系是固定的。因此,括號表達式只用來指定滿足緊跟在單詞 'Chapter' 和一個空格之后的單字符位置的字符集合。這里是第九個字符位置。
如果希望使用范圍而不是字符本身來表示待匹配的字符,則可以使用連字符將該范圍的開始和結(jié)束字符分開。每個字符的字符值將決定其在一個范圍內(nèi)的相對順序。下面的 JScript 正則表達式包含了一個等價于上面所示的括號列表的范圍表達式。
/Chapter [1-5]/
VBScipt 中相同功能的表達式如下所示:
"Chapter [1-5]"
如果以這種方式指定范圍,則開始和結(jié)束值都包括在該范圍內(nèi)。有一點特別需要注意的是,在 Unicode 排序中起始值一定要在結(jié)束值之前。
如果想在括號表達式中包括連字符,則必須使用下述方法之一:
[\-]
[-a-z] [a-z-]
[!--] [!-~]
同樣,通過在列表開始處放置一個插入符(^),就可以查找所有不在列表或范圍中的字符。如果該插入符出現(xiàn)在列表的其他位置,則匹配其本身,沒有任何特殊含義。下面的 JScript 正則表達式匹配章節(jié)號大于 5 的章節(jié)標題:
/Chapter [^12345]/
對 VBScript 則使用:
"Chapter [^12345]"
在上面所示的示例中,表達式將匹配第九個位置處除1, 2, 3, 4, or 5 之外的任何數(shù)字字符。因此, 'Chapter 7' 為一個匹配,同樣 'Chapter 9' 也是如此。
上面的表達式可以使用連字符 (-) 表示。對 JScript 為:
/Chapter [^1-5]/
或者,對 VBScript 為:
"Chapter [^1-5]"
括號表達式的典型用法是指定對任何大寫或小寫字母字符或任何數(shù)字的匹配。下面的 JScript 表達式給出了這一匹配:
/[A-Za-z0-9]/
等價的 VBScript 表達式為:
"[A-Za-z0-9]"
推薦:
Hibernate中文手冊》作者認為要學Hibernate看這個就足夠了,里面幾乎包括了所有的細節(jié),不過可能不太適合快速入門。
地址:http://www.hibernate.org/hib_docs/v3/reference/zh-%20cn/html_single/
關(guān)于struts的資料就很多了,這里推薦一個可以下載一些入門教程的網(wǎng)站。
地址:http://www.wnetw.com/jclub/index.jsp
強烈建議入門的朋友先了解一下基本的原理!否則本文可能對你沒有任何幫助。
相關(guān)工具下載:(注意版本)
mysql5.0 http://www.mysql.org/
eclipse 3.1.1 http://www.eclipse.org/
myeclipse4.0.3 http://www.myeclipseide.com/
tomcat5.5
安裝:
關(guān)于tomcat和mysql的安裝就不多說了,需要注意的是最好保證你的 jdk是1.5的版本,并配置好你的環(huán)境變量,不然可能會遇到一些問題。
把eclipse解開,再去安裝剛下載的myeclipse,在安裝的時候需要把路徑指定到剛才解開的eclipse上,由于myeclipse是個收費軟件,所以需要注冊。不過一般按照Chinese的習慣,去google一個注冊碼就可以了:}
開發(fā)環(huán)境部署:
好了,現(xiàn)在保證你的mysql和tomcat服務(wù)能夠正常啟動,myeclipse能夠正常打開(如果不能,可以去找一下相關(guān)的說明或者給作者留言)。下面我們就要開始真正的開始部署一個傳說中的tomcat+struts+hibernate+mysql結(jié)構(gòu)的工程了!(faint!前言就寫的我好累)
首先,在myeclipse里新建一個工程。在左邊的Package Exporler面版里點右鍵選擇new->project…
在跳出菜單里選擇MyEclipse->J2EE Projects->Web Project。
點擊next后進入如下畫面:
工程名為:test
結(jié)束后點擊Finish。
好了,如果成功的話你就會在 Package Exporler里看到一個新的test工程!現(xiàn)在我們先配置一下數(shù)據(jù)庫方面的東西。首先在你的mysql 里建立一個數(shù)據(jù)庫webases,再在里面新建一個表admin,里面三個字段分別為id,name,password其中id為自動取值的主鍵(mysql具體的操作可以自己找資料,不是本文涉及范圍)。
再回到myeclipse ,選中window->Open Perspective->Other…
可以看到現(xiàn)在跳出一個名為Select Perspective的菜單,在里面選中MyEclipse Databases Exporler,可以看到現(xiàn)在到了下面的頁面。
按以上圖示輸入相關(guān)字段后點擊Finish便建立了一個數(shù)據(jù)庫連接,在新出現(xiàn)的JDBC for Mysql上點右鍵,選擇Open connection…,確認用戶名和密碼正確后點OK,如果一切順利的話你會看到下面的畫面:
這說明你已經(jīng)和數(shù)據(jù)庫建立了正確的連接?,F(xiàn)在我們再回到window->Open Perspective- >Other…里的MyEclipse,也就是我們剛進來的時候看到的畫面。
右鍵點擊你剛建立的工程 test并選擇MyEclipse->Add struts Capabilities…在跳出的菜單里按照如下輸入并確定:
好了,現(xiàn)在你已經(jīng)為你的工程增加了struts,接下來和上面一樣在右鍵工程后選擇MyEclipse- >Add Hibernate Capabilities…一路確定下來為你的工程添加Hibernate。(為方便起見我們在選擇路徑時把HibernateSessionFactory.java放在了src/com下面,其實最好建立個單獨的目錄如 src/com/hibernate)
為了更好的演示我們不建立通常的登陸頁面而是建立個注冊頁面。選擇 src目錄下的hibernate.cfg.xml文件。照如下填寫并保存。這樣hibernate就為你建立了數(shù)據(jù)庫的連接池。
下面我們再選擇WebRoot/WEB-INF/struts-config.xml文件,在畫面中點擊右鍵選擇new- >Form, Action and JSP。如下填寫
再選擇JSP選項,如下
最后選擇Finish。
再新建一個一個success.jsp的頁面,
在剛才struts- config.xml文件里右鍵選擇addAdmin選擇Properties,在菜單里選擇Forwords,再點add,如下圖填寫
最后你的struts-config.xml就是下面這個樣子:
下面我們轉(zhuǎn)到hibernate。換到剛才我們建立數(shù)據(jù)庫的頁面,選擇你的admin的表點右鍵選擇Create Hibernate Mapping。選擇好打包路徑后選擇Finish。如圖:
在你剛才選擇的路徑下(我為方便是src/com/yourcompanyname/)下新建立的文件 AdminDAOFactory.java文件并輸入以下內(nèi)容:
package com.yourcompanyname;
import java.util.Iterator;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.hibernate.SessionFactory;
public class AdminDAOFactory {
Session session;
Transaction tx;
public void add(Admin admin) throws HibernateException {
/**
* Creation Date: 11-17-2005
* TODO Add a new admin user.
* @param An object of Admin
* @return void
* @author Coder Guo
*/
try {
session = SessionFactory.currentSession();
tx = session.beginTransaction();
//Add a new admin
session.save(admin);
tx.commit ();
}catch(HibernateException e){
throw e;
}finally{
if (tx!=null) {
tx.rollback();
}
SessionFactory.closeSession();
}
}
}
再打開com.yourcompany.struts.action下的AddAdminAction.java添加(其中如果有錯誤選中好按ctrl+shift+o自動添加包)
public class AddAdminAction extends Action {
// --------------------------------------------------------- Instance Variables
// --------------------------------------------------------- Methods
/**
* Method execute
* @param mapping
* @param form
* @param request
* @param response
* @return ActionForward
* @author Coder Guo
*/
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
AddAdminForm addAdminForm = (AddAdminForm) form;
// TODO Add a new admin
Admin admin = new Admin();
admin.setName(addAdminForm.getName ());
admin.setPassword(addAdminForm.getPassword ());
AdminDAOFactory adminDAO = new AdminDAOFactory ();
adminDAO.add(admin);
return mapping.findForward("success");
}
}
再打開com.yourcompanyname.struts.form下的AddAdminForm.java,修改(如果有錯誤按照上面說的方法導入包)
public ActionErrors validate(
ActionMapping mapping,
HttpServletRequest request) {
// TODO Auto-generated method stub
ActionErrors errors = new ActionErrors();
Session session = SessionFactory.currentSession();
Transaction tx = session.beginTransaction ();
Query query = session.createQuery("select admin from Admin as admin where admin.name = '" + this.name + "'");
Iterator it = query.iterate ();
if (it.hasNext()){
errors.add ("addAdmin.err.name",new ActionMessage("form.addAdmin.err.name"));
}
tx.commit();
SessionFactory.closeSession ();
return errors;
}
public void reset(ActionMapping mapping, HttpServletRequest request) {
// TODO Auto-generated method stub
this.name=null;
this.password=null;
}
再打開com\yourcompanyname\struts下的ApplicationResource.properties在這里面添加錯誤信息:
Form.addAdmin.err.name=err
最后,(汗,好累啊-_-!)打開addAdmin.jsp修改成如下: <script language = "javascript"> <body> </html:html> 在項目文件點右鍵->"myeclipse"->"Add and remove project deployment",如下圖: 好了,我們的配置工作基本結(jié)束了,在myeclipse上開啟tomcat服務(wù) 現(xiàn)在打開瀏覽器,輸入
<%@ page contentType="text/html; charset=utf-8"%>
<%@ page language="java"%>
<%@ taglib uri="<%@ taglib uri="
<!--
function check(){
if (loginForm.userName.value == "" || loginForm.password.value == ""){
alert("請輸入完整的信息!");
loginForm.userName.focus();
return false;
}
}
//-->
</script>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html:html>
<head>
<html:base />
<title>login.jsp</title>
<link href="css/webcss.css" rel="stylesheet" type="text/css">
<meta http-equiv="pragma" content="no- cache">
<meta http-equiv="cache-control" content="no- cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http- equiv="description" content="This is my page">
</head>
<center>
<p> </p>
<p> </p>
<table width="300" border="0" cellpadding="0" cellspacing="0">
<html:form action="/addAdmin" focus="name" method="GET">
<tr align="center" valign="middle">
<td colspan="2" class="typt_normal">新增管理員</td>
</tr>
<tr>
<td width="100" align="center" valign="middle" class="typt_normal">名稱: </td>
<td width="200" align="left"><html:text property="name" styleClass="text_s"/><html:errors property="addAdmin.err.name"/></td>
</tr>
<tr>
<td width="100" align="center" valign="middle" class="typt_normal">密碼: </td>
<td width="200" align="left"><html:password property="password" styleClass="text_s"/></td>
</tr>
<tr>
<td colspan="2" align="center" valign="middle"><html:submit value="提交" onclick="return check ();"/><html:reset value="重置"></html:reset></td>
</tr>
</html:form>
</table>
</center>
</body>
其中可以看到如何在struts的標簽中使用javascript的方法。
配置好myeclipse于tomcat的連接。在window->Preferences做如下設(shè)定:
http://127.0.0.1:8080/test/addAdmin.jsp就可以看到你的jsp頁面了!
]]>
一、前言
J2EE和.NET是目前企業(yè)級運用的兩大陣營,誰優(yōu)誰劣各有說法。筆者是做J2EE方向的,覺得J2EE比起.NET最大的優(yōu)勢就是其經(jīng)過長實踐發(fā)展總結(jié)出來的大量模式和大量先進的框架。這些框架許多都是開源的——開源也是J2EE陣營的另一優(yōu)勢。本篇文章的主角就是目前J2EE web應用中最流行的兩大開源框架——Hibernate和Struts。
二、相關(guān)概念與工具介紹
下面我將分別對本文“三大主角”所涉及到相關(guān)概念進行說明。
Hibernate及相關(guān)知識介紹
Hibernate:
中文意思是"冬眠“,呵呵,不知道設(shè)計者為何用這個名字。它是一個開源的ORM框架(關(guān)于ORM下文還會講解),它是通過對JDBC API進行封裝從而實現(xiàn)對java對象持久化的。有人可能要問:JDBC其實不難操作,為什么還要封裝它哪?其實答案很簡單,因為現(xiàn)在通用的數(shù)據(jù)庫都是關(guān)系數(shù)據(jù)庫,我們通過JDBC操作無法做到OOP,所以Hibernate將JDBC封裝起來,并且提供了一套OO化的Hibernate API供頂層操作。Hibernate現(xiàn)在幾乎已經(jīng)成為ORM的公認標準了(剛推出的EJB 3.0標準中使用的ORM事實上就是Hibernate)
ORM:
這里解釋下ORM。ORM是一種模式(關(guān)于模式,筆者之前在這里發(fā)表過一篇介紹工廠模式的文章,讀者可以看看),它的英文是Object-Relation Mapping,中譯為對象-關(guān)系映射,它指的是“在單個組建中負責所有實體域?qū)ο蟮某志没?,封裝數(shù)據(jù)訪問細節(jié)”(注:此定義來自《精通Hibernate:java對象持久化技術(shù)詳解》,孫衛(wèi)琴,電子工業(yè)出版社)。筆者的覺得很容易理解:把關(guān)系數(shù)據(jù)庫對象化。
Struts及相關(guān)知識介紹
Struts:
Struts是由著名的Apache基金會開發(fā)的開源項目。中譯為“框架”,顧名思義,它就是一種MVC框架。眾所周知,MVC是一種業(yè)務(wù)邏輯與表示分離的模式,在java web上的應用十分廣泛。以前MVC的主要表現(xiàn)形式是JSP Model2,也就是JSP+Servlet+Javabean的應用,而近年來Struts的應用越來越廣泛,目前已經(jīng)是最流行的MVC框架了。
MVC:
Model-View-Controller,中譯為模型-視圖-控制器。MVC不是真正意義上的軟件設(shè)計模式,而更是一種解決方案,它把軟件系統(tǒng)的所有業(yè)務(wù)邏輯方面的編程交給了Model,把所有UI視圖的設(shè)計和編程交給了View,再用Controller控制器控制Model并生成相應的View,從而真正實現(xiàn)了業(yè)務(wù)邏輯與用戶界面的分離。
Eclipse介紹
Eclipse是由IBM公司開發(fā)出來,后來又免費捐獻出來的開源工具,是一套主要用于Java開發(fā)的IDE(Eclipse通過添加某些插件可以實現(xiàn)對UML、C++等的開發(fā))。Eclipse具有強大的擴展功能,加上其開源的特性,導致許多愛好者和公司為其開發(fā)了非常優(yōu)秀的插件,Myeclipse就是其中之一。Myeclipse是面向J2EE開發(fā)者的Eclipse插件,功能強大,好用。本文的實例就是基于Eclipse+Myeclipse環(huán)境下開發(fā)出來的。
創(chuàng)建/運行本文實例除了安裝以上工具和插件外還需要安裝一個Web容器,本文使用的是Jboss,筆者可以自行選擇使用Tomcat或Weblogic等,這些對運行本文實例影響不大。
本文選擇的數(shù)據(jù)庫是SQLServer2000,關(guān)于Mysql、Oracle等其他數(shù)據(jù)庫的操作方法類似。
關(guān)于Eclipse下載和安裝方法本文不做介紹,請讀者自行在網(wǎng)上查找相關(guān)方法。
三、實例需求與總體設(shè)計
1、需求定義
由于本文的目的是介紹在Eclipse IDE下開發(fā)Struts+Hibernate的具體方法,而不是介紹項目開發(fā)/軟件設(shè)計的技巧,所以本文實例需求非常簡單。
本文實例是一個web留言簿,可以讓匿名用戶發(fā)表一些留言信息,并保存至數(shù)據(jù)庫。做過web開發(fā)的朋友肯定做過這類實例,非常經(jīng)典。由于實例簡單并且容易理解,所以筆者也省去畫用例圖說明的步驟。
2、總體設(shè)計
本實例按傳統(tǒng)J2EE web項目的設(shè)計方法,分為5層架構(gòu),自底向上分別是:數(shù)據(jù)庫層 -> ORM層(Hibernate層) -> 業(yè)務(wù)邏輯層 -> 控制層(Struts Action) -> 視圖表示層。
數(shù)據(jù)庫的DDL語句如下:
四、持久化層與業(yè)務(wù)層實踐(Hibernate實踐)
好,戲肉開始。
1、先打開Eclipse。點擊“新建項目”->“Web Project”,出現(xiàn)如下窗口,在窗口中Project Name填入“Memo”作為項目名:
?
2、點擊“窗口”->“打開透視圖”->“其他”,出現(xiàn)如下窗口,雙擊“Myeclipse Database Explorer”,切換到如下視圖:
3、在“DB Browser”控制面板點擊“new”,新建一個數(shù)據(jù)庫連接。在彈出的窗口中點擊“new driver”新建一個數(shù)據(jù)庫連接驅(qū)動。如下圖:
4、上一步后回到以下視圖,在列表中選擇上一步創(chuàng)建的驅(qū)動,填入相關(guān)數(shù)據(jù)庫資料,點擊確定即可。(此步驟前必須已經(jīng)打開數(shù)據(jù)庫,最后已經(jīng)按照本實例的DDL創(chuàng)建了庫和表)
5、完成上一步后出現(xiàn)以下視圖。點擊“memo”的右鍵,點擊“open connetion”->“確定”。如果上述步驟成功的話這里會連接到數(shù)據(jù)庫,并顯示相關(guān)的數(shù)據(jù)庫結(jié)構(gòu)。
成功后如下圖:
6、點擊“窗口”->“打開透視圖”->“其他”->“Myeclipse”切換到項目控制視圖。在項目名上點擊右鍵->“myeclipse”->“Add Hibernate capabilites”,出現(xiàn)以下視圖,并按下圖填入相關(guān)信息:
點下一步后出現(xiàn)如下框圖,按圖片上內(nèi)容填寫:
提交后出現(xiàn)以下視圖,按圖片內(nèi)容填寫:
7、在項目名上點擊右鍵->“myeclipse”->“Add Struts capabilites”,出現(xiàn)下面視圖,按圖中內(nèi)容天下:
8、點擊“窗口”->“打開透視圖”->“其他”,出現(xiàn)如下窗口,雙擊“Myeclipse Database Explorer”,切換到數(shù)據(jù)庫管理視圖,找到我們?yōu)楸敬螌嵗齽?chuàng)建的表格,點右鍵->“create hibernate mapping”后出現(xiàn)下圖,按圖上內(nèi)容填寫:
9、至此Hibernate的創(chuàng)建工作已經(jīng)完成,如下圖,接下來我們寫個DAO工廠類來操作Hibernate API。
點擊com.woden包,新建個類,如下圖:
輸入以下代碼:
以上只有一個插入方法,如果讀者需要更多方法可以在DAO中自行添加。
至此,數(shù)據(jù)庫層、ORM層和業(yè)務(wù)層的代碼已經(jīng)完成。
五、控制層與表示層實踐(Struts實踐)
1、新建一個welcome.jsp文件,作為實例的首頁。具體方法是在“webroot”文件夾圖標點右鍵->new->“jsp”,接下來填寫的東西很簡單就不用介紹了吧。
2、在上一步驟的第7步中已經(jīng)在myeclipse中導入了struts,我們下面就可以開始編輯設(shè)置我們的struts實例。打開webboot目錄下WEB-INF中的struts配置文件“struts-config.xml”,如下圖:
3、在屏幕空白處點右鍵->“new”->“new form,action and jsp”,會出現(xiàn)如下視圖,按下圖提示填寫內(nèi)容:
這里記得點擊“jsp”標簽條,出現(xiàn)以下界面,按下圖設(shè)置:
4、上一步驟設(shè)置了form,點擊下一步看到如下視圖,按下圖設(shè)置,具體步驟是:點擊“foward”標簽->“add”->name填“success”,path選擇“welcome.jsp”,其他不用填->確定。
5、上一步驟點擊了“完成”后出現(xiàn)下圖:
6、這一步驟是設(shè)置資源文件,為了struts的國際化和錯誤提示做準備。找到項目文件夾中src(源文件夾),找到ApplicationResourse.properties,雙擊打開,如下圖所示配置:(注:這里筆者安裝了一個免費的ascii轉(zhuǎn)unicode的插件)
如果讀者沒有安裝ascii自動轉(zhuǎn)unicode組建,可以直接copy我轉(zhuǎn)換后的資源文件內(nèi)容:
7、下面打開com.woden.form.MemoForm.java文件,輸入以下代碼:
8、上面已經(jīng)寫出了ActionForm的代碼,具體代碼筆者在這里不解釋,我想看過struts基礎(chǔ)的朋友都應該很清楚了,下面貼處Action的代碼:
9、最后編輯下幾個相關(guān)jsp文件的內(nèi)容,分別如下:
至此,本實例完成。
六、發(fā)布與運行
1、在項目文件點右鍵->“myeclipse”->“Add and remove project deployment”,如下圖:
2、點擊圖標,選擇“Jboss”->“start”(注:這里如果用的是tomcat也類似操作,關(guān)于服務(wù)器配置的方法這里不祥談,請讀者自行在網(wǎng)上查找相關(guān)資料),會發(fā)現(xiàn)控制臺會輸出類似如下信息:
打開瀏覽器,輸入:http://localhost:8080/ 后如果出現(xiàn)下圖證明啟動成功:
3、輸入網(wǎng)址:http://localhost:8080/Memo/addmemo.jsp ,會看到效果圖如下圖:
4、按照正常流程和非正常流程分別留言一次,呵呵,效果出來沒有?如果沒有出現(xiàn)預期效果請檢查前面步驟。
七、寫在最后
在本文最后,筆者再次強調(diào),本文的目的是介紹Eclipse IDE關(guān)于創(chuàng)建Struts+Hibernate應用的方法,而不是介紹j2ee框架的概念和運用,更不是介紹java設(shè)計與模式。本文對IDE的配置、服務(wù)器配置的方法也沒做詳細介紹,因為這都不是本文重點。對以上知識想了解多點的讀者可以google一下。
本文的實例只是一個入門,強調(diào)的是一種方法,而不是強調(diào)功能,所以本文的實例只有一個簡單的錄入功能。在看完本文后讀者可以添加更多的功能(我想,當這一架構(gòu)搭建起來后,添加功能已經(jīng)是相當容易的事情了)。
當一個代碼項目大了以后,每次重新編譯,打包,測試等都會變得非常復雜而且重復,因此c語言中有make腳本來幫助這些工作的批量完成。在Java中應用是平臺無關(guān)性的,當然不會用平臺相關(guān)的make腳本來完成這些批處理任務(wù)了,ANT本身就是這樣一個流程腳本引擎,用于自動化調(diào)用程序完成項目的編譯,打包,測試等。除了基于JAVA是平臺無關(guān)的外,腳本的格式是基于XML的,比make腳本來說還要好維護一些。
每個ant腳本(缺省叫build.xml)中設(shè)置了一系列任務(wù)(target):比如對于一個一般的項目可能需要有以下任務(wù)。
<project default="usage" basedir="."> <!-- =================================================================== --> <!-- Initialization target --> <!-- =================================================================== --> <target name="init"> <tstamp/> <property file="${basedir}/build.properties" /> <property name="Name" value="ProjectFullName"/> <property name="name" value="project_name"/> <property name="version" value="0.2"/> <property name="year" value="2003"/> <echo message="----------- ${Name} ${version} [${year}] ------------"/> <property name="debug" value="off"/> <property name="optimize" value="on"/> <property name="deprecation" value="on"/> <property name="src.dir" value="./src/WEB-INF/src"/> <property name="lib.dir" value="./src/WEB-INF/lib"/> <property name="packages" value="com.chedong.*,org.apache.lucene.*"/> <property name="build.src" value="./src/WEB-INF/build"/> <property name="build.dest" value="./src/WEB-INF/classes"/> <property name="build.javadocs" value="./src/doc"/> <path id="classpath"> <pathelement path="${jsdk_jar}"/> <fileset dir="${lib.dir}"> <include name="**/*.jar"/> </fileset> </path> <filter token="year" value="${year}"/> <filter token="version" value="${version}"/> <filter token="date" value="${TODAY}"/> <filter token="log" value="true"/> <filter token="verbose" value="true"/> </target> <!-- =================================================================== --> <!-- Help on usage --> <!-- =================================================================== --> <target name="usage" depends="init"> <echo message="${Name} Build file"/> <echo message="-------------------------------------------------------------"/> <echo message=""/> <echo message=" available targets are:"/> <echo message=""/> <echo message=" jar --> generates the ${name}.jar file"/> <echo message=" build --> compiles the source code"/> <echo message=" javadoc --> generates the API documentation"/> <echo message=" clean --> cleans up the directory"/> <echo message=""/> <echo message=" Please rename build.properties.default to build.properties"/> <echo message=" and edit build.properties to specify JSDK 2.3 classpath."/> <echo message=""/> <echo message=" See the comments inside the build.xml file for more details."/> <echo message="-------------------------------------------------------------"/> <echo message=""/> <echo message=""/> </target> <!-- =================================================================== --> <!-- Prepares the source code --> <!-- =================================================================== --> <target name="prepare-src" depends="init"> <!-- create directories --> <mkdir dir="${build.src}"/> <mkdir dir="${build.dest}"/> <!-- copy src files --> <copy todir="${build.src}"> <fileset dir="${src.dir}"/> </copy> </target> <!-- =================================================================== --> <!-- Compiles the source directory --> <!-- =================================================================== --> <target name="build" depends="prepare-src"> <javac srcdir="${build.src}" destdir="${build.dest}" debug="${debug}" optimize="${optimize}"> <classpath refid="classpath"/> </javac> </target> <!-- =================================================================== --> <!-- Creates the class package --> <!-- =================================================================== --> <target name="jar" depends="build"> <jar jarfile="${lib.dir}/${name}.jar" basedir="${build.dest}" includes="**"/> </target> <!-- =================================================================== --> <!-- Creates the API documentation --> <!-- =================================================================== --> <target name="javadoc" depends="build"> <mkdir dir="${build.javadocs}"/> <javadoc packagenames="${packages}" sourcepath="${build.src}" destdir="${build.javadocs}" author="true" version="true" use="true" splitindex="true" windowtitle="${Name} API" doctitle="${Name}"> <classpath refid="classpath"/> </javadoc> </target> <!-- =================================================================== --> <!-- Clean targets --> <!-- =================================================================== --> <target name="clean" depends="init"> <delete dir="${build.src}"/> <delete dir="${build.dest}/org"/> <delete dir="${build.dest}/com"/> <delete> <fileset dir="${build.dest}" includes="**/*.class"/> </delete> </target> </project> <!-- End of file --> |
缺省任務(wù):usage 打印幫助文檔,告訴有那些任務(wù)選項:可用的有build, jar, javadoc和clean.
初始化環(huán)境變量:init
所有任務(wù)都基于一些基本環(huán)境變量的設(shè)置初始化完成,是后續(xù)其他任務(wù)的基礎(chǔ),在環(huán)境初始化過程中,有2點比較可以方便設(shè)置:
1 除了使用卻缺省的property設(shè)置了JAVA源路徑和輸出路徑外,引用了一個外部的build.properties文件中的設(shè)置,
<property file="${basedir}/build.properties" />
這樣大部分簡單配置用戶只要會看懂build.properties就可以了,畢竟XML比起key value的屬性文件還是要可讀性差一些。用build.properties也可以方便其他用戶從編譯的細節(jié)中解放出來。
2 CLASSPATH設(shè)置:使用了其中的:
<path id="classpath"> <pathelement path="${jsdk_jar}"/> <fileset dir="${lib.dir}"> <include name="**/*.jar"/> </fileset> </path> |
則相當于設(shè)置了:CLASSPATH=/path/to/resin/lib/jsdk23.jar;/path/to/project/lib/*.jar;
文件復制:prepare-src
創(chuàng)建臨時SRC存放目錄和輸出目錄。
<!-- =================================================================== --> <!-- Prepares the source code --> <!-- =================================================================== --> <target name="prepare-src" depends="init"> <!-- create directories --> <mkdir dir="${build.src}"/> <mkdir dir="${build.dest}"/> <!-- copy src files --> <copy todir="${build.src}"> <fileset dir="${src.dir}"/> </copy> </target> |
編譯任務(wù):build
編譯時的CLASSPATH環(huán)境通過一下方式找到引用一個path對象
<classpath refid="classpath"/> |
打包任務(wù):jar
對應用打包生成項目所寫名的.jar文件
<!-- =================================================================== --> <!-- Creates the class package --> <!-- =================================================================== --> <target name="jar" depends="build"> <jar jarfile="${lib.dir}/${name}.jar" basedir="${build.dest}" includes="**"/> </target> 生成JAVADOC文檔任務(wù): javadoc <!-- =================================================================== --> <!-- Creates the API documentation --> <!-- =================================================================== --> <target name="javadoc" depends="build"> <mkdir dir="${build.javadocs}"/> <javadoc packagenames="${packages}" sourcepath="${build.src}" destdir="${build.javadocs}" author="true" version="true" use="true" splitindex="true" windowtitle="${Name} API" doctitle="${Name}"> <classpath refid="classpath"/> </javadoc> </target> 清空臨時編譯文件:clean <!-- =================================================================== --> <!-- Clean targets --> <!-- =================================================================== --> <target name="clean" depends="init"> <delete dir="${build.src}"/> <delete dir="${build.dest}/org"/> <delete dir="${build.dest}/com"/> <delete> <fileset dir="${build.dest}" includes="**/*.class"/> </delete> </target> |
TODO:
更多任務(wù)/擴展:(樣例)
public interface UserDAO {
public abstract boolean isValidUser(String username, String password);
}
UserDAOImp.java
import java.util.List;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import com.test.Hibernate.SessionFactory;
public class UserDAOImp extends HibernateDaoSupport implements UserDAO {
private SessionFactory sessionFactory;
private static String hql = "from User u where u.username=? ";
public boolean isValidUser(String username, String password) {
List userList = this.getHibernateTemplate().find(hql, username);
if (userList.size() > 0) {
return true;
}
return false;
}
}
修改LoginAction.java文件,使用userDao的方法來進行用戶驗證
package com.test.struts.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.validator.DynaValidatorForm;
import com.test.UserDAO;
public class LoginAction extends Action {
private UserDAO userDAO;
public UserDAO getUserDAO() {
return userDAO;
}
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
DynaValidatorForm loginForm = (DynaValidatorForm) form;
// TODO Auto-generated method stub
String username = (String) loginForm.get("username");
String password = (String) loginForm.get("password");
loginForm.set("password", null);
if (userDAO.isValidUser(username,password)) {
return mapping.findForward("indexGo");
} else {
return mapping.getInputForward();
}
}
}
綠色字體為修改部份
現(xiàn)在剩下最后的spring配置了
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost/test</value>
</property>
<property name="username">
<value>root</value>
</property>
<property name="password">
<value>root</value>
</property>
</bean>
<!-- 配置sessionFactory, 注意這里引入的包的不同 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref local="dataSource" />
</property>
<property name="mappingResources">
<list>
<value>com/test/Hibernate/User.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="userDAO" class="com.test.UserDAOImp">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="userDAOProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="target">
<ref local="userDAO" />
</property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="is*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
<bean name="/login" class="com.test.struts.action.LoginAction" singleton="false">
<property name="userDAO">
<ref bean="userDAOProxy" />
</property>
</bean>
</beans>
現(xiàn)在可以進行測試了!
在編寫代碼有配置內(nèi)容時一定要注意 hibernate 和 hibernate3 ,這兩個包的名字就只差一個字,千萬不要有錯,否則找錯誤可是很難的。