PS.只針對社招人員
若您或您的朋友有這方面的意向,請提供簡歷到:yaominxi@huawei.com
Hibernate入門 - 基礎配置 | ||
thinking_org 原創 更新: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會轉化為1插入數據庫,當你在Hibernate里面輸入false的時候,Hibernate會轉化為0插入數據庫,后面的Y,N同理。 對于某些數據庫,例如Oracle來說,沒有boolean數據類型,就是采用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數據庫的例子,很直觀,不必解釋,不同的數據庫的連接參數模板中全部給出了。 hibernate.connection.pool_size 1 hibernate.statement_cache.size 25 這是Hibernate自帶的連接池的配置參數,在默認情況下將采用。意義很直觀,不多解釋。 只是提醒一點,Hibernate這個連接池是非常原始非常簡單的連接池,如果你在項目中用Hibernate的話,建議你首選App Server的連接池,次選Hibernate帶的DBCP連接池。自帶的連接池應該做為末選。 如果你采用DBCP連接池,除了要配置DBCP連接池以外,還需要取消掉下行的注釋: hibernate.connection.provider_class net.sf.hibernate.connection.DBCPConnectionProvider 其它的連接池同理。 如果采用App Server的連接池,假設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 其它參數就不必寫了,因為已經在App Server配置連接池的時候指定好了。 如果你不是在App Server環境中使用Hibernate,例如遠程客戶端程序,但是你又想用App Server的數據庫連接池,那么你還需要配置JNDI的參數,例如Hibernate連接遠程Weblogic上的數據庫連接池: 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發送給數據庫的sql顯示出來,這是一個非常非常有用處的功能。當你在調試Hibernate的時候,讓Hibernate打印sql語句,可以幫助你迅速解決問題。 #hibernate.connection.isolation 4 指定數據庫的隔離級別,往往不同的數據庫有自己定義的隔離級別,未必是Hibernate的設置所能更改的,所以也不必去管它了。 hibernate.jdbc.fetch_size 50 hibernate.jdbc.batch_size 25 這兩個選項非常非常非常重要!!!將嚴重影響Hibernate的CRUD性能! C = create, R = read, U = update, D = delete Fetch Size 是設定JDBC的Statement讀取數據的時候每次從數據庫中取出的記錄條數。 例如一次查詢1萬條記錄,對于Oracle的JDBC驅動來說,是不會1次性把1萬條取出來的,而只會取出Fetch Size條數,當紀錄集遍歷完了這些記錄以后,再去數據庫取Fetch Size條數據。 因此大大節省了無謂的內存消耗。當然Fetch Size設的越大,讀數據庫的次數越少,速度越快;Fetch Size越小,讀數據庫的次數越多,速度越慢。 這有點像平時我們寫程序寫硬盤文件一樣,設立一個Buffer,每次寫入Buffer,等Buffer滿了以后,一次寫入硬盤,道理相同。 Oracle數據庫的JDBC驅動默認的Fetch Size=10,是一個非常保守的設定,根據我的測試,當Fetch Size=50的時候,性能會提升1倍之多,當Fetch Size=100,性能還能繼續提升20%,Fetch Size繼續增大,性能提升的就不顯著了。 因此我建議使用Oracle的一定要將Fetch Size設到50。 不過并不是所有的數據庫都支持Fetch Size特性,例如MySQL就不支持。 MySQL就像我上面說的那種最壞的情況,他總是一下就把1萬條記錄完全取出來,內存消耗會非常非常驚人!這個情況就沒有什么好辦法了 :( Batch Size是設定對數據庫進行批量刪除,批量更新和批量插入的時候的批次大小,有點相當于設置Buffer緩沖區大小的意思。 Batch Size越大,批量操作的向數據庫發送sql的次數越少,速度就越快。我做的一個測試結果是當Batch Size=0的時候,使用Hibernate對Oracle數據庫刪除1萬條記錄需要25秒,Batch Size = 50的時候,刪除僅僅需要5秒!!! 可見有多么大的性能提升!很多人做Hibernate和JDBC的插入性能測試會奇怪的發現Hibernate速度至少是JDBC的兩倍,就是因為Hibernate使用了Batch Insert,而他們寫的JDBC沒有使用Batch的緣故。 以我的經驗來看,Oracle數據庫 Batch Size = 30 的時候比較合適,50也不錯,性能會繼續提升,50以上,性能提升的非常微弱,反而消耗內存更加多,就沒有必要了。 #hibernate.jdbc.use_scrollable_resultset true 設定是否可以使用JDBC2.0規范的可滾動結果集,這對Hibernate的分頁顯示有一定的作用,默認就好了。 #hibernate.cglib.use_reflection_optimizer false 默認打開,啟用cglib反射優化。cglib是用來在Hibernate中動態生成PO字節碼的,打開優化可以加快字節碼構造的速度。 不過,當你在調試程序過程中,特別是和proxy,lazy loading相關的應用中,代碼出錯,但是出錯提示信息有語焉不詳,那么你可以把cglib優化關掉,這樣Hibernate會輸出比較詳細的調試信息,幫助你debug |
2004 年11月30日,世界各國科學家投入研究已有近四十年歷史的電子紙領域,又傳來了一個好消息。日本日立公司新近成功開發出了一種超薄的電子紙,這種紙張顯示尺寸為16.2厘米×18.1厘米,厚度僅有3毫米,樣品重量100克。與一般競爭對手開發的只能顯示兩色的電子紙不同,日立的該款產品,其液晶顯示器已經達到能同時顯示64色的水平。最令人驚訝的是,它可以直接貼在墻上,并且可以根據遙控器的指揮而隨意改變顯示的圖像和信息。日立公司稱,這款產品可以用于在墻上顯示各種內容,比如家庭照片、工作計劃表和菜譜等。 技術流派殊途同歸 所謂"電子紙"(Electronic Papers),其實就是一種外觀像紙或像投影片的新型的超薄平面監示器,在各種場合(尤其是戶外)的文字辨認性上,優于常規的LCD,且能夠與報紙相比擬。 "電子紙"概念興起于1980年代前后,彼時,一大批科學家開始投入此領域的研究,在當時研究者的理想中,該種紙張將可以逐漸代替傳統紙張,既便于文字閱讀,又可以改寫內容,反復使用。到了本世紀初,隨著技術研究呈現出若干可喜的回報,有人開始大膽預測,電子紙會在未來三五年內達到大規模應用階段,而10 年左右的時間,傳統平面媒體業將會因電子紙技術的普及而發生顛覆性的變革。 目前的電子紙大致可分液晶型以及非液晶型兩大類。液晶型產品多半是由LCD廠商所開發出,以不使用偏光片或彩色濾光片的方式降低監視器厚度,或是采用特殊的液晶材料及顯示方式達到目標。其中代表廠商是Fuji Xerox和大日本INK公司。而非液晶型領域較知名者為E-Ink公司的電子墨水(Electronic Ink)監視器,以及SONY的電解析出型電子監視器。 在電子紙的研制領域,成立于1997年的美國E-Ink公司的地位顯得首屈一指,這家隸屬于麻省理工學院的公司的電子超薄顯示器技術代表著目前業內的最高水準。公司最新的成果是一種應用于電子報紙、可穿戴式電腦屏幕、便攜信息終端屏幕、電子詞典、電子圖書和智慧型身份辨識卡的電子裝置。公司發言人表示:這是至今為止世界上最完美的電子紙張產品,只有0.3毫米厚,可以任意彎曲而不發生字面的扭曲;支持以無線的方式下載文本內容,如果必要的話,可以隨時進行閱讀內容的網絡刷新和內容改寫。 E-Ink公司所研發的電子紙張,表面看起來與普通紙張十分相似,可以像報紙一樣被折疊卷起,但實際上卻有天壤之別。它上面涂有一種由無數微小的透明顆粒組成的電子墨水,顆粒直徑只有人的頭發絲的一半大小。這種微小顆粒內包含著黑色的染料和一些更為微小的白色粒子,染料使包裹著它的透明顆粒呈黑色,那些更為微小的白色粒子能夠感應電荷而朝不同的方向運動,當它們集中向某一個方向運動時,就能使原本看起來呈黑色的顆粒的某一面變成白色。根據這一原理,當這種電子墨水被涂到紙、布或其他平面物體上后,人們只要適當地對它予以電擊,就能使數以億計的顆粒變幻顏色,從而根據人們的設定不斷地改變所顯現的圖案和文字,這便是電子墨水的神奇功效。當然,電子墨水的顏色并不局限于黑白兩色,只要調整顆粒內的染料和微型粒子的顏色,便能夠使電子墨水展現出五彩繽紛的色彩和圖案來。由于此種監視器具有記憶性,因此只有畫素顏色變化時(例如從黑轉到白)才耗電,關電源后顯示幕上畫面仍可保留,因此非常省電。2顆AA電池即可供數周以上長期使用。 而SONY的電子紙張發展,則以顯示靜態畫面為主,主要是利用銀(Ag)在電子化學反應過程中,在透明電極上析出,或于固態電解質中溶解的方式達到呈現黑與百的效果。 這一技術最主要的貢獻將在于提高電子紙的反射率。 雖然當前有許多廠商進行電子紙相關技術研發,發展方向亦相當分歧,但我們已經可以從中歸結出現代電子紙的產品特性:一為較輕、較薄,比當前通用TFT LCD、STN LCD模塊為薄。二為大多數具有資料保存性,只有畫面異動時(例如由黑轉到白)才耗電,電源關閉后信息仍可留存在監視器上,因此比TFT LCD、STN LCD更為省電。三為反射率高于反射式LCD,更接近報紙水平,有些廠商的產品甚至可達影印用紙水平(因此肉眼對其所顯示的文字內容更易辨識)。四為對比度優于一般報紙。五為初期以黑白方式顯示文字內容為主,較缺乏全彩或動畫功能,應答速度普遍較TFT LCD、STN LCD慢。六為部分電子紙監視器具可撓性或是可以卷曲。 蘊含巨大商機? 電子紙張屬于一種新興技術,各廠商皆在摸索之中,主要市場尚待確認。按照目前業界比較一致的觀點來說,接下來兩三年仍然屬于電子紙的技術成熟階段:更輕更薄,由單色到多色,由靜態到動態。其正式的市場起飛可能要等到2007年或更晚。屆時,信用卡、可貼附在衣服或公文包上、具PDA功能的電子紙張,可能是未來應用的發展方向。但初期應用主要還是以電子海報、超薄電子書為主。依照各廠商產品發展計劃,未來不但可以看到隨身攜帶的電子報紙、電子書、電子速記本外,電子紙張亦可能成為捷運、公車或一般商家的平面廣告載具。當前在上述場所見到的平面印刷廣告,將來有可能出現全新風貌。比如當你擁有一張報社發放的電子報紙閱讀器的話,那么每天的報紙內容將會以無線的方式發送到你的面前. 未來對電子紙需求有正面效益的一個觀察重點,是全球用紙量在近十年來激增,背后因素當然是信息量產出的爆炸,除報紙以外,各式各樣的雜志、宣傳海報以及計算機印出數量均有大幅增加情形。而需求數量龐大的傳統紙張對森林的威脅使環保人士感到憤怒。此一背景對于電子紙監視器有利,因為其有助于節約用紙量。但相應的問題也隨之而來,與報紙、雜志、海報等紙張類媒體相比,目前的電子紙因成本過高而缺乏長遠的競爭力。同時,大部分的電子紙還是不夠薄,反射率不夠高。另一方面,對于所有的顯示用電子紙來說,目前最致命的缺陷是無法表達足夠連貫的視頻畫面--市面上普通的LCD的最短畫面響應時間低于12ms,但即使如此,LCD仍然被指責為無法與CRT進行這方面的性能抗衡。而普通電子紙的畫面響應時間將超過100 ms。如果電子紙無法對動畫畫面的顯示有所突破,那么它被人們接受的可能就會受到極大限制。 諸如以上因素,因此雖然根據預測,2005年電子紙張潛在市場規模具有100億美元商機,不過因為相關技術不成熟,有待改善空間仍大,加上廠商生產成本下降速度以及產能是否能夠配合等多項問題,預估2005年實際市場規模只有預測的1/10左右。 幸而研究人員從未放棄過技術改善的腳步。今年3月,日本千葉大學已經開發出了厚度只有0.1毫米的電子紙產品,這是人類首次將電子紙真正在厚度上接近到了紙的范疇。而早在2002年上半,SONY已展示了一款比報紙反射率(約60%)更高的電子紙張,反射率達到73%,純白表現程度與影印紙相當,有助提高消費者觀看意愿。至于動態圖像的支持,九州大學與普利斯通的研究小組開發的使用粉狀墨的電子紙,相應速度目前為世界最高,已經到達0.2ms。 由此我們完全可以樂觀地推斷,隨著科學技術的不斷完善,電子紙時代也將很快到來。事實上,盡管目前普及顯得遙遠,但真實的應用的確已經出現--SONY的 LIBRIe、Adobe的在線書籍商店,都是電子紙技術初期應用的最好體現。今年4月末,SONY推出了一種被稱為LIBRIe的電子書產品。 LIBRIe的大小和一本普通的書差不多,但是作為一種電子產品,LIBRIe配備了USB和耳機接口,同時內置文字放大和字典查詢的功能。用戶可以憑借 LIBRIe提供的MS卡存儲數字化的文字,也可以通過SONY開設的電子書租賃服務"Timebook Town"以月租的方式從網上下載閱讀內容。這樣的服務模式標志著多年來的電子紙及其下游產品已經進入了真正的實用階段,人類的數字化生活也許要因此而翻開嶄新的一頁。 |
[前 言]:眾所皆知,項目管理要做的三件大事就是:計劃、組織和控制,然而如何計劃、組織和控制好一個項目,不僅要求項目經理要有系統
[關健詞]:基準計劃、比較基準工期、比較基準成本、工期差異、成本差異、BCWS、ACWP、BCWP、SV、CV等。
一、 項目管理與Project2000的關系
在項目管理知識體系中,包括九大知識領域(范圍管理、時間管理、費用管理、質量管理、人力資源管理、溝通管理、風險管理、采購管理、綜合管理)。但從項目管理輔助工具軟件Project2000來說,它包含了這九大知識領域中的5大核心領域,另外4個領域需要通過其它輔助工具或人工操作來完成。包括的5大領域如下所述:
1、 范圍管理
項目管理的第一個知識領域就是"范圍管理",在項目范圍中,包括兩層內容:一是項
目范圍;二是產品范圍。項目范圍針對的是我們項目的目標,包括軟件開發、集成、培訓和項目實施等。產品范圍側重在軟件的需求范圍,可以理解為對項目范圍的一個重要補充。兩者有一定關聯,但也各有側重,只有這兩者相加,才構成了我們完整的項目范圍。然而在Project2000工具中,指的項目范圍是指第一種,結果輸出就是WBS分解。
2、 時間管理
時間管理也稱進度管理,在Project2000中,它提供了工期估計、工作搭接關系、進度安排、進度控制等基本功能。還能夠自動計算出關健路徑,可以很方便的設置我們的里程碑控制點,并能夠實現項目的動態跟蹤。還提供了多種時間的管理方法,甘特圖、網絡圖、日歷圖等。應該說時間管理,是Project 2000中最強大的功能。
3、 費用管理
在費用管理中,Project2000中采用的是"自底向上費用估算"的技術,由于它是依賴每個WBS任務的估算,所以使得費用估算更為準確。并且它還能與EXCEL等進行結合,生成費用曲線圖和掙得值趨勢圖。
4、 人力資源管理
在人力資源管理中,Project2000提供了人力資源的規劃、人力資源責任矩陣、資源需求直方圖、資源均衡等,它能幫我們做好資源的分配、進行資源的工作量、成本和工時的統計。
5、 整合管理
項目管理的整合管理就是對于整個項目的范圍、時間、費用、資源等進行綜合管理和協調,在Project2000中,它能根據范圍、時間、資源的變化自動進行相應計算和調整。
二、 Project2000使用前的環境設置
在進行計劃編制前,需先設置好Project2000的使用環境,這樣可以更方便我們計劃編
制時的操作。環境設置一要根據自己的習慣,二是要根據項目的實際情況。下面介紹幾種常用的環境設置項。
* 首先,要設置項目摘要信息,在摘要信息中需輸入該項目的標題、項目經理和單位等信息。主要是便于打印時顯示的信息。
操作方法:選中菜單 文件-》屬性-》摘要信息-》。
* 設置項目的日歷,默認從星期日開始,中國人的習慣一般是從周一開始。
操作方法:選中菜單 工具-》選項-》日歷-》每周開始于-》。
* 設置任務類型,默認為"固定工時",固定工時的含義是當一項任務分配給一個人做是10天,當增加一人時,則工期自動變為5天。我們的操作習慣應該是人員增加時,原工期一般要求仍不變。所以需選擇為"固定工期"。
操作方法:選中菜單 工具-》選項-》日程 -》默認任務類型-》。
* 設置WBS編號,默認無WBS編號,為了計劃閱讀清晰,建議設置大綱編號作為WBS編號。
操作方法:選中菜單 工具-》選項-》視圖-》選中顯示大綱編號。
* 設置工作時間,默認是按標準日,也即周六、周日休息。行政日指不但考慮周六、周日休息,而且考慮到中國的傳統節假日(如國慶、五一等)。我們一般要根據項目的具體情況,如該項目比較工期比較緊,項目組要求每周六加班,周日休息,那么就需將周六設置為"非默認工作時間"。
操作方法:選中菜單 工具-》更改工作時間-》選中對象-》非默認工作時間。
* 設置條形式樣式,可根據自己的習慣,設定關健任務、非關健任務、進度條、里程碑為不同的樣式和顏色。
操作方法:選中菜單 格式-》條形圖樣式-》。
說明:建議環境設置可以設置為一個模板,這樣就無需每個項目都進行設置一下,提高計劃編制效率。
三、 如何使用Project 2000來制定計劃
在項目管理知識體系中,項目的計劃包括4個核心計劃和4個輔助計劃,4個核心計劃為:范圍計劃、人力資源計劃、進度計劃和費用計劃;4個輔助計劃為:質量計劃、溝通計劃、風險計劃和采購計劃。利用Project2000工具,能很方便的完成4個核心計劃的制定。
為了使我們能夠更好的掌握如何運用Project2000工具來做計劃的,在這里將上述講述的4個核心計劃,分解成8個步驟來講述,并在每個步驟當中,給予案例,這樣更便于我們的理解和操作。
案例背景描述:
某企業決定開發一套項目管理軟件。
該軟件的主要功能包括:項目及工作信息的錄入、項目網絡計劃圖的繪制、項目時間計劃的安排、甘特圖計劃的制定、項目執行信息的錄入與分析及各種計劃報表的輸出等。該企業準備投入25萬元進行該系統的開發,時間要求是20~25周。該軟件項目的計劃開始時間是2002.1.1日,企業要求軟件正式驗收前需要試運行4周以上的時間,并根據試運行情況進行適當修改。
1、 目標確定
項目目標就是實施項目所要達到的期望結果,是衡量項目成功與否的標
|
項目目標的描述必須明確、具體、盡量定量描述,需滿足Smart原則:
* Specific 明確
* Measurable 可衡量性
* Achievable 雖然極具挑戰性, 但是有計劃完成
* Result Driven 面向成果
* Time 具時間性
案例示范:目標描述:
a、 總費用:在25萬的費用預算內;
b、 時間:從2002年1月1日開始,至2002年6月27日完成,總工期24周;
c、 交付物:開發一套功能齊全的項目管理軟件、其中主要功能為:項目及工作信息的錄入;項目網絡計劃圖的繪制;項目時間計劃的安排;甘特圖計劃的制定;項目執行信息的錄入與分析及各種計劃報表的輸出等。
說明:在Project2000中,沒有特定的項目目標書面位置,可以專門采用Word文檔進行描述,也可直接在Project2000中的備注欄中注明。
2、 范圍定義
范圍定義就是將項目可交付成果分成幾個小的、更易管理的單元。范圍定義的結果是
形成工作結構分解圖(WBS)。WBS分解就是先把復雜的項目逐步分解成一層一層的要素(工作),直到具體明確為止。
WBS分解的步驟:
* 總項目
* 子項目或主體工作任務
* 主要工作任務
* 次要工作任務
* 具體工作包
WBS的表現形式:
* 樹形列表
* 鋸齒列表
WBS分解結果要求:
* 可管理、可定量測量、可獨立分配任務的;
* 可以進行費用和時間的估計;
* 不體現工期和活動的先后順序;
* 包括管理活動;
* 分解完后需進行核對。
說明:WBS分解是項目計劃的基礎,也是最關健的。需要做的前期調研和需求分析工作。如果WBS偏差率較高,則整個計劃的基本上很難執行。所以這塊基石一定要打好。
另外,在WBS分解過程當中,項目管理工作內容不能漏掉。
案例示范:
在Project 2000中,WBS分解采用的是鋸齒形式,WBS編碼能自動生成,最多可分解
為500多層,100萬個WBS任務。如:
3、 工作排序
工作排序的確定涉及到各工作之間相互關系的識別和說明。任何工作的執行必須依賴于一定工作的完成,也就是說它的執行必須在某些工作完成之后才行,這就是工作的先后依賴關系。工作的先后依賴關系有兩種:一種是工作之間本身存在的、無法改變的邏輯關系。如設計與開發。還有一種是組織關系,一般由管理人員根據實際情況來確定。我們要在邏輯關系的基礎上再加以分析,考慮組織關系。
工作排序需要確定的內容:
* 強制的邏輯關系的確定;
* 組織關系的確定;
* 外部制約關系的確定;
* 實際過程中的限制和假設。
工作排序常用的方法:
* 單代號法(AON法)
* 雙代號法(AOA法)
案例示范:
4、 工期估計
工時的估計是項目計劃制定的一項重要的基礎工作,它直接關系到項目的總工期。如果估計的太短,那么在工作中會造成被動局面;相反,如果估計的太長,那么整個工期延長。所以說在工時估計的時候,要在考慮到各種資源、人力、物力、財力的情況下,把工作置于獨立的正常狀態下進行估計,要做統盤考慮,不可顧此失彼。
工期估計的方法:
* 專家判斷。依賴于專家組成員的歷史經驗。
* 類比估計法。依賴于同類型項目的歷史實際數據。
說明:在人力資源尚未分配時,進行工時估計,一般以按平均資源能力進行估算。
5、 進度安排
根據項目內容的分解,找出各組成要素工作的先后順序,估計出各工作的延續時間之后,就要安排好項目的時間進度。因為在進度安排之前,我們的計劃都是假設在正常情況下的計劃,實際中我們的計劃會受到各種因素的影響和限制,所以需要根據這些限制重新對進度進行調整。進度安排主要是要根據實際情況來考慮我們的計劃。另外,在進度安排中,要將里程碑計劃和關健路徑計劃加入。
進度安排的方法:
* 關健路徑法。關健路徑是指機動時間為0的工作,如果延期,會導致總工期延期,需特別關注。
* 里程碑計劃法。為更好的對項目進度的進展測量進行測量,需設置合理的里程碑點,用于檢查階段性成果的輸出,以及實際進度與計劃的偏差。
* 計劃評審技術(PERT)。對于工作先后邏輯關系及活動不確的時間,可采用最最短時間a、最可能時間m、最長時間b,然后按照β分布計算該工作的期望時間t。
* 并行壓縮法。對于限定工期的項目,往往需采用并行處理技術,保證項目在限定的工期內完成。并行處理雖然壓縮了時間,但同時會引發人力資源和質量的風險,需綜合考慮。
案例示范:
在該項目的Project甘特圖進度安排中
6、 人力資源安排
資源計劃涉及到決定什么樣的資源,以及多少資源將用于項目的每一工作的執行過程之中。這里的資源包括人、設備和材料等。象我們的設備分解單也是屬于資源
|
人力資源計劃:
* 分析出人力資源需求
* 人力資源獲取
* 人力資源培訓
在Project2000中,先需建立資源庫,具體操作是:工具-》資源-》分配資源。將項目所需人力資源錄入,人力資源包括本部門、協作部門、用戶和第三方廠商等。資源庫建立完后,就可采用拖放的方式來對每條任務分配資源。
資源分配完畢后,項目計劃編制者需調整和優化資源,如資源過度分配或資源剩余等。
說明:1、這里所指的資源,均指人力資源,其它如設備資源沒有包括在此中。
2、在第四步工期估計時,尚未分配資源,所以按平均資源能力估計,但資源分配后,對工期估計要做相應一些調整。
案例示范:
7、 費用估計
費用估計指的是預估完成項目各工作所需資源的費用的近似值。目前我們考慮的資源
主要是人力資源和差旅費用。而設備和材料資源暫未考慮。費用估計應該與工作質量的結果相聯系。費用估計過程中亦應該考慮各種形式的費用交換。
費用估計的常用方法:
* 類比估計法。依賴于歷史數據的積累。
* 從上而下估計法。
* 從下到上估計法。
在Project2000中,采用的方法是"從下到上估計法",這種技術通常首先估計各個獨立工作的費用,然后再匯總從下往上估計出整個項目的總費用。估計相對會比較準確。
在Project2000預算中,我們首先要輸入人力資源的單位價格,在Project工具中,人力資源基本單位為:工時。在數據錄入時要進行換算,需將每天標價除以8,轉換為工時單價。人力單價估計完后,還要對差旅、招待、活動、通信費、辦公等其它費用進行單價估計,如差旅費平均每趟多少,招待費平均每次多少,活動費平均每次多少等,這些單價要依據項目的規模、復雜度和地域等因素來確定,有的還要參照公司財務制度的標準(如通信費用報銷規定、差旅補貼規定等)。在Proejct2000的差旅、招待費等的單價錄入中,類型選擇為"材料"。
案例示范:
8、 費用預算
費用的預算包括給每一項獨立工作分配全部費用,以獲取度量項目執行的費用基線。
費用預算可以分為三部分,即人工費用預算、輔助服務費用預算和采購物品費用預算。但我們目前費用預算主要考慮的是人工費用預算和差旅等其它費用。
在Project2000中,當費用估計完成后,一般來說人力成本便自動計算出來了。但對于差旅等其它費用還需按里程碑或或主體任務進行分配,對于較小的項目也可就在總項目中分配(本例就是在總項目中分配)。分配方法與第六步的人力資源分配方法一樣。
案例示范:
四、 計劃的應用
計劃的編制,不是單獨由項目經理來做,應該是要求項目成員或項目主要成員一起參與。
項目計劃制定完后,還要組織計劃的評審。計劃評審通過后,就形成了項目的基準計劃,這個基準計劃是日后項目控制的杠桿,也是項目績效考核的重要基礎數據。
應用一:里程碑計劃
里程碑,一般都是項目的關健控制點,里程碑的設置應滿足階段成果和易測量兩種屬性。對項目高層經理或項目主管來說,他們進度控制的焦點往往就是里程碑計劃。
操作方法是,選中菜單的項目-》篩選-》里程碑。并插入列備注(輸出成果)。
案例示范:(藍色字體就是我們的里程碑點,共4個)
應用二:關健任務
關健任務,也即機動時間為0的工作,只在關健任務上的工期延期一天,則總工期必將延期一天。所以關健任務對總工期的控制有關至關重要的作用。對項目經理來說,進度控制的側重點應在關健路徑的任務上。
關健路徑顯示有兩種方法:一是在菜單的格式-》甘特圖向導-》關健路徑;另一種是在菜單的項目-》篩選-》關健路徑。第一種情況在前面計劃編制的第6步進度安排時有體現。下面以第二種為例。
案例示范:
應用三:任務責任分配
基準計劃形成后,項目經理需將各任務分配給個每個項目成員。并要求每個項目成員簽署任務責任書或任務承諾書,一般在正式開工前的開工會議上進行。任務分派完后,這樣我們的計劃就開始正式進入執行階段了。
在Project2000中的任務分配,操作過程是:資源使用狀況-》在列中加入開始時間、完成時間、完成百分比、備注(即輸出成果)等列,使得任務分配的信息更全面。
案
應用四:資源負荷分析 計劃完成后,還要檢查資源分配是否超負荷,如資源超負荷過多,則該計劃很難執行。檢查資源超負荷的方法如下: 接著,超負荷資源找出來后,我們接著要將該資源超負荷分配的任務要找出來。操作方法:選中菜單的項目-》篩選-》使用資源,然后根據彈出的提示框,選擇資源"王五"。則可看出超負荷分配的任務。 對于人力資源分配時,必須掌握一個均衡分配的原則,不能某一段時間人力資源需求量驟增,某一段時間驟減。這樣對人力資源的調配和獲取帶來困難。項目經理可以通過"人力資源工時曲線圖"幫助進行分析。 操作方法:選擇 視圖-》工具欄-》分析,則這是在Project2000工具中會出現:"在EXCEL中分析時間刻度數據",點擊該快捷圖標-》選擇完整項目-》選擇導出的域為"工時"-》選擇時間單位為"周"-》導出數據 應用五:費用預算曲線圖 在費用預算,如按時間坐標來分析,有兩種表現方式,一是費用預算曲線圖,二是費用預算累計曲線圖。 對于費用預算累計曲線圖,同上述操作方法基本一致,就是在選擇導出的域為"累計成本"便可。 另外,在費用預算中,如從資源坐標來分析,費用來源分為兩大類,一是人力成本費用,二是差旅、交通、招待、會議、等費用。費用從資源角度顯示如下。(當然也可將人力資源成本倒出到EXCEL中進行小計。) 五、 如何使用Project 2000來控制計劃 1、 進度跟蹤 案例示范: 假如,實際工期花費了11工作日,則在實際工期中輸入11便可,完成百分比,則會自動計算,在下面進度控制中,便會體現實際工期比計劃工期多用了1天。 2、 未完成任務的查看 3、 進度和費用偏差 4、 項目跟蹤甘特圖 操作方法:選中"跟蹤甘特圖"便可。在下圖中,下面灰色部分表示原比較基準進度條,上面的藍色部分表示實際進度條。從該圖中可看出實際進度有后延。 案例示范: 5、 項目總體進展情況統計 |
操作方法:選中菜單 項目-》項目信息-》在對話框中點擊"統計信息"。例如從下圖中可以看出:該項目在當前狀態下,已完成總任務的28%,費用花了¥112,034.81元,總工期延期了1天,費用超支了¥3904.00元。
案例示范:
6、 掙得值法分析
掙得值法實際上是一種分析目標實施與目標期望之間差異的方法,又稱偏差分析法。它控制的原理就是利用已完成工作的實際成本(ACWP)、計劃完成工作的預算成本(BCWS)、實際完成工作量的預算成本(BCWP)三個基礎數據,來計算得出進度偏差(SV)和費用偏差(CV)。
假如,以第一個里程碑點200年1月21日作為檢查點,來計算該項目的進度和費用偏差值。
操作方法:選擇,項目-》項目信息-》在彈出的"項目信息"框中,將狀態日期選擇為:"2002年1月21日"。然后分別插入列"BCWS"、"ACWP"、"BCWP"、"SV"、"CV"等,從計算結果可得SV<0、CV<0,說明該項目在第一個里程碑點進度延期了,費用也超去了,必須采取控制措施或計劃變更。
案例示范:
說明:由于檢查點為2002年1月21日,而"需求分析"任務工期為5天,實際完成日期為2002年1月22日,所以的計劃工作量的實際成本為8000*4/5=6400;已完成工作量的預算成本為4000*4/5=3200。圖示如下:
六、 結束語
以上是本人根據對Project2000的一些粗略理解,并結合近5年來的項目管理實踐經驗總結而成。謹以把此文獻給各項目經理,以供參考。希望我們的項目經理能掌握一些工具,來幫助我們更好的管理項目。另外,在后一段時間,我們將繼續推出基于WEB的團隊項目管理工具-"Project Central工具"的應用與實例
一.JAVA電子書
優點:書籍量大,經常更新,教育網下載速度超快
不足:每天只能下載4本
孫衛琴感動了我!(我--張孝祥) | ||
thinking_org 轉貼 更新:2006-08-02 09:09:55 版本: 1.0 |
今天聽了孫衛琴的講座,頗受感動。本來覺得孫衛琴的成功是走了一些竅門,無非是綜合了國外多本書籍的成果,再用自己的語言描述出來而已,少有她自己摸索和實踐的東西。即便這般認為,但孫衛琴也是令我非常尊敬和佩服的,因為有過類似寫作的經歷,我深知只要不是攢書,只要是抱著對讀者負責、對自己的作品負責的心態來寫作,那么整個創作過程就會非常艱辛,需要毅力來堅持,何況孫衛琴在短短幾年內寫出了這么多受人喜歡的書籍,那寫書的效率和付出的辛勞是不言而喻的。對于孫衛琴,我只能是佩服和尊敬,我沒有資格去挑剔人家書中的缺陷,因為在寫書效率上我不如人家,至少我不能在這么短的寫作周期內寫出好過她的書。 前些天因為培訓合作事宜,與孫衛琴通過電話,知道了她和我有一樣的憂患,那就是老了誰來養,我們都是自由職業,沒有國家皇糧,沒有養老保險,所以,現在只能比別人付出更多的努力,以便讓自己的未來有一定的安全感。她說有人指責她抄襲老外的作品,我跟她談到,不要理會那些人的言論,她把國外作者的經驗按中國人的閱讀方式引入了中國,這作出的貢獻是值得肯定的,是有歷史意義的,不象國內某些作者直接抄取其他國內作者的書,重復別人的工作,那就談不上對社會有什么歷史貢獻和價值了,無非是給自己謀取了一些名利而已。我作為一個被人贊揚過的、也被人譏笑和嘲罵過的作者,我的感受是很深的,一些人看到別人的成果后,然后對別人的成果進行挑刺,這是一件很簡單的事情,大家都能做,但這不能說一個能挑刺的人水平就怎樣,這往往是那些自己找不到成就,而只能靠給被人挑刺來滿足自己虛榮心的人所為。如果那些人果真有本事的話,就先別急著給別人挑刺,而是自己也做點類似的東西出來,做完后就知道自己還不如人家的好呢!我有一個很大的創作計劃,本來如果我的臉皮厚,我也可以在孫衛琴那幾本書的基礎上修修改改,稍作完善,然后再從別的書上整點資源進來,到時候還可以對大家說,我的書比孫衛琴的好,因為站在孫衛琴的基礎上創作,我想應該比她的好點吧!但我沒必要那么做,我不是為了經濟效益和名聲而不擇手段的人!我把寫作當作了一種藝術,我希望完全用自己的方式來寫作,寫出我想寫的那些東西,我希望做出對社會有歷史價值的貢獻,所以,我是不可能抄襲別人的,對我來說,即使在出版社多出了幾本書,只要不是我自己用心寫出來的,而是與別人寫得差不多,那我從中也根本就找不到任何成就感,基于這種寫作心態,我自身寫作周期很漫長,所以,我希望孫衛琴能夠結合培訓的特點,重新調整一下她的那些書籍內容,以便我們作為全國范圍內的培訓教材使用。 上次的電話僅僅是簡單問了一下她目前的情況和想法,并不知道她創作的經歷。可是,我今天聽完別人對孫衛琴的介紹,我是真的感動了,孫衛琴在懷孕4個月后開始寫struts,在小孩出生3月后就把孩子托付給了江蘇常州的父母,又只身一人回到上海,開始把自己封閉在一小屋里寫hibernate,最長時間是12天沒見到過一個人,可敬!我等有人洗衣做飯的大老爺們,在她面前還有什么苦可叫! 注:為了創作,我估計也能夠忍受12天不與外界接觸的寂寞, 但現在身體素質跟不上了,每天只要在電腦前連續工作8個小時以上,就會頭暈、惡心,渾身乏力,胃病復發,所以,我原來靠個人英雄主義的寫作思想開始逐步轉向了團對協作,我佩服孫衛琴哪來這么好的體力! 看了下面一些人的評論,想想這個世間還真好笑,看來還是有許多對我沒有好感的人在經常關注我的blog啊,不知這些人是一種什么樣的看客心態,在滿篇文章中揪人家的小辮子,然后就開始發揮自己無限的遐想了,為了讓這些人明白自己是多么"聰明",特作如下解釋: 1.孫衛琴老師的書中確實很多代碼都是直接來自一些現有外版書籍,已有數人親自給我這么說過,但我并沒有私下向別人說過,因為我理解孫衛琴老師,能做成這樣已經非常不容易,不能要求別人十全十美。我親自與孫衛琴交流時就是這么說的。 2.這些發表評論的人誰寫過書,誰想堅持不懈地好好寫本書過,沒有!那就不要站著說話不腰疼,我一直在努力寫書,我寫的內容到底有多大價值,以后會有人給出恰當評價的。正因為我太想寫成一系列的好書了,所以,花費的功夫非常之多,加上這么多年的身體透支,感覺寫書就是心有余而力不足,這個力不足不是學不會知識,而是沒有體力去鉆研和細化每個知識細節,所以,發出了"我佩服孫衛琴哪來這么好的體力!"的慨嘆。我就是認為struts,hibernate,spring從學習的角度來說,一點也不難,但要扣細,確實要花費大量的時間和體力,如果你的java基礎和java web不是很好,覺得struts,hibernate,spring很難,那是情理之中的事,但不要以己度人,對你難的事,對別人來說未必就難! 3.我從來不怕解剖我自己,我就是一個非常非常普通的人,只是我有理想,有目標,我為了理想一直在奮斗。我根本不在意別人的評論,只是嘆息那些自以為是的人,怎么對在別人的字里行間挑話題這么有興趣,真不知道這些人平常的工作是什么。(完) 我(張孝祥)的技術學習觀念: 我一直認為基礎知識最重要,無論是對國家,還是對個人的后期發展,都是最重要的.有些人自以為是,以為會玩玩struts,hibernate之類的工具,就覺得自己不得了,其實,那算什么,一個用高級工具的用戶而已,如果中國全是這樣的高級用戶,中國軟件永遠不會有出頭之日,永遠只能用別人做好的工具!非常遺憾的是,我搞這些基礎知識的"研究",常常引來一些譏諷聲和嘲笑聲,不過,這些譏諷聲和嘲笑聲并不能左右我的思想!我沒必要為去迎合那些無知和沒有遠見的人(不是攻擊別人,而我就是這么想的)而改變自己的立場和理念! 我現在不算精通struts,hibernate,spring,但是,還算學得明白,照著一些現有的書籍和別人的思路講講課,應該不會有什么問題.我并不覺得這樣就有什么資本,我從未欽佩過那些使用struts,hibernate,spring的大蝦們,而是只佩服當初開發struts,hibernate,spring這些框架的大俠們.佩服那些對這些框架的內部原理有深入研究的技術牛人們!我在學習struts和spring時,發現這些框架的設計師們對html,css,javascript,http協議,servlet,jsp,java等基礎性知識掌握得都非常全面,并且細節都非常清楚,敢問國內那些看不上這些基礎知識的人們,為何struts和spring設計師們都覺得這些知識重要,而你卻認為不重要,說句不客氣的話,因為你還連一點概念都沒有,你永遠到不了struts和spring設計師們的水平,我雖達不到他們的水平,至少我可以追隨他們的思想,讀懂他們的源碼,知道他們為何要這么做! 每個人都可以有自己的想法,但沒必要把自己的想法強加給其他人! |
![]() 圖 1 MVC和J2EE技術 |
![]() 圖 2 Struts MVC實現 |
![]() 圖 3 Struts接受并返回響應的中間過程 Struts1.1新增功能 1、多模塊的支持 我們知道,在Struts 1.0中,只能在web.xml中為ActionServlet指定一個Struts配置文件(struts-config.xml),這對一個只需一兩個人開發的小系統當然沒有任何問題,但如果一個多人開發的大中型應用程序,問題就產生了。因為許多開發人員可能同時都需要修改Struts配置文件,這樣肯定會造成一定程度的資源爭奪,可能會出現彼此覆蓋的情況,這樣勢必會影響開發效率并引起開發人員的抱怨。 在Struts 1.1中,為了解決這個并行開發的問題,提出了兩種解決方案: ·多個配置文件 支持多個配置文件,是指你能夠為ActionServlet同時指定多個xml配置文件,文件之間以逗號分隔,請看下面web.xml中關于多個struts配置文件的聲明示例: 代碼清單 1 多個struts配置文件
通過這種方法,你可以為每一個模塊定義一個配置文件,由于項目一般按模塊劃分工作,這樣就大大地減小了沖突的概率。 ·獨立的模塊 但是,多個配置文件存在一個潛在的問題:不同的配置文件之間會產生沖突,因為在ActionServlet初始化的時候多個配置文件還是要合并到一起。比如,在struts-config.xml中配置了一個名為errorDbAccess的<exception>,而在book-struts-config.xml中也配置了一個同樣的<exception>,這樣就產生沖突了。 為了徹底解決這種沖突,Struts 1.1中引進了模塊(Module)的概念。一個模塊就是一個獨立的子系統,對應一個獨立的配置文件,ActionServlet將不同模塊的配置文件保存在各自獨立的ModuleConfig對象中的。 下面是兩個獨立模塊的配置方式: 代碼清單 2 多模塊配置方式
通過這種方式,我們配置了兩個模塊,一個模塊名為config,而另一個名為config/book。 ·動態ActionForm支持 ActionForm表示HTTP頁面表單的數據,可以將其看成視圖頁面數據的服務器映射,它負責保存視圖中的數據供控制器或者其他視圖使用。此外,它還負責數據有效性的驗證,所以Struts 1.1文檔把它比作HTTP和Action之間的防火墻,這足以體現ActionForm在視圖和控制器之間的過濾器作用。 由于ActionForm對應于HTTP頁面表單,所以隨著頁面的增多,你的ActionForm將會急聚增加。動態ActionForm(DynaActionForm)即為減少ActionForm的數目被設計出來,利用它你不必創建一個個具體的ActionForm類,只需要在配置文件中配置出所需的虛擬ActionForm,而由Struts框架通過配置文件動態創建這個ActionForm。例如,代碼清單 3通過指定<form-bean>的type為"org.apache.struts.action.DynaActionForm"來創建一個動態的ActionForm--loginForm。 代碼清單 3 配置一個動態ActionForm
DynaActionForm將屬性保存在一個Map對象中,同時提供相應的get(name)和set(name,value)方法,其中參數name是要訪問的屬性名,而value是一個Object。例如要訪問DynaActionForm中bookName的值,可以采用String bookName = (String)get("bookName")方法,由于bookName存儲在Map中,所以要進行強制轉換。 由于DynaActionForm通過配置文件產生,并沒有一個實體對象類,如果要對動態ActionForm對象進行校驗需要使用DynaValidatorForm,它是DynaActionForm的子類,它能夠提供動態ActionForm和動態表單輸入驗證的功能。檢驗規則在validation.xml配置文件中定義,而這些規則的所對應的實現函數在validator-rules.xml文件中定義。 ·通過配置方式實現異常處理 Struts1.1允許以配置方式進行異常處理,配置方式可以避免在Action中通過硬編碼來處理異常,從而提高應用程序異常處理的靈活性和可維護性。一般情況下,一個異常處理對象可以通過以下步驟實現: 1.實現org.apache.struts.action.ExceptionHandler的子類,覆蓋execute()方法,在該方法中處理異常并且返回一個ActionForward對象。 2.在配置文件中配置異常處理對象,你可以配置一個全局的處理類或者單獨為每個Action配置處理類。 代碼清單 4定義了一個全局的處理類TestExceptionHandler,它被用來處理所有的異常。 代碼清單 4 一個全局宣告式異常處理的配置
type屬性定義了匹配的異常,path定義了異常發生后轉發的地址,而handler指定在轉發前對異常的特殊處理,如果沒有提供handler,默認的處理類org.apache.struts.action.ExceptionHandler。 |
開發環境:? Java?SDK?(I?am?currently?using?version?1.4.1)? Ant?(using?version?1.5.3) Apache?Tomcat?(using?version?4.1.24) 您可以用功能相同的任何容器或者java運行環境? 第1步:開發路徑? 為了保留我們的開發中每一步的流程,我們將保存所有的源碼和文件。? 首先,我們創建一個springapp的目錄(你可以將這個目錄建在任何地方),然后,在springapp目錄下創建子目錄src,用來保存java資源文件。然后我們建立另一個子目錄war,這個目錄將保存生成的war文件。? 建立WEB-INF子目錄,和它的classes,lib子目錄。? OK,你的目錄應該這個樣子:? 代碼:? -spirngapp? ??-WEB-INF? ??????-classes? ??????-lib? ??-src? ??-war? 第2步:創建jsp? 我們創建一個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>?????? 現在,我們來完成這個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? 現在我們來寫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?我就不用說了吧? 如果你執行install命令,將在tomcat?webapps目錄下建立springapp目錄。? 如果你用其他的web應用服務器,那么你可以刪除tomcat指定的命令集,你可以用server提供的熱部署進行啟動和停止你的應用.? 現在我們來看一下ant提供的每個命令,在你的springapp目錄下執行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? 現在,我們來部署應用,執行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? 如果你還沒有安裝,請執行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? 現在,讓我們打開瀏覽器看一下結果http://localhost:8080/springapp/index.jsp? 第5步:下載spring?framework?package? 如果你還沒有下在spring,請到www.springframework.org/download.html.?尋找最新版本.? 下面我們將完成利用spring?framework?進行開發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目錄下創建一個springapp-servlet.xml文件,它的命名規則是web.xml中的servlet-name?加上'-servlet'后綴,這是在springframework中的標準命名法則.? 現在,我們聲明一個bean?:springappController?他對應的類是SpringappController.class? 這個定義用于我們控制業務邏輯。我們還需要定義一個url?mapping作為http調用的路徑.? 代碼:? 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步:創建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("");? ????}? }? 這只是一個基礎控制框架,稍候我們完成它.? 第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步:建立日志系統? 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步:創建視圖? 代碼:? 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");? ????}? }? 現在我們運行build,?deploy,?stop,?start?命令.? 這樣我們就成功地建立了一個mvc應用,訪問http://loaclhost:8080/springapp/hello.htm? 小結? 以上,我們快速地利用spring?framework建立了MVC應用程序,? 1、建立index.jsp,測試管理工具和開發環境? 2、編寫springapp-servlet.xml配置文件。? 3、編寫控制器代碼,SpringappController.java結合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體系結構?對應各個部分的開發工作主要包括哪些?
2. XML包括哪些解釋技術,區別是什么?
3. JSP有哪些內置對象和動作?它們的作用分別是什么?
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 '%%' )
的檢索結果為何不同?
5、SQL問答題
表結構:
1、 表名:g_cardapply
字段(字段名/類型/長度):
g_applyno varchar 8;//申請單號(關鍵字)
g_applydate bigint 8;//申請日期
g_state varchar 2;//申請狀態
2、 表名:g_cardapplydetail
字段(字段名/類型/長度):
g_applyno varchar 8;//申請單號(關鍵字)
g_name varchar 30;//申請人姓名
g_idcard varchar 18;//申請人身份證號
g_state varchar 2;//申請狀態
其中,兩個表的關聯字段為申請單號。
題目:
1、 查詢身份證號碼為440401430103082的申請日期
2、 查詢同一個身份證號碼有兩條以上記錄的身份證號碼及記錄個數
3、 將身份證號碼為440401430103082的記錄在兩個表中的申請狀態均改為07
4、 刪除g_cardapplydetail表中所有姓李的記錄
在應用程序中添加日志記錄總的來說基于三個目的:監視代碼中變量的變化情況,周期性的記錄到文件中供其他應用進行統計分析工作;跟蹤代碼運行時軌跡,作為日后審計的依據;擔當集成開發環境中的調試器的作用,向文件或控制臺打印代碼的調試信息。
最普通的做法就是在代碼中嵌入許多的打印語句,這些打印語句可以輸出到控制臺或文件中,比較好的做法就是構造一個日志操作類來封裝此類操作,而不是讓一系列的打印語句充斥了代碼的主體。
在強調可重用組件開發的今天,除了自己從頭到尾開發一個可重用的日志操作類外,Apache為我們提供了一個強有力的日志操作包-Log4j。
Log4j是Apache的一個開放源代碼項目,通過使用Log4j,我們可以控制日志信息輸送的目的地是控制臺、文件、GUI組件、甚至是套接口服務器、NT的事件記錄器、UNIX Syslog守護進程等;我們也可以控制每一條日志的輸出格式;通過定義每一條日志信息的級別,我們能夠更加細致地控制日志的生成過程。最令人感興趣的就是,這些可以通過一個配置文件來靈活地進行配置,而不需要修改應用的代碼。
此外,通過Log4j其他語言接口,您可以在C、C++、.Net、PL/SQL程序中使用Log4j,其語法和用法與在Java程序中一樣,使得多語言分布式系統得到一個統一一致的日志組件模塊。而且,通過使用各種第三方擴展,您可以很方便地將Log4j集成到J2EE、JINI甚至是SNMP應用中。
本文介紹的Log4j版本是1.2.3。作者試圖通過一個簡單的客戶/服務器Java程序例子對比使用與不使用Log4j 1.2.3的差別,并詳細講解了在實踐中最常使用Log4j的方法和步驟。在強調可重用組件開發的今天,相信Log4j將會給廣大的設計開發人員帶來方便。加入到Log4j的隊伍來吧!
我們先來看一個簡單的例子,它是一個用Java實現的客戶/服務器網絡程序。剛開始我們不使用Log4j,而是使用了一系列的打印語句,然后我們將使用Log4j來實現它的日志功能。這樣,大家就可以清楚地比較出前后兩個代碼的差別。
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. 服務器程序
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. 服務器程序
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. 服務器程序配置文件
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由三個重要的組件構成:日志信息的優先級,日志信息的輸出目的地,日志信息的輸出格式。日志信息的優先級從高到低有ERROR、WARN、INFO、DEBUG,分別用來指定這條日志信息的重要程度;日志信息的輸出目的地指定了日志將打印到控制臺還是文件中;而輸出格式則控制了日志信息的顯示內容。
其實您也可以完全不使用配置文件,而是在代碼中配置Log4j環境。但是,使用配置文件將使您的應用程序更加靈活。
Log4j支持兩種配置文件格式,一種是XML格式的文件,一種是Java特性文件(鍵=值)。下面我們介紹使用Java特性文件做為配置文件的方法:
log4j.rootLogger = [ level ] , appenderName, appenderName, …其中,level 是日志記錄的優先級,分為OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定義的級別。Log4j建議只使用四個級別,優先級從高到低分別是ERROR、WARN、INFO、DEBUG。通過在這里定義的級別,您可以控制到應用程序中相應級別的日志信息的開關。比如在這里定義了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),通過指定的名字獲得記錄器,如果必要的話,則為這個名字創建一個新的記錄器。Name一般取本類的名字,比如:
static Logger logger = Logger.getLogger ( ServerWithLog4j.class.getName () ) ;
3.2.2.讀取配置文件
當獲得了日志記錄器之后,第二步將配置Log4j環境,其語法為:
BasicConfigurator.configure (): 自動快速地使用缺省Log4j環境。
PropertyConfigurator.configure ( String configFilename) :讀取使用Java的特性文件編寫的配置文件。
DOMConfigurator.configure ( String filename ) :讀取XML形式的配置文件。
3.2.3.插入記錄信息(格式化日志信息)
當上兩個必要步驟執行完畢,您就可以輕松地使用不同優先級別的日志記錄語句插入到您想記錄日志的任何地方,其語法如下:
Logger.debug ( Object message ) ; Logger.info ( Object message ) ; Logger.warn ( Object message ) ; Logger.error ( Object message ) ;
如果您想更深入地了解Log4j,請經常訪問下面提及的相關鏈接。
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基礎,webwork基礎,對spring有一定的了解。
http://www.springframework.org/ 站點可以了解更多關于spring的詳細信息. Spring是一個很好的AOP框架,能提供自動的事務管理。
http://www.opensymphony.com/webwork/ 站點可以了解更多的webwork . Webwork是一個很好的 MVC 框架,以下簡單介紹,webwork 和 spring 的融合,以用戶注冊為例。
2 整合步驟
2 .1使用 SpringObjectFactory
dev.java.net上的 xwork-optional 包括了對 xwork-spring 的支持,可以下載些包。包中只有4個類,可以根據具體情況使用。我在例子中使用了SpringObjectFactory類和SpringObjectFactoryListener 類,并安照webwork的文件在web.xml加入了,以下節點
<!-- 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的執行。
<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 的作用是設置 XWork 和 Webwork 的環境,使這能從spring 中加載數據和信息(在contextInitialized(ServletContextEvent event)方法中,當啟動web應用程序是調用).
要使ContextLoaderServlet比SpringObjectFactoryListener類更早執行,我使用的方法是重載ContextLoaderServlet,在中子類的int方法中設置XWork 和 Webwork 的環境,去掉SpringObjectFactoryListener 監聽器,并整改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中增加如下節點
<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中要調用的類名。
匹配中文字符的正則表達式: [\u4e00-\u9fa5]
匹配雙字節字符(包括漢字在內):[^\x00-\xff]
應用:計算字符串的長度(一個雙字節字符長度計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函數,我們就可以利用這個表達式來實現,如下:
應用:javascript中沒有像vbscript那樣的trim函數,我們就可以利用這個表達式來實現,如下:String.prototype.trim = function()
{
return this.replace(/(^\s*)|(\s*$)/g, "");
}
利用正則表達式分解和轉換IP地址:
下面是利用正則表達式匹配IP地址,并將IP地址轉換成對應數值的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函數來分解可能更簡單,程序如下:
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+)*
匹配網址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) //結果為:abcefgi
我原來在CSDN上發貼尋求一個表達式來實現去除重復字符的方法,最終沒有找到,這是我能想到的最簡單的實現方法。思路是使用后向引用取出包括重復的字符,再以重復的字符建立第二個表達式,取到不重復的字符,兩者串連。這個方法對于字符順序有要求的字符串可能不適用。
得用正則表達式從URL地址中提取文件名的javascript程序,如下結果為page1
s="http://www.9499.net/page1.htm"
s=s.replace(/(.*\/){0,}([^\.]+).*/ig,"$2")
alert(s)
利用正則表達式限制網頁表單里的文本框輸入內容:
用正則表達式限制只能輸入中文: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,''))"
用正則表達式限制只能輸入數字:onkeyup="value=value.replace(/[^\d]/g,'') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))"
用正則表達式限制只能輸入數字和英文:onkeyup="value=value.replace(/[\W]/g,'') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))"
正則表達式,正規表達式,正則表達式匹配,正則表達式語法,模式匹配,正規表達式匹配 javascript正則表達式 ASP正則表達式 ASP.NET正則表達式 C#正則表達式 JSP正則表達式 PHP正則表達式 VB.NET正則表達式 VBSCript正則表達式編程 delphi正則表達式 jscript
正則表達式 regular expression
正則表達式 RegExp
模式 pattern
匹配 Match
.NET命名空間: System.Text.RegularExpression
補充:
^\d+$ //匹配非負整數(正整數 + 0)
^[0-9]*[1-9][0-9]*$ //匹配正整數
^((-\d+)|(0+))$ //匹配非正整數(負整數 + 0)
^-[0-9]*[1-9][0-9]*$ //匹配負整數
^-?\d+$ //匹配整數
^\d+(\.\d+)?$ //匹配非負浮點數(正浮點數 + 0)
^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$ //匹配正浮點數
^((-\d+(\.\d+)?)|(0+(\.0+)?))$ //匹配非正浮點數(負浮點數 + 0)
^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$ //匹配負浮點數
^(-?\d+)(\.\d+)?$ //匹配浮點數
^[A-Za-z]+$ //匹配由26個英文字母組成的字符串
^[A-Z]+$ //匹配由26個英文字母的大寫組成的字符串
^[a-z]+$ //匹配由26個英文字母的小寫組成的字符串
^[A-Za-z0-9]+$ //匹配由數字和26個英文字母組成的字符串
^\w+$ //匹配由數字、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) //結果為:abcefgi
===============================
如果var s = "abacabefggeeii"
結果就不對了,結果為:abeicfgg
正則表達式的能力有限
RE: totoro
謝謝你的指點,這個javascript正則表達式程序算法確實有問題,我會試著找更好的辦法!!!
1.確認有效電子郵件格式
下面的代碼示例使用靜態 Regex.IsMatch 方法驗證一個字符串是否為有效電子郵件格式。如果字符串包含一個有效的電子郵件地址,則 IsValidEmail 方法返回 true,否則返回 false,但不采取其他任何操作。您可以使用 IsValidEmail,在應用程序將地址存儲在數據庫中或顯示在 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.清理輸入字符串
下面的代碼示例使用靜態 Regex.Replace 方法從字符串中抽出無效字符。您可以使用這里定義的 CleanInput 方法,清除掉在接受用戶輸入的窗體的文本字段中輸入的可能有害的字符。CleanInput 在清除掉除 @、-(連字符)和 .(句點)以外的所有非字母數字字符后返回一個字符串。
[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>...) 組捕獲的子字符串。
有幾種靜態函數使您可以在使用正則表達式操作時無需創建顯式正則表達式對象,而 Regex.Replace 函數正是其中之一。如果您不想保留編譯的正則表達式,這將給您帶來方便
4.提取 URL 信息
以下代碼示例使用 Match.Result 來從 URL 提取協議和端口號。例如,"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}");
}
普通字符由所有那些未顯式指定為元字符的打印和非打印字符組成。這包括所有的大寫和小寫字母字符,所有數字,所有標點符號以及一些符號。
最簡單的正則表達式是一個單獨的普通字符,可以匹配所搜索字符串中的該字符本身。例如,單字符模式 'A' 可以匹配所搜索字符串中任何位置出現的字母 'A'。這里有一些單字符正則表達式模式的示例:
/a/ /7/ /M/
等價的 VBScript 單字符正則表達式為:
"a" "7" "M"
可以將多個單字符組合在一起得到一個較大的表達式。例如,下面的 JScript 正則表達式不是別的,就是通過組合單字符表達式 'a'、'7'以及 'M' 所創建出來的一個表達式。
/a7M/
等價的 VBScript 表達式為:
"a7M"
請注意這里沒有連接操作符。所需要做的就是將一個字符放在了另一個字符后面。
有不少元字符在試圖對其進行匹配時需要進行特殊的處理。要匹配這些特殊字符,必須首先將這些字符轉義,也就是在前面使用一個反斜杠 (\)。下表給出了這些特殊字符及其含義:
特殊字符 | 說明 |
---|---|
$ | 匹配輸入字符串的結尾位置。如果設置了 RegExp 對象的 Multiline 屬性,則 $ 也匹配 '\n' 或 '\r'。要匹配 $ 字符本身,請使用 \$。 |
( ) | 標記一個子表達式的開始和結束位置。子表達式可以獲取供以后使用。要匹配這些字符,請使用 \( 和 \)。 |
* | 匹配前面的子表達式零次或多次。要匹配 * 字符,請使用 \*。 |
+ | 匹配前面的子表達式一次或多次。要匹配 + 字符,請使用 \+。 |
. | 匹配除換行符 \n之外的任何單字符。要匹配 .,請使用 \。 |
[ | 標記一個中括號表達式的開始。要匹配 [,請使用 \[。 |
? | 匹配前面的子表達式零次或一次,或指明一個非貪婪限定符。要匹配 ? 字符,請使用 \?。 |
\ | 將下一個字符標記為或特殊字符、或原義字符、或后向引用、或八進制轉義符。例如, 'n' 匹配字符 'n'。'\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"
如果試圖匹配一個包含文件名的字符串,其中句點 (.) 是輸入字符串的一部分,則可以在正則表達式中的句點前面加上一個反斜杠 (\) 字符來實現這一要求。舉例來說,下面的 JScript 正則表達式就能匹配 'filename.ext':
/filename\.ext/
對 VBScript 而言,等價的表達式如下所示:
"filename\.ext"
這些表達式仍然是相當有限的。它們只允許匹配任何單字符。很多情況下,對從列表中匹配特殊字符十分有用。例如,如果輸入文字中包含用數字表示為Chapter 1, Chapter 2諸如此類的章節標題,你可能需要找到這些章節標題。
可以在一個方括號 ([ 和 ]) 中放入一個或多個單字符,來創建一個待匹配的列表。如果字符被放入括號中括起來,則該列表稱為括號表達式。括號內和其他任何地方一樣,普通字符代表其本身,也就是說,它們匹配輸入文字中出現的一處自己。大多數特殊字符在位于括號表達式中時都將失去其含義。這里有一些例外:
括號表達式中所包含的字符只匹配該括號表達式在正則表達式中所處位置的一個單字符。下面的 JScript 正則表達式可以匹配 'Chapter 1'、'Chapter 2'、'Chapter 3'、'Chapter 4' 以及 'Chapter 5':
/Chapter [12345]/
在 VBScript 中要匹配同樣的章節標題,請使用下面的表達式:
"Chapter [12345]"
請注意單詞 'Chapter' 及后面的空格與括號內的字符的位置關系是固定的。因此,括號表達式只用來指定滿足緊跟在單詞 'Chapter' 和一個空格之后的單字符位置的字符集合。這里是第九個字符位置。
如果希望使用范圍而不是字符本身來表示待匹配的字符,則可以使用連字符將該范圍的開始和結束字符分開。每個字符的字符值將決定其在一個范圍內的相對順序。下面的 JScript 正則表達式包含了一個等價于上面所示的括號列表的范圍表達式。
/Chapter [1-5]/
VBScipt 中相同功能的表達式如下所示:
"Chapter [1-5]"
如果以這種方式指定范圍,則開始和結束值都包括在該范圍內。有一點特別需要注意的是,在 Unicode 排序中起始值一定要在結束值之前。
如果想在括號表達式中包括連字符,則必須使用下述方法之一:
[\-]
[-a-z] [a-z-]
[!--] [!-~]
同樣,通過在列表開始處放置一個插入符(^),就可以查找所有不在列表或范圍中的字符。如果該插入符出現在列表的其他位置,則匹配其本身,沒有任何特殊含義。下面的 JScript 正則表達式匹配章節號大于 5 的章節標題:
/Chapter [^12345]/
對 VBScript 則使用:
"Chapter [^12345]"
在上面所示的示例中,表達式將匹配第九個位置處除1, 2, 3, 4, or 5 之外的任何數字字符。因此, 'Chapter 7' 為一個匹配,同樣 'Chapter 9' 也是如此。
上面的表達式可以使用連字符 (-) 表示。對 JScript 為:
/Chapter [^1-5]/
或者,對 VBScript 為:
"Chapter [^1-5]"
括號表達式的典型用法是指定對任何大寫或小寫字母字符或任何數字的匹配。下面的 JScript 表達式給出了這一匹配:
/[A-Za-z0-9]/
等價的 VBScript 表達式為:
"[A-Za-z0-9]"
推薦:
Hibernate中文手冊》作者認為要學Hibernate看這個就足夠了,里面幾乎包括了所有的細節,不過可能不太適合快速入門。
地址:http://www.hibernate.org/hib_docs/v3/reference/zh-%20cn/html_single/
關于struts的資料就很多了,這里推薦一個可以下載一些入門教程的網站。
地址:http://www.wnetw.com/jclub/index.jsp
強烈建議入門的朋友先了解一下基本的原理!否則本文可能對你沒有任何幫助。
相關工具下載:(注意版本)
mysql5.0 http://www.mysql.org/
eclipse 3.1.1 http://www.eclipse.org/
myeclipse4.0.3 http://www.myeclipseide.com/
tomcat5.5
安裝:
關于tomcat和mysql的安裝就不多說了,需要注意的是最好保證你的 jdk是1.5的版本,并配置好你的環境變量,不然可能會遇到一些問題。
把eclipse解開,再去安裝剛下載的myeclipse,在安裝的時候需要把路徑指定到剛才解開的eclipse上,由于myeclipse是個收費軟件,所以需要注冊。不過一般按照Chinese的習慣,去google一個注冊碼就可以了:}
開發環境部署:
好了,現在保證你的mysql和tomcat服務能夠正常啟動,myeclipse能夠正常打開(如果不能,可以去找一下相關的說明或者給作者留言)。下面我們就要開始真正的開始部署一個傳說中的tomcat+struts+hibernate+mysql結構的工程了!(faint!前言就寫的我好累)
首先,在myeclipse里新建一個工程。在左邊的Package Exporler面版里點右鍵選擇new->project…
在跳出菜單里選擇MyEclipse->J2EE Projects->Web Project。
點擊next后進入如下畫面:
工程名為:test
結束后點擊Finish。
好了,如果成功的話你就會在 Package Exporler里看到一個新的test工程!現在我們先配置一下數據庫方面的東西。首先在你的mysql 里建立一個數據庫webases,再在里面新建一個表admin,里面三個字段分別為id,name,password其中id為自動取值的主鍵(mysql具體的操作可以自己找資料,不是本文涉及范圍)。
再回到myeclipse ,選中window->Open Perspective->Other…
可以看到現在跳出一個名為Select Perspective的菜單,在里面選中MyEclipse Databases Exporler,可以看到現在到了下面的頁面。
按以上圖示輸入相關字段后點擊Finish便建立了一個數據庫連接,在新出現的JDBC for Mysql上點右鍵,選擇Open connection…,確認用戶名和密碼正確后點OK,如果一切順利的話你會看到下面的畫面:
這說明你已經和數據庫建立了正確的連接。現在我們再回到window->Open Perspective- >Other…里的MyEclipse,也就是我們剛進來的時候看到的畫面。
右鍵點擊你剛建立的工程 test并選擇MyEclipse->Add struts Capabilities…在跳出的菜單里按照如下輸入并確定:
好了,現在你已經為你的工程增加了struts,接下來和上面一樣在右鍵工程后選擇MyEclipse- >Add Hibernate Capabilities…一路確定下來為你的工程添加Hibernate。(為方便起見我們在選擇路徑時把HibernateSessionFactory.java放在了src/com下面,其實最好建立個單獨的目錄如 src/com/hibernate)
為了更好的演示我們不建立通常的登陸頁面而是建立個注冊頁面。選擇 src目錄下的hibernate.cfg.xml文件。照如下填寫并保存。這樣hibernate就為你建立了數據庫的連接池。
下面我們再選擇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就是下面這個樣子:
下面我們轉到hibernate。換到剛才我們建立數據庫的頁面,選擇你的admin的表點右鍵選擇Create Hibernate Mapping。選擇好打包路徑后選擇Finish。如圖:
在你剛才選擇的路徑下(我為方便是src/com/yourcompanyname/)下新建立的文件 AdminDAOFactory.java文件并輸入以下內容:
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",如下圖: 好了,我們的配置工作基本結束了,在myeclipse上開啟tomcat服務 現在打開瀏覽器,輸入
<%@ 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做如下設定:
http://127.0.0.1:8080/test/addAdmin.jsp就可以看到你的jsp頁面了!
]]>
一、前言
J2EE和.NET是目前企業級運用的兩大陣營,誰優誰劣各有說法。筆者是做J2EE方向的,覺得J2EE比起.NET最大的優勢就是其經過長實踐發展總結出來的大量模式和大量先進的框架。這些框架許多都是開源的——開源也是J2EE陣營的另一優勢。本篇文章的主角就是目前J2EE web應用中最流行的兩大開源框架——Hibernate和Struts。
二、相關概念與工具介紹
下面我將分別對本文“三大主角”所涉及到相關概念進行說明。
Hibernate及相關知識介紹
Hibernate:
中文意思是"冬眠“,呵呵,不知道設計者為何用這個名字。它是一個開源的ORM框架(關于ORM下文還會講解),它是通過對JDBC API進行封裝從而實現對java對象持久化的。有人可能要問:JDBC其實不難操作,為什么還要封裝它哪?其實答案很簡單,因為現在通用的數據庫都是關系數據庫,我們通過JDBC操作無法做到OOP,所以Hibernate將JDBC封裝起來,并且提供了一套OO化的Hibernate API供頂層操作。Hibernate現在幾乎已經成為ORM的公認標準了(剛推出的EJB 3.0標準中使用的ORM事實上就是Hibernate)
ORM:
這里解釋下ORM。ORM是一種模式(關于模式,筆者之前在這里發表過一篇介紹工廠模式的文章,讀者可以看看),它的英文是Object-Relation Mapping,中譯為對象-關系映射,它指的是“在單個組建中負責所有實體域對象的持久化,封裝數據訪問細節”(注:此定義來自《精通Hibernate:java對象持久化技術詳解》,孫衛琴,電子工業出版社)。筆者的覺得很容易理解:把關系數據庫對象化。
Struts及相關知識介紹
Struts:
Struts是由著名的Apache基金會開發的開源項目。中譯為“框架”,顧名思義,它就是一種MVC框架。眾所周知,MVC是一種業務邏輯與表示分離的模式,在java web上的應用十分廣泛。以前MVC的主要表現形式是JSP Model2,也就是JSP+Servlet+Javabean的應用,而近年來Struts的應用越來越廣泛,目前已經是最流行的MVC框架了。
MVC:
Model-View-Controller,中譯為模型-視圖-控制器。MVC不是真正意義上的軟件設計模式,而更是一種解決方案,它把軟件系統的所有業務邏輯方面的編程交給了Model,把所有UI視圖的設計和編程交給了View,再用Controller控制器控制Model并生成相應的View,從而真正實現了業務邏輯與用戶界面的分離。
Eclipse介紹
Eclipse是由IBM公司開發出來,后來又免費捐獻出來的開源工具,是一套主要用于Java開發的IDE(Eclipse通過添加某些插件可以實現對UML、C++等的開發)。Eclipse具有強大的擴展功能,加上其開源的特性,導致許多愛好者和公司為其開發了非常優秀的插件,Myeclipse就是其中之一。Myeclipse是面向J2EE開發者的Eclipse插件,功能強大,好用。本文的實例就是基于Eclipse+Myeclipse環境下開發出來的。
創建/運行本文實例除了安裝以上工具和插件外還需要安裝一個Web容器,本文使用的是Jboss,筆者可以自行選擇使用Tomcat或Weblogic等,這些對運行本文實例影響不大。
本文選擇的數據庫是SQLServer2000,關于Mysql、Oracle等其他數據庫的操作方法類似。
關于Eclipse下載和安裝方法本文不做介紹,請讀者自行在網上查找相關方法。
三、實例需求與總體設計
1、需求定義
由于本文的目的是介紹在Eclipse IDE下開發Struts+Hibernate的具體方法,而不是介紹項目開發/軟件設計的技巧,所以本文實例需求非常簡單。
本文實例是一個web留言簿,可以讓匿名用戶發表一些留言信息,并保存至數據庫。做過web開發的朋友肯定做過這類實例,非常經典。由于實例簡單并且容易理解,所以筆者也省去畫用例圖說明的步驟。
2、總體設計
本實例按傳統J2EE web項目的設計方法,分為5層架構,自底向上分別是:數據庫層 -> ORM層(Hibernate層) -> 業務邏輯層 -> 控制層(Struts Action) -> 視圖表示層。
數據庫的DDL語句如下:
四、持久化層與業務層實踐(Hibernate實踐)
好,戲肉開始。
1、先打開Eclipse。點擊“新建項目”->“Web Project”,出現如下窗口,在窗口中Project Name填入“Memo”作為項目名:
?
2、點擊“窗口”->“打開透視圖”->“其他”,出現如下窗口,雙擊“Myeclipse Database Explorer”,切換到如下視圖:
3、在“DB Browser”控制面板點擊“new”,新建一個數據庫連接。在彈出的窗口中點擊“new driver”新建一個數據庫連接驅動。如下圖:
4、上一步后回到以下視圖,在列表中選擇上一步創建的驅動,填入相關數據庫資料,點擊確定即可。(此步驟前必須已經打開數據庫,最后已經按照本實例的DDL創建了庫和表)
5、完成上一步后出現以下視圖。點擊“memo”的右鍵,點擊“open connetion”->“確定”。如果上述步驟成功的話這里會連接到數據庫,并顯示相關的數據庫結構。
成功后如下圖:
6、點擊“窗口”->“打開透視圖”->“其他”->“Myeclipse”切換到項目控制視圖。在項目名上點擊右鍵->“myeclipse”->“Add Hibernate capabilites”,出現以下視圖,并按下圖填入相關信息:
點下一步后出現如下框圖,按圖片上內容填寫:
提交后出現以下視圖,按圖片內容填寫:
7、在項目名上點擊右鍵->“myeclipse”->“Add Struts capabilites”,出現下面視圖,按圖中內容天下:
8、點擊“窗口”->“打開透視圖”->“其他”,出現如下窗口,雙擊“Myeclipse Database Explorer”,切換到數據庫管理視圖,找到我們為本次實例創建的表格,點右鍵->“create hibernate mapping”后出現下圖,按圖上內容填寫:
9、至此Hibernate的創建工作已經完成,如下圖,接下來我們寫個DAO工廠類來操作Hibernate API。
點擊com.woden包,新建個類,如下圖:
輸入以下代碼:
以上只有一個插入方法,如果讀者需要更多方法可以在DAO中自行添加。
至此,數據庫層、ORM層和業務層的代碼已經完成。
五、控制層與表示層實踐(Struts實踐)
1、新建一個welcome.jsp文件,作為實例的首頁。具體方法是在“webroot”文件夾圖標點右鍵->new->“jsp”,接下來填寫的東西很簡單就不用介紹了吧。
2、在上一步驟的第7步中已經在myeclipse中導入了struts,我們下面就可以開始編輯設置我們的struts實例。打開webboot目錄下WEB-INF中的struts配置文件“struts-config.xml”,如下圖:
3、在屏幕空白處點右鍵->“new”->“new form,action and jsp”,會出現如下視圖,按下圖提示填寫內容:
這里記得點擊“jsp”標簽條,出現以下界面,按下圖設置:
4、上一步驟設置了form,點擊下一步看到如下視圖,按下圖設置,具體步驟是:點擊“foward”標簽->“add”->name填“success”,path選擇“welcome.jsp”,其他不用填->確定。
5、上一步驟點擊了“完成”后出現下圖:
6、這一步驟是設置資源文件,為了struts的國際化和錯誤提示做準備。找到項目文件夾中src(源文件夾),找到ApplicationResourse.properties,雙擊打開,如下圖所示配置:(注:這里筆者安裝了一個免費的ascii轉unicode的插件)
如果讀者沒有安裝ascii自動轉unicode組建,可以直接copy我轉換后的資源文件內容:
7、下面打開com.woden.form.MemoForm.java文件,輸入以下代碼:
8、上面已經寫出了ActionForm的代碼,具體代碼筆者在這里不解釋,我想看過struts基礎的朋友都應該很清楚了,下面貼處Action的代碼:
9、最后編輯下幾個相關jsp文件的內容,分別如下:
至此,本實例完成。
六、發布與運行
1、在項目文件點右鍵->“myeclipse”->“Add and remove project deployment”,如下圖:
2、點擊圖標,選擇“Jboss”->“start”(注:這里如果用的是tomcat也類似操作,關于服務器配置的方法這里不祥談,請讀者自行在網上查找相關資料),會發現控制臺會輸出類似如下信息:
打開瀏覽器,輸入:http://localhost:8080/ 后如果出現下圖證明啟動成功:
3、輸入網址:http://localhost:8080/Memo/addmemo.jsp ,會看到效果圖如下圖:
4、按照正常流程和非正常流程分別留言一次,呵呵,效果出來沒有?如果沒有出現預期效果請檢查前面步驟。
七、寫在最后
在本文最后,筆者再次強調,本文的目的是介紹Eclipse IDE關于創建Struts+Hibernate應用的方法,而不是介紹j2ee框架的概念和運用,更不是介紹java設計與模式。本文對IDE的配置、服務器配置的方法也沒做詳細介紹,因為這都不是本文重點。對以上知識想了解多點的讀者可以google一下。
本文的實例只是一個入門,強調的是一種方法,而不是強調功能,所以本文的實例只有一個簡單的錄入功能。在看完本文后讀者可以添加更多的功能(我想,當這一架構搭建起來后,添加功能已經是相當容易的事情了)。
當一個代碼項目大了以后,每次重新編譯,打包,測試等都會變得非常復雜而且重復,因此c語言中有make腳本來幫助這些工作的批量完成。在Java中應用是平臺無關性的,當然不會用平臺相關的make腳本來完成這些批處理任務了,ANT本身就是這樣一個流程腳本引擎,用于自動化調用程序完成項目的編譯,打包,測試等。除了基于JAVA是平臺無關的外,腳本的格式是基于XML的,比make腳本來說還要好維護一些。
每個ant腳本(缺省叫build.xml)中設置了一系列任務(target):比如對于一個一般的項目可能需要有以下任務。
<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 --> |
缺省任務:usage 打印幫助文檔,告訴有那些任務選項:可用的有build, jar, javadoc和clean.
初始化環境變量:init
所有任務都基于一些基本環境變量的設置初始化完成,是后續其他任務的基礎,在環境初始化過程中,有2點比較可以方便設置:
1 除了使用卻缺省的property設置了JAVA源路徑和輸出路徑外,引用了一個外部的build.properties文件中的設置,
<property file="${basedir}/build.properties" />
這樣大部分簡單配置用戶只要會看懂build.properties就可以了,畢竟XML比起key value的屬性文件還是要可讀性差一些。用build.properties也可以方便其他用戶從編譯的細節中解放出來。
2 CLASSPATH設置:使用了其中的:
<path id="classpath"> <pathelement path="${jsdk_jar}"/> <fileset dir="${lib.dir}"> <include name="**/*.jar"/> </fileset> </path> |
則相當于設置了:CLASSPATH=/path/to/resin/lib/jsdk23.jar;/path/to/project/lib/*.jar;
文件復制:prepare-src
創建臨時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> |
編譯任務:build
編譯時的CLASSPATH環境通過一下方式找到引用一個path對象
<classpath refid="classpath"/> |
打包任務:jar
對應用打包生成項目所寫名的.jar文件
<!-- =================================================================== --> <!-- Creates the class package --> <!-- =================================================================== --> <target name="jar" depends="build"> <jar jarfile="${lib.dir}/${name}.jar" basedir="${build.dest}" includes="**"/> </target> 生成JAVADOC文檔任務: 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:
更多任務/擴展:(樣例)
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();
}
}
}
綠色字體為修改部份
現在剩下最后的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>
現在可以進行測試了!
在編寫代碼有配置內容時一定要注意 hibernate 和 hibernate3 ,這兩個包的名字就只差一個字,千萬不要有錯,否則找錯誤可是很難的。