在Ruby中,一切都是對象。對于那些喜歡使用高度面向?qū)ο蟮恼Z言(例如Smalltalk,Eiffel或CLOS)的用戶來說,這是非常受歡迎的。例如1,2,3或10.8等等都是對象,而不是如Java或C++中的原始類型;字符串是對象,類和方法也都是對象。例如,下面都是有效的Ruby代碼(在Ruby中,注釋行是以"#"符號界定的):
#對象-34的絕對值 -34.abs #對一個浮點數(shù)進行四舍五入處理 10.8.round #返回一個字符串對象的大寫且逆轉(zhuǎn)的副本 "This?is?Ruby".upcase.reverse #返回數(shù)學(xué)sin方法的參數(shù)個數(shù) Math.method(:sin).arity
|
?
圖5.Ruby是全對象化的:在Ruby中,整數(shù),浮點數(shù),字符串,甚至類和方法都是對象。這里的代碼展示了針對這些類型對象的方法調(diào)用。
在Ruby中,所有功能都是通過調(diào)用對象上的方法(或操作)實現(xiàn)的。事實上,Ruby中的方法調(diào)用就象其它程序語言中的函數(shù)或過程調(diào)用一樣。
就象在所有面向?qū)ο蟪绦蛘Z言中一樣,對象是從類中創(chuàng)建的。Ruby庫中提供了許多預(yù)構(gòu)建的類。你可以修改這些類或構(gòu)建你自己的類。Ruby中的類是使用"class"關(guān)鍵字定義的。類名開始是一個大寫字母。類定義以"end"關(guān)鍵字結(jié)束。因此,一個Rectangle類的定義可能有如下形式:
為了把方法添加到類,可以使用def關(guān)鍵字。方法的定義也應(yīng)該以end關(guān)鍵字結(jié)束。跟隨def關(guān)鍵字和方法名后面就是方法參數(shù)。把一個area方法添加到上面的Rectangle類的代碼看上去如下所示:
class?Rectangle def?area?(hgt,wdth) return?hgt*wdth end end? |
對于那些熟悉其它程序語言的用戶,他可能注意到一些差別。Ruby并不使用任何花括號來限定類或方法,也不使用分號或其它字符來表示程序語句行的結(jié)束。Ruby的目標,根據(jù)它的創(chuàng)建者說明,是簡單、易用并使編碼成為一件"趣事"。誰想記住所有的那些分號?沒有意思!在Ruby中,只要你把語句放在一行上,不需要分號或其它代碼行結(jié)束標記。順便說一下,在area方法參數(shù)周圍的括號是不必要的。在默認情況下,Ruby返回一個方法中最后的內(nèi)容,因此return關(guān)鍵字也可以省略。因此,你可以建立如下簡單編碼的Rectangle類:
class?Rectangle def?area?hgt,?wdth hgt*wdth end end |
? 盡管上面代碼是有效的,但是小括號還是被推薦使用于方法參數(shù)表達的,這主要是為了實現(xiàn)較好的可讀性。
?????? 實例變量和屬性
類也可以有實例變量(在一些語言中也稱為屬性)。例如,由Rectangle類創(chuàng)建的對象應(yīng)該都有一個高度和寬度。在Ruby中,實例變量不必顯式地在類中聲明,只是必須在它們的命名中以一個特殊字符來標記和使用。具體地說,所有的實例變量名都以"@"開頭。為了實現(xiàn)當(dāng)調(diào)用area方法時,存儲矩形實例的高度和寬度,你僅需把實例變量添加到area方法即可:
class?Rectangle def?area?(hgt,?wdth) @height=hgt @width?=?wdth @height*@width end end |
? 更確切地說,當(dāng)創(chuàng)建一個Rectangle實例時,應(yīng)該指定高度和寬度,而實例變量在此時才確定。另外,Ruby提供了一種特殊的方法initialize,它允許你建立或準備類的新實例:
class?Rectangle def?initialize?(hgt,?wdth) @height?=?hgt @width?=?wdth end def?area?() @height*@width end end |
為了創(chuàng)建一個新的Rectangle對象或?qū)嵗?,你要調(diào)用標準的Ruby類構(gòu)造器方法"new":
?
或,你可以使用沒有括號的形式:
?
這個例子創(chuàng)建了一個新的Rectangle對象并且調(diào)用了initialize方法,其中傳入?yún)?shù)4和7。注意,在下面的代碼中添加了height和width方法以便共享高度和寬度信息:
class?Rectangle def?initialize?(hgt,?wdth) @height?=?hgt @width?=?wdth end def?height return?@height end def?width return?@width end def?area?() @height*@width end end |
?
同樣,為了使另外某個方法能夠更新或設(shè)置一個Rectangle對象的高度和寬度,需要定義其它一些設(shè)置方法:
class?Rectangle def?initialize?(hgt,?wdth) @height?=?hgt @width?=?wdth end def?height return?@height end def?height=(newHgt) @height=newHgt end def?width return?@width end def?width=(newWdth) @width=newWdth end def?area?() @height*@width end end |
?
譯者注 本文中的mutator和accessor相當(dāng)于其它語言中的setter和getter。
上面的mutator方法("height="和"width=")可能看起來有點神秘,但是它們確實只是一些方法。不要讓命名中的等號蒙騙了你。在方法名最后的額外字符對于Ruby并不意味著什么,但是它提高了代碼的可讀性。請看下列代碼:
?
在此,一個Rectangle對象的高度正被賦值(改變)。事實上,這僅是一個對Rectangle對象的"height="方法的調(diào)用。
因為授予到一個對象的實例變量的存取權(quán)限非常普通,所以Ruby提供了一組關(guān)鍵字來實現(xiàn)一次性定義實例變量和accessor/mutator方法,從而使這些實例變量成為"public"屬性。這些關(guān)鍵字是attr_reader,attr_accessor。它們有助于極大地簡化代碼:
class?Rectangle attr_accessor?:height,?:width def?initialize?(hgt,?wdth) @height?=?hgt @width?=?wdth end def?area?() @height*@width end end |
?
在上面的示例代碼中,attr_accessor給出了Rectangle相應(yīng)于height和width屬性的getter和setter。
用交互式Ruby構(gòu)建應(yīng)用程序 現(xiàn)在,你已經(jīng)知道如何構(gòu)建一個簡單的Ruby應(yīng)用程序。為了展示Ruby解釋器的交互性,讓我們啟動一個交互的Ruby幫助和控制臺工具(使用Ruby安裝的fxri工具),見圖6。

圖6.啟動fxri:從Windows開始菜單中打開交互式Ruby工具fxri。
在窗口的右下方是一個交互式的Ruby命令提示符(即"irb(main):001:0>"),它在窗口打開時顯示出來。你可以進入到irb命令提示符行中并輸入"Rectangle.new(6,5).area()"。之后,你應(yīng)該看到如下結(jié)果:
irb(main):013:0>?Rectangle.new(6,5).area() =>?30 |
?
簡潔有力!
在Ruby中,類從來不關(guān)閉。這意味著,你總是可以在一個現(xiàn)有類上添加或重定義方法。例如,你還可以在你創(chuàng)建的Rectangle類上添加一個circumference方法。在命令提示符上,請逐行輸入下列代碼:
class?Rectangle def?circumference?() @height?*?2?+?@width?*?2 end end |
?

圖7.輸入Rectangle類:把Rectangle類的定義輸入到fxri交互式Ruby解釋器中,見圖中的右下方。
Rectangle類又被定義了一次?不,Ruby解釋器知道你正在修改當(dāng)前的Rectangle類,它把一個新方法添加到現(xiàn)有Rectangle類中?,F(xiàn)在,在命令提示符上輸入下列一行:"Rectangle.new(2,3).circumference()"。你應(yīng)該看到類似如下的結(jié)果:
irb(main):014:0>?class?Rectangle irb(main):015:1>?def?circumference() irb(main):016:2>?@height?*?2?+?@width?*?2 irb(main):017:2>?end irb(main):018:1>?end =>?nil irb(main):019:0>?Rectangle.new(2,3).circumference =>?10 |
?
為了重新定義Rectangle類中的任何方法,例如area方法,只需簡單地重新輸入具有新的area方法定義的類定義即可:
irb(main):020:0>?class?Rectangle irb(main):021:1>?def?area() irb(main):022:2>?@height*2 irb(main):023:2>?end irb(main):024:1>?end =>?nil irb(main):025:0>?Rectangle.new(6,5).area =>?12 |
?
在上面的簡單例子中,area方法被重新定義以便總是返回原來高度的2倍。
一個類永遠不會被關(guān)閉的思想可以應(yīng)用于你自己定義的類和該語言中的內(nèi)嵌類中。為了說明問題,讓我們把一個area方法添加到String類。在命令提示符中輸入下列代碼:
class?String def?area() length() end end |
?
現(xiàn)在,你在定義一個字符串的"area"方法以返回該字符串的長度。現(xiàn)在,你可以把你的名字作為一個字符串來試用一下這個新方法,見下面代碼:
irb(main):026:0>?class?String irb(main):027:1>?def?area() irb(main):028:2>?length() irb(main):029:2>?end irb(main):030:1>?end =>?nil irb(main):031:0>?"Jim".area =>?3? |
在本文示例中,我們使用Ruby的交互式特性及其開發(fā)環(huán)境來測試這種語言,而且我們僅使用了較小的代碼片斷。
Ruby是一種面向?qū)ο蟮脑幊陶Z言,是它讓許多開發(fā)者感到驚訝,甚至令他們提出這樣的疑問:是否真正存在比Java和C#更好的語言?本文將對Ruby語言作初步的探討并試圖回答這一問題。
一、 引言
你是否聽說過Ruby?如今,它成了軟件開發(fā)界的一個流行話題。該語言在去年春天的一次Java會議上引起我的注意,當(dāng)時象Bruce Tate,Dave Thomas等著名人物都在談?wù)揜uby并且告訴在場的觀眾Ruby值得一看。
現(xiàn)在,如果你象我一樣正在從事軟件開發(fā),那么我們就有共識:盡管學(xué)習(xí)一種新的編程語言可能是一件趣事,但是只有你對它具有深入了解之后,你才有資格以一種懷疑眼光來看待另一種編程語言。畢竟,在上世紀八、九十年代的編程語言之爭最終得出結(jié)論-從根本上看存在兩大陣營:Java世界和微軟基于.NET支持的開發(fā)語言。并不是我不想學(xué)習(xí)另一種語言,其實我只是期望通過選擇其它編程語言才能獲得一定技術(shù)優(yōu)勢的日子早點結(jié)束。然而,由于前面幾位著名人士的影響,我決定一試Ruby。
好,假定"我已經(jīng)到過山頂",那么本文就是我對Ruby的研究報告。
二、 安裝Ruby
Ruby是一種開源的編程語言,由日本的Yukihiro Matsumoto在九十年代中期開發(fā)。你可以在www.ruby-lang.org站點得到Ruby。這種語言最初被作為一種腳本語言創(chuàng)建,可應(yīng)用于許多平臺上,包括Linux、各種類UNIX、MS-DOS、Windows、BeOS、Amiga、Acorn Risc OS和MacOS X。當(dāng)前Ruby的最新版本是1.8.4。對于使用Windows平臺的用戶,你可以點按這里來得到一個"one-click"型Windows安裝程序。隨同基本的Ruby二進制文件和庫文件,這一下載中還包含一些有用的(并且是免費的)IDE和工具,包括幫助文檔和示例代碼,RubyGems包管理器,F(xiàn)reeRIDE(免費的Ruby IDE),F(xiàn)ox GUI庫,fxri(一種搜索引擎和Ruby文檔的GUI指南,還有一個交互式命令行工具)和SciTE(Scintilla文本編輯器IDE)。在寫本文時,Windows安裝程序所提供的Ruby的"穩(wěn)定"版本是1.8.2,還有一個1.8.4版本的預(yù)覽版。注意,本文中的示例代碼是用Windows安裝程序所提供的1.8.2版本編寫的。
使用Windows安裝程序安裝Ruby是相當(dāng)直接的事情。你只要下載并運行一個簡單的可執(zhí)行安裝文件(ruby182-15.exe),這個程序就會啟動一個標準的安裝向?qū)АO螺d文件大約有15MB,在向?qū)О裄uby安裝到Windows平臺上后占大約40MB的硬盤空間。
對于那些偏愛自己的編輯器的程序員,大量的編輯器都提供了對Ruby的支持,包括emacs,vim,JEdit,Jed,Nedit和Textpad。當(dāng)然,還有著名的Ruby Eclipse工程。Ruby開發(fā)工具(RDT)是一種Eclipse插件,當(dāng)前仍處于早期開發(fā)中,但是你可以從此處下載試用它。另外,市場上還有一些便宜的Ruby IDE,Arachno Ruby就是其中之一。
運行Ruby
就象許多解釋性語言一樣,Ruby提供給程序員多種開發(fā)代碼的方法。你可以使用命令行工具以交互方式運行Ruby或者創(chuàng)建一個Ruby程序文件,然后要求Ruby的解釋器執(zhí)行此程序。
在Windows中,打開命令行提示符窗口,在提示符上輸入"Ruby"并回車(注意:你應(yīng)該能夠使系統(tǒng)沿Ruby的\bin目錄找到Ruby可執(zhí)行文件)。那么,Ruby就會運行并等候你輸入程序。輸入下面的程序,然后按Ctrl+D再按回車鍵,你就會看到Ruby執(zhí)行你的程序,如圖1所示。
def convertCtoF (celsius) print(celsius.to_s + " degrees celsius is " + ((celsius * 9)/5 + 32).to_s + " degrees in fahrenheit\n") end convertCtoF(20) |

圖1.在Ruby中以交互方式運行攝氏到華氏溫度轉(zhuǎn)換計算
圖1中的轉(zhuǎn)換程序也可以用一種Ruby IDE或簡單文本編輯器實現(xiàn)并保存到一個文件中-例如convertCtoF.rb(.rb是Ruby程序的常用文件類型)?,F(xiàn)在,Ruby解釋器將執(zhí)行這個文件中的Ruby程序,見圖2。

圖2.運行convertCtoF.rb
那些熟悉Smalltalk,Common Lisp Object System(CLOS),或其它解釋性編程環(huán)境的用戶肯定都會熟悉交互的開發(fā)環(huán)境。交互特點允許你用小塊編程代碼進行試驗。通過使用一個特殊的Ruby批處理文件irb.bat,你就能夠克服Ruby解釋器的非交互性特征。圖3顯示了使用irb.bat命令啟動的Ruby。現(xiàn)在,代碼可以被逐行地輸入,解釋和測試。

圖3.交互式Ruby
交互式Ruby特征也被嵌入到若干工具中。例如,Ruby文檔的圖形接口fxri,不僅可作為一種語言指南,而且可以用作一種交互式Ruby解釋器(見圖4)。

圖4.fxri的交互式Ruby能力:在此,fxri也用來運行和圖3相同的Ruby命令,但這是從文檔工具內(nèi)部運行的。
摘要: 1?
?
J2EE
多層應(yīng)用分析
1.1? ???????
J2EE
層次結(jié)構(gòu)
J2EE
的三層結(jié)構(gòu)在業(yè)界是指表示...
閱讀全文
你正在學(xué)習(xí)CSS布局嗎?是不是還不能完全掌握純CSS布局?通常有兩種情況阻礙你的學(xué)習(xí):
第一種可能是你還沒有理解CSS處理頁面的原理。在你考慮你的頁面整體表現(xiàn)效果前,你應(yīng)當(dāng)先考慮內(nèi)容的語義和結(jié)構(gòu),然后再針對語義、結(jié)構(gòu)添加CSS。這篇文章將告訴你應(yīng)該怎樣把HTML結(jié)構(gòu)化。
另一種原因是你對那些非常熟悉的表現(xiàn)層屬性(例如:cellpadding,、hspace、align="left"等等)束手無策,不知道該轉(zhuǎn)換成對 應(yīng)的什么CSS語句。 當(dāng)你解決了第一種問題,知道了如何結(jié)構(gòu)化你的HTML,我再給出一個列表,詳細列出原來的表現(xiàn)屬性用什么CSS來代替。
結(jié)構(gòu)化HTML
我們在剛學(xué)習(xí)網(wǎng)頁制作時,總是先考慮怎么設(shè)計,考慮那些圖片、字體、顏色、以及布局方案。然后我們用Photoshop或者Fireworks畫出來、切割成小圖。最后再通過編輯HTML將所有設(shè)計還原表現(xiàn)在頁面上。
如果你希望你的HTML頁面用CSS布局(是CSS-friendly的),你需要回頭重來,先不考慮“外觀”,要先思考你的頁面內(nèi)容的語義和結(jié)構(gòu)。
外觀并不是最重要的。一個結(jié)構(gòu)良好的HTML頁面可以以任何外觀表現(xiàn)出來,CSS Zen Garden是一個典型的例子。CSS Zen Garden幫助我們最終認識到CSS的強大力量。
HTML不僅僅只在電腦屏幕上閱讀。你用photoshop精心設(shè)計的畫面可能不能顯示在PDA、移動電話和屏幕閱讀機上。但是一個結(jié)構(gòu)良好的HTML頁面可以通過CSS的不同定義,顯示在任何地方,任何網(wǎng)絡(luò)設(shè)備上。
開始思考
首先要學(xué)習(xí)什么是"結(jié)構(gòu)",一些作家也稱之為"語義"。這個術(shù)語的意思是你需要分析你的內(nèi)容塊,以及每塊內(nèi)容服務(wù)的目的,然后再根據(jù)這些內(nèi)容目的建立起相應(yīng)的HTML結(jié)構(gòu)。
如果你坐下來仔細分析和規(guī)劃你的頁面結(jié)構(gòu),你可能得到類似這樣的幾塊:
標志和站點名稱
主頁面內(nèi)容
站點導(dǎo)航(主菜單)
子菜單
搜索框
功能區(qū)(例如購物車、收銀臺)
頁腳(版權(quán)和有關(guān)法律聲明)
我們通常采用DIV元素來將這些結(jié)構(gòu)定義出來,類似這樣:
<div id="header"></div>
<div id="content"></div>
<div id="globalnav"></div>
<div id="subnav"></div>
<div id="search"></div>
<div id="shop"></div>
<div id="footer"></div>
這不是布局,是結(jié)構(gòu)。這是一個對內(nèi)容塊的語義說明。當(dāng)你理解了你的結(jié)構(gòu),就可以加對應(yīng)的ID在DIV上。DIV容器中可以包含任何內(nèi)容塊,也可以嵌套另一個DIV。內(nèi)容塊可以包含任意的HTML元素---標題、段落、圖片、表格、列表等等。
根據(jù)上面講述的,你已經(jīng)知道如何結(jié)構(gòu)化HTML,現(xiàn)在你可以進行布局和樣式定義了。每一個內(nèi)容塊都可以放在頁面上任何地方,再指定這個塊的顏色、字體、邊框、背景以及對齊屬性等等。
使用選擇器是件美妙的事
id的名稱是控制某一內(nèi)容塊的手段,通過給這個內(nèi)容塊套上DIV并加上唯一的id,你就可以用CSS選擇器來精確定義每一個頁面元素的外觀表現(xiàn),包括標 題、列表、圖片、鏈接或者段落等等。例如你為#header寫一個CSS規(guī)則,就可以完全不同于#content里的圖片規(guī)則。
另外一個例子是:你可以通過不同規(guī)則來定義不同內(nèi)容塊里的鏈接樣式。類似這樣:#globalnav a:link或者 #subnav a:link或者#content a:link。你也可以定義不同內(nèi)容塊中相同元素的樣式不一樣。例如,通過#content p和#footer p分別定義#content和#footer中p的樣式。從結(jié)構(gòu)上講,你的頁面是由圖片、鏈接、列表、段落等組成的,這些元素本身并不會對顯示在什么網(wǎng)絡(luò) 設(shè)備中(PDA還是手機或者網(wǎng)絡(luò)電視)有影響,它們可以被定義為任何的表現(xiàn)外觀。
一個仔細結(jié)構(gòu)化的HTML頁面非常簡單,每一個元素都被用于結(jié)構(gòu)目的。當(dāng)你想縮進一個段落,不需要使用blockquote標簽,只要使用p標簽,并對p 加一個CSS的margin規(guī)則就可以實現(xiàn)縮進目的。p是結(jié)構(gòu)化標簽,margin是表現(xiàn)屬性,前者屬于HTML,后者屬于CSS。(這就是結(jié)構(gòu)于表現(xiàn)的 相分離.)
良好結(jié)構(gòu)的HTML頁面內(nèi)幾乎沒有表現(xiàn)屬性的標簽。代碼非常干凈簡潔。例如,原先的代碼<table width="80%" cellpadding="3" border="2" align="left">,現(xiàn)在可以只在HTML中寫<table>,所有控制表現(xiàn)的東西都寫到CSS中去,在結(jié)構(gòu)化的HTML中, table就是表格,而不是其他什么(比如被用來布局和定位)。
親自實踐一下結(jié)構(gòu)化
上面說的只是最基本的結(jié)構(gòu),實際應(yīng)用中,你可以根據(jù)需要來調(diào)整內(nèi)容塊。常常會出現(xiàn)DIV嵌套的情況,你會看到"container"層中又有其它層,結(jié)構(gòu)類似這樣:
<div id="navcontainer">
<div id="globalnav">
<ul>a list</ul>
</div>
<div id="subnav">
<ul>another list</ul>
</div>
</div>
嵌套的div元素允許你定義更多的CSS規(guī)則來控制表現(xiàn),例如:你可以給#navcontainer一個規(guī)則讓列表居右,再給#globalnav一個規(guī)則讓列表居左,而給#subnav的list另一個完全不同的表現(xiàn)。
用CSS替換傳統(tǒng)方法
下面的列表將幫助你用CSS替換傳統(tǒng)方法:
HTML屬性以及相對應(yīng)的CSS方法
HTML屬性
CSS方法說明
align="left"
align="right" float: left;
float: right; 使用CSS可以浮動 任何元素:圖片、段落、div、標題、表格、列表等等
當(dāng)你使用float屬性,必須給這個浮動元素定義一個寬度。
marginwidth="0" leftmargin="0" marginheight="0" topmargin="0" margin: 0; 使用CSS, margin可以設(shè)置在任何元素上, 不僅僅是body元素.更重要的,你可以分別指定元素的top, right, bottom和left的margin值。
vlink="#333399" alink="#000000" link="#3333FF" a:link #3ff;
a:visited: #339;
a:hover: #999;
a:active: #00f;
在HTML中,鏈接的顏色作為body的一個屬性值定義。整個頁面的鏈接風(fēng)格都一樣。使用CSS的選擇器,頁面不同部分的鏈接樣式可以不一樣。
bgcolor="#FFFFFF" background-color: #fff; 在CSS中,任何元素都可以定義背景顏色,不僅僅局限于body和table元素。
bordercolor="#FFFFFF" border-color: #fff; 任何元素都可以設(shè)置邊框(boeder),你可以分別定義top, right, bottom和left
border="3"cellspacing="3" border-width: 3px; 用CSS,你可以定義table的邊框為統(tǒng)一樣式,也可以分別定義top, right, bottom and left邊框的顏色、尺寸和樣式。
你可以使用 table, td or th 這些選擇器.
如果你需要設(shè)置無邊框效果,可以使用CSS定義: border-collapse: collapse;
<br clear="left">
<br clear="right">
<br clear="all">
clear: left;
clear: right;
clear: both;
許多2列或者3列布局都使用 float屬性來定位。如果你在浮動層中定義了背景顏色或者背景圖片,你可以使用clear屬性.
cellpadding="3"
vspace="3"
hspace="3" padding: 3px; 用CSS,任何元素都可以設(shè)定padding屬性,同樣,padding可以分別設(shè)置top, right, bottom and left。padding是透明的。
align="center" text-align: center;
margin-right: auto; margin-left: auto;
Text-align 只適用于文本.
象div,p這樣的塊級可以通過margin-right: auto; 和margin-left: auto;來水平居中
一些令人遺憾的技巧和工作環(huán)境
由于瀏覽器對CSS支持的不完善,我們有時候不得不采取一些技巧(hacks)或建立一種環(huán)境(Workarounds)來讓CSS實現(xiàn)傳統(tǒng)方法同樣的效 果。例如塊級元素有時侯需要使用水平居中的技巧,盒模型bug的技巧等等。所有這些技巧都在Molly Holzschlag的文章《Integrated Web Design: Strategies for Long-Term CSS Hack Management》中有詳細說明
Spring?MVC?框架。用銀行示例介紹如何建模和構(gòu)建簡單的應(yīng)用程序。示例應(yīng)用程序包含了已經(jīng)學(xué)過的一些技術(shù)(例如依賴注入),但是主要演示?Spring?MVC?的特性。
在開始之前,請?下載這篇文章的源代碼。請參閱?參考資料?訪問?Spring?框架和?Tom
cat?5.0,運行示例需要它們。
Spring?MVC?框架
Spring?框架提供了構(gòu)建?Web?應(yīng)用程序的全功能?MVC?模塊。使用?Spring?可插入的?MVC?架構(gòu),可以選擇是使用內(nèi)置的?Spring?Web?框架還是?Struts?這樣的?Web?框架。通過策略接口,Spring?框架是高度可配置的,而且包含多種視圖技術(shù),例如?JavaServer?Pages(JSP)技術(shù)、Velocity、Tiles、iText?和?POI。Spring?MVC?框架并不知道使用的視圖,所以不會強迫您只使用?JSP?技術(shù)。Spring?MVC?分離了控制器、模型對象、分派器以及處理程序?qū)ο蟮慕巧@種分離讓它們更容易進行定制。
Spring?的?Web?MVC?框架是圍繞?DispatcherServlet?設(shè)計的,它把請求分派給處理程序,同時帶有可配置的處理程序映射、視圖解析、本地語言、主題解析以及上載文件支持。默認的處理程序是非常簡單的?Controller?接口,只有一個方法?ModelAndView?handleRequest(request,?response)。Spring?提供了一個控制器層次結(jié)構(gòu),可以派生子類。如果應(yīng)用程序需要處理用戶輸入表單,那么可以繼承?AbstractFormController。如果需要把多頁輸入處理到一個表單,那么可以繼承?AbstractWizardFormController。
示例應(yīng)用程序有助于直觀地學(xué)習(xí)這些特性。銀行應(yīng)用程序允許用戶檢索他們的帳戶信息。在構(gòu)建銀行應(yīng)用程序的過程中,可以學(xué)到如何配置?Spring?MVC?框架和實現(xiàn)框架的視圖層,視圖層包括?JSTL?標記(用于顯示輸出的數(shù)據(jù))和JavaServer?Pages?技術(shù)。
配置?Spring?MVC
要開始構(gòu)建示例應(yīng)用程序,請配置?Spring?MVC?的?DispatcherServlet。請在?web.xml?文件中注冊所有配置。清單?1?顯示了如何配置?sampleBankingServlet。
清單?1.?配置?Spring?MVC?DispatcherServlet
<servlet>
<servlet-name>sampleBankingServlet</servlet-name>
<servlet-class>
org.springframework.we.servlet.DispatcherServlet
<servlet-class>
<load-on-startup>1<load-on-startup>
<servlet>
DispatcherServlet?從一個?XML?文件裝入?Spring?應(yīng)用程序上下文,XML?文件的名稱是?servlet?的名稱后面加上?-servlet?。在這個示例中,DispatcherServlet?會從?sampleBankingServlet-servlet.xml?文件裝入應(yīng)用程序上下文。
配置應(yīng)用程序的?URL
下一步是配置想讓?sampleBankingServlet?處理的?URL。同樣,還是要在?web.xml?中注冊所有這些信息。
清單?2.?配置想要處理的?URL
<servlet-mapping>
<servlet-name>?sampleBankingServlet<servlet-name>
<url-pattern>*.jsp</url-pattern>
</servlet-mapping>
裝入配置文件
下面,裝入配置文件。為了做到這點,請為?Servlet?2.3?規(guī)范注冊?ContextLoaderListener?或為?Servlet?2.2?及以下的容器注冊?ContextLoaderServlet。為了保障后向兼容性,請用?ContextLoaderServlet。在啟動?Web?應(yīng)用程序時,ContextLoaderServlet?會裝入?Spring?配置文件。清單?3?注冊了?ContextLoaderServlet。
清單?3.?注冊?ContextLoaderServlet
<servlet>
<servlet-name>context>servlet-name>
<servlet-class>
org.springframework.web.context.ContextLoaderServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
contextConfigLocation?參數(shù)定義了要裝入的?Spring?配置文件,如下面的?servlet?上下文所示。
<context-param>
<param-value>contextConfigLocation</param-value>
<param-value>/WEB-INF/sampleBanking-services.xml</param-value>
</context-param>
sampleBanking-services.xml?文件代表示例銀行應(yīng)用程序服務(wù)的配置和?bean?配置。如果想裝入多個配置文件,可以在?<param-value>?標記中用逗號作分隔符。
Spring?MVC?示例
示例銀行應(yīng)用程序允許用戶根據(jù)惟一的?ID?和口令查看帳戶信息。雖然?Spring?MVC?提供了其他選項,但是我將采用?JSP?技術(shù)作為視圖頁面。這個簡單的應(yīng)用程序包含一個視圖頁用于用戶輸入(ID?和口令),另一頁顯示用戶的帳戶信息。
我從?LoginBankController?開始,它擴展了?Spring?MVC?的?SimpleFormController。SimpleFormContoller?提供了顯示從?HTTP?GET?請求接收到的表單的功能,以及處理從?HTTP?POST?接收到的相同表單數(shù)據(jù)的功能。LoginBankController?用?AuthenticationService?和?AccountServices?服務(wù)進行驗證,并執(zhí)行帳戶活動?!?配置視圖屬性?”一節(jié)中的?清單?5?描述了如何把?AuthenticationService?和?AccountServices?連接到?LoginBankController。?清單?4?顯示了?LoginBankController?的代碼。
配置視圖屬性
下面,我必須注冊在接收到?HTTP?GET?請求時顯示的頁面。我在?Spring?配置中用?formView?屬性注冊這個頁面,如清單?5?所示。sucessView?屬性代表表單數(shù)據(jù)提交而且?doSubmitAction()?方法中的邏輯成功執(zhí)行之后顯示的頁面。formView?和?sucessView?屬性都代表被定義的視圖的邏輯名稱,邏輯名稱映射到實際的視圖頁面。
清單?5.?注冊?LoginBankController
<bean?id="loginBankController"
class="springexample.controller.LoginBankController">
<property?name="sessionForm"><value>true</value></property>
<property?name="commandName"><value>loginCommand</value></property>
<property?name="commandClass">
<value>springexample.commands.LoginCommand</value>
</property>
<property?name="authenticationService">
<ref?bean="authenticationService"?/>
</property>
<property?name="accountServices">
<ref?bean="accountServices"?/>
</property>
<property?name="formView">
<value>login</value>
</property>
<property?name="successView">
<value>accountdetail</value>
</property>
</bean>
commandClass?和?commandName?標記決定將在視圖頁面中活動的?bean。例如,可以通過?login.jsp?頁面訪問?loginCommand?bean,這個頁面是應(yīng)用程序的登錄頁面。一旦用戶提交了登錄頁面,應(yīng)用程序就可以從?LoginBankController?的?onSubmit()?方法中的命令對象檢索出表單數(shù)據(jù)。
視圖解析器
Spring?MVC?的?視圖解析器?把每個邏輯名稱解析成實際的資源,即包含帳戶信息的?JSP?文件。我用的是?Spring?的?InternalResourceViewResolver,如?清單?6?所示。
因為我在?JSP?頁面中使用了?JSTL?標記,所以用戶的登錄名稱解析成資源?/jsp/login.jsp,而?viewClass?成為?JstlView。
驗證和帳戶服務(wù)
就像前面提到的,LoginBankController?內(nèi)部連接了?Spring?的?AccountServices?和?AuthenticationService。AuthenticationService?類處理銀行應(yīng)用程序的驗證。AccountServices?類處理典型的銀行服務(wù),例如查找交易和電匯。清單?7?顯示了銀行應(yīng)用程序的驗證和帳戶服務(wù)的配置。
清單?7.?配置驗證和帳戶服務(wù)
<beans>
<bean?id="accountServices"
class="springexample.services.AccountServices">
</bean>
<bean?id="authenticationService"
class="springexample.services.AuthenticationService">
</bean>
</beans>
以上服務(wù)在?sampleBanking-services.xml?中注冊,然后裝入?web.xml?文件中,就像?前面討論的那樣??刂破骱头?wù)配置好后,這個簡單的應(yīng)用程序就完成了?,F(xiàn)在我們來看看部署和測試它時會發(fā)生什么!
部署應(yīng)用程序
我把示例應(yīng)用程序部署在?Tomcat?servlet?容器中。Tomcat?是?Java?Servlet?和?Java?ServerPagest?技術(shù)的官方參考實現(xiàn)中使用的?servlet?容器。如果以前沒這么做過,請?下載?jakarta-tomcat-5.0.28.exe?并運行它把?Tomcat?安裝到自己喜歡的任何位置,例如?c:\tomcat5.0。
接下來,下載示例代碼?并釋放到驅(qū)動器(例如?c:\?)上。創(chuàng)建了?Spring?項目的文件夾之后,打開它并把?spring-banking?子文件夾拷貝到?c:\tomvat5.0\webapps。spring-banking?文件夾是一個?Web?檔案,里面包含?Spring?MVC?示例應(yīng)用程序。lib?文件夾包含應(yīng)用程序需要的?Spring?框架、與Spring?相關(guān)的?MVC?庫以及?JSTL?標記庫和?jar?文件。
要啟動?Tomcat?服務(wù)器,請使用以下命令:
cd?bin?C:\Tomcat?5.0\bin>?catalina.bat?start
Tomcat?應(yīng)當(dāng)啟動并部署?Spring?MVC?示例應(yīng)用程序。
測試應(yīng)用程序
要測試應(yīng)用程序,請打開?Web?瀏覽器,指向?
http://localhost:tomcatport/springbanking?并用?Tomcat?服務(wù)器實際運行的端口替換?tomcatport。應(yīng)當(dāng)看到圖?1?所示的登錄屏幕。輸入用戶?ID?“admin”和口令“password”,并按下登錄按鈕。其他用戶?ID?或口令會造成來自驗證服務(wù)的錯誤。
圖?1.?Spring?MVC?示例登錄屏幕

登錄成功之后,會看到圖?2?所示的帳戶細節(jié)頁面。
圖?2.?Spring?MVC?示例帳戶細節(jié)頁面
結(jié)束語
在三部分的?Spring?系列?的第三篇文章中,我介紹了?Spring?MVC?框架的特性。我演示了如何配置和開發(fā)?Spring?MVC?應(yīng)用程序、如何配置?Spring?MVC?控制器和向其中插入依賴項、如何用?JavaServer?Pages?技術(shù)開發(fā)應(yīng)用程序視圖,以及如何把自己的頁面與?Spring?MVC?的視圖層集成??偨Y(jié)這篇文章時,我演示了如何在?Tomcat?servlet?容器中部署應(yīng)用程序以及如何在瀏覽器中測試它。
引言
數(shù)據(jù)庫的設(shè)計范式是
數(shù)據(jù)庫設(shè)計所需要滿足的規(guī)范,滿足這些規(guī)范的
數(shù)據(jù)庫是簡潔的、結(jié)構(gòu)明晰的,同時,不會發(fā)生插入(insert)、刪除(delete)和更新(update)操作異常。反之則是亂七八糟,不僅給
數(shù)據(jù)庫的編程人員制造麻煩,而且面目可憎,可能存儲了大量不需要的冗余信息。
設(shè)計范式是不是很難懂呢?非也,大學(xué)教材上給我們一堆數(shù)學(xué)公式我們當(dāng)然看不懂,也記不住。所以我們很多人就根本不按照范式來設(shè)計
數(shù)據(jù)庫。
實質(zhì)上,設(shè)計范式用很形象、很簡潔的話語就能說清楚,道明白。本文將對范式進行通俗地說明,并以筆者曾經(jīng)設(shè)計的一個簡單論壇的
數(shù)據(jù)庫為例來講解怎樣將這些范式應(yīng)用于實際工程。
范式說明 第一范式(1NF):
數(shù)據(jù)庫表中的字段都是單一屬性的,不可再分。這個單一屬性由基本類型構(gòu)成,包括整型、實數(shù)、字符型、邏輯型、日期型等。
例如,如下的
數(shù)據(jù)庫表是符合第一范式的:
而這樣的
數(shù)據(jù)庫表是不符合第一范式的:
字段1 | 字段2 | 字段3 | 字段4 |
? | ? | 字段3.1 | 字段3.2 | ? |
很顯然,在當(dāng)前的任何關(guān)系數(shù)據(jù)庫管理系統(tǒng)(DBMS)中,傻瓜也不可能做出不符合第一范式的數(shù)據(jù)庫,因為這些DBMS不允許你把數(shù)據(jù)庫表的一列再分成二列或多列。因此,你想在現(xiàn)有的DBMS中設(shè)計出不符合第一范式的數(shù)據(jù)庫都是不可能的。
第二范式(2NF):數(shù)據(jù)庫表中不存在非關(guān)鍵字段對任一候選關(guān)鍵字段的部分函數(shù)依賴(部分函數(shù)依賴指的是存在組合關(guān)鍵字中的某些字段決定非關(guān)鍵字段的情況),也即所有非關(guān)鍵字段都完全依賴于任意一組候選關(guān)鍵字。假定選課關(guān)系表為SelectCourse(學(xué)號, 姓名, 年齡, 課程名稱, 成績, 學(xué)分),關(guān)鍵字為組合關(guān)鍵字(學(xué)號, 課程名稱),因為存在如下決定關(guān)系:
(學(xué)號, 課程名稱) → (姓名, 年齡, 成績, 學(xué)分)
這個數(shù)據(jù)庫表不滿足第二范式,因為存在如下決定關(guān)系:
(課程名稱) → (學(xué)分)
(學(xué)號) → (姓名, 年齡)
即存在組合關(guān)鍵字中的字段決定非關(guān)鍵字的情況。
由于不符合2NF,這個選課關(guān)系表會存在如下問題:
(1) 數(shù)據(jù)冗余:
同一門課程由n個學(xué)生選修,"學(xué)分"就重復(fù)n-1次;同一個學(xué)生選修了m門課程,姓名和年齡就重復(fù)了m-1次。
(2) 更新異常:
若調(diào)整了某門課程的學(xué)分,數(shù)據(jù)表中所有行的"學(xué)分"值都要更新,否則會出現(xiàn)同一門課程學(xué)分不同的情況。
(3) 插入異常:
假設(shè)要開設(shè)一門新的課程,暫時還沒有人選修。這樣,由于還沒有"學(xué)號"關(guān)鍵字,課程名稱和學(xué)分也無法記錄入數(shù)據(jù)庫。
(4) 刪除異常:
假設(shè)一批學(xué)生已經(jīng)完成課程的選修,這些選修記錄就應(yīng)該從數(shù)據(jù)庫表中刪除。但是,與此同時,課程名稱和學(xué)分信息也被刪除了。很顯然,這也會導(dǎo)致插入異常。
把選課關(guān)系表SelectCourse改為如下三個表:
學(xué)生:Student(學(xué)號, 姓名, 年齡);
課程:Course(課程名稱, 學(xué)分);
選課關(guān)系:SelectCourse(學(xué)號, 課程名稱, 成績)。
這樣的數(shù)據(jù)庫表是符合第二范式的,消除了數(shù)據(jù)冗余、更新異常、插入異常和刪除異常。
另外,所有單關(guān)鍵字的數(shù)據(jù)庫表都符合第二范式,因為不可能存在組合關(guān)鍵字。
第三范式(3NF):在第二范式的基礎(chǔ)上,數(shù)據(jù)表中如果不存在非關(guān)鍵字段對任一候選關(guān)鍵字段的傳遞函數(shù)依賴則符合第三范式。所謂傳遞函數(shù)依賴,指的是如果存在"A → B → C"的決定關(guān)系,則C傳遞函數(shù)依賴于A。因此,滿足第三范式的數(shù)據(jù)庫表應(yīng)該不存在如下依賴關(guān)系:
關(guān)鍵字段 → 非關(guān)鍵字段x → 非關(guān)鍵字段y
假定學(xué)生關(guān)系表為Student(學(xué)號, 姓名, 年齡, 所在學(xué)院, 學(xué)院地點, 學(xué)院電話),關(guān)鍵字為單一關(guān)鍵字"學(xué)號",因為存在如下決定關(guān)系:
(學(xué)號) → (姓名, 年齡, 所在學(xué)院, 學(xué)院地點, 學(xué)院電話)
這個數(shù)據(jù)庫是符合2NF的,但是不符合3NF,因為存在如下決定關(guān)系:
(學(xué)號) → (所在學(xué)院) → (學(xué)院地點, 學(xué)院電話)
即存在非關(guān)鍵字段"學(xué)院地點"、"學(xué)院電話"對關(guān)鍵字段"學(xué)號"的傳遞函數(shù)依賴。
它也會存在數(shù)據(jù)冗余、更新異常、插入異常和刪除異常的情況,讀者可自行分析得知。
把學(xué)生關(guān)系表分為如下兩個表:
學(xué)生:(學(xué)號, 姓名, 年齡, 所在學(xué)院);
學(xué)院:(學(xué)院, 地點, 電話)。
這樣的數(shù)據(jù)庫表是符合第三范式的,消除了數(shù)據(jù)冗余、更新異常、插入異常和刪除異常。
鮑依斯-科得范式(BCNF):在第三范式的基礎(chǔ)上,數(shù)據(jù)庫表中如果不存在任何字段對任一候選關(guān)鍵字段的傳遞函數(shù)依賴則符合第三范式。
假設(shè)倉庫管理關(guān)系表為StorehouseManage(倉庫ID, 存儲物品ID, 管理員ID, 數(shù)量),且有一個管理員只在一個倉庫工作;一個倉庫可以存儲多種物品。這個數(shù)據(jù)庫表中存在如下決定關(guān)系:
(倉庫ID, 存儲物品ID) →(管理員ID, 數(shù)量)
(管理員ID, 存儲物品ID) → (倉庫ID, 數(shù)量)
所以,(倉庫ID, 存儲物品ID)和(管理員ID, 存儲物品ID)都是StorehouseManage的候選關(guān)鍵字,表中的唯一非關(guān)鍵字段為數(shù)量,它是符合第三范式的。但是,由于存在如下決定關(guān)系:
(倉庫ID) → (管理員ID)
(管理員ID) → (倉庫ID)
即存在關(guān)鍵字段決定關(guān)鍵字段的情況,所以其不符合BCNF范式。它會出現(xiàn)如下異常情況:
(1) 刪除異常:
當(dāng)倉庫被清空后,所有"存儲物品ID"和"數(shù)量"信息被刪除的同時,"倉庫ID"和"管理員ID"信息也被刪除了。
(2) 插入異常:
當(dāng)倉庫沒有存儲任何物品時,無法給倉庫分配管理員。
(3) 更新異常:
如果倉庫換了管理員,則表中所有行的管理員ID都要修改。
把倉庫管理關(guān)系表分解為二個關(guān)系表:
倉庫管理:StorehouseManage(倉庫ID, 管理員ID);
倉庫:Storehouse(倉庫ID, 存儲物品ID, 數(shù)量)。
這樣的數(shù)據(jù)庫表是符合BCNF范式的,消除了刪除異常、插入異常和更新異常。
范式應(yīng)用
我們來逐步搞定一個論壇的數(shù)據(jù)庫,有如下信息:
?。?) 用戶:用戶名,email,主頁,電話,聯(lián)系地址
?。?) 帖子:發(fā)帖標題,發(fā)帖內(nèi)容,回復(fù)標題,回復(fù)內(nèi)容
第一次我們將數(shù)據(jù)庫設(shè)計為僅僅存在表:
用戶名 | email | 主頁 | 電話 | 聯(lián)系地址 | 發(fā)帖標題 | 發(fā)帖內(nèi)容 | 回復(fù)標題 | 回復(fù)內(nèi)容 |
這個數(shù)據(jù)庫表符合第一范式,但是沒有任何一組候選關(guān)鍵字能決定數(shù)據(jù)庫表的整行,唯一的關(guān)鍵字段用戶名也不能完全決定整個元組。我們需要增加"發(fā)帖ID"、"回復(fù)ID"字段,即將表修改為:
用戶名 | email | 主頁 | 電話 | 聯(lián)系地址 | 發(fā)帖ID | 發(fā)帖標題 | 發(fā)帖內(nèi)容 | 回復(fù)ID | 回復(fù)標題 | 回復(fù)內(nèi)容 |
這樣數(shù)據(jù)表中的關(guān)鍵字(用戶名,發(fā)帖ID,回復(fù)ID)能決定整行:
(用戶名,發(fā)帖ID,回復(fù)ID) → (email,主頁,電話,聯(lián)系地址,發(fā)帖標題,發(fā)帖內(nèi)容,回復(fù)標題,回復(fù)內(nèi)容)
但是,這樣的設(shè)計不符合第二范式,因為存在如下決定關(guān)系:
(用戶名) → (email,主頁,電話,聯(lián)系地址)
(發(fā)帖ID) → (發(fā)帖標題,發(fā)帖內(nèi)容)
(回復(fù)ID) → (回復(fù)標題,回復(fù)內(nèi)容)
即非關(guān)鍵字段部分函數(shù)依賴于候選關(guān)鍵字段,很明顯,這個設(shè)計會導(dǎo)致大量的數(shù)據(jù)冗余和操作異常。
我們將數(shù)據(jù)庫表分解為(帶下劃線的為關(guān)鍵字):
(1) 用戶信息:用戶名,email,主頁,電話,聯(lián)系地址
(2) 帖子信息:發(fā)帖ID,標題,內(nèi)容
?。?) 回復(fù)信息:回復(fù)ID,標題,內(nèi)容
?。?) 發(fā)貼:用戶名,發(fā)帖ID
?。?) 回復(fù):發(fā)帖ID,回復(fù)ID
這樣的設(shè)計是滿足第1、2、3范式和BCNF范式要求的,但是這樣的設(shè)計是不是最好的呢?
不一定。
觀察可知,第4項"發(fā)帖"中的"用戶名"和"發(fā)帖ID"之間是1:N的關(guān)系,因此我們可以把"發(fā)帖"合并到第2項的"帖子信息"中;第5項"回復(fù)"中的 "發(fā)帖ID"和"回復(fù)ID"之間也是1:N的關(guān)系,因此我們可以把"回復(fù)"合并到第3項的"回復(fù)信息"中。這樣可以一定量地減少數(shù)據(jù)冗余,新的設(shè)計為:
?。?) 用戶信息:用戶名,email,主頁,電話,聯(lián)系地址
(2) 帖子信息:用戶名,發(fā)帖ID,標題,內(nèi)容
(3) 回復(fù)信息:發(fā)帖ID,回復(fù)ID,標題,內(nèi)容
數(shù)據(jù)庫表1顯然滿足所有范式的要求;
數(shù)據(jù)庫表2中存在非關(guān)鍵字段"標題"、"內(nèi)容"對關(guān)鍵字段"發(fā)帖ID"的部分函數(shù)依賴,即不滿足第二范式的要求,但是這一設(shè)計并不會導(dǎo)致數(shù)據(jù)冗余和操作異常;
數(shù)據(jù)庫表3中也存在非關(guān)鍵字段"標題"、"內(nèi)容"對關(guān)鍵字段"回復(fù)ID"的部分函數(shù)依賴,也不滿足第二范式的要求,但是與數(shù)據(jù)庫表2相似,這一設(shè)計也不會導(dǎo)致數(shù)據(jù)冗余和操作異常。
由此可以看出,并不一定要強行滿足范式的要求,對于1:N關(guān)系,當(dāng)1的一邊合并到N的那邊后,N的那邊就不再滿足第二范式了,但是這種設(shè)計反而比較好!
對于M:N的關(guān)系,不能將M一邊或N一邊合并到另一邊去,這樣會導(dǎo)致不符合范式要求,同時導(dǎo)致操作異常和數(shù)據(jù)冗余。
對于1:1的關(guān)系,我們可以將左邊的1或者右邊的1合并到另一邊去,設(shè)計導(dǎo)致不符合范式要求,但是并不會導(dǎo)致操作異常和數(shù)據(jù)冗余。
結(jié)論
滿足范式要求的數(shù)據(jù)庫設(shè)計是結(jié)構(gòu)清晰的,同時可避免數(shù)據(jù)冗余和操作異常。這并意味著不符合范式要求的設(shè)計一定是錯誤的,在數(shù)據(jù)庫表中存在1:1或1:N關(guān)系這種較特殊的情況下,合并導(dǎo)致的不符合范式要求反而是合理的。
在我們設(shè)計數(shù)據(jù)庫的時候,一定要時刻考慮范式的要求。
一、數(shù)據(jù)庫設(shè)計過程
數(shù)據(jù)庫技術(shù)是信息資源管理最有效的手段。數(shù)據(jù)庫設(shè)計是指對于一個給定的應(yīng)用環(huán)境,構(gòu)造最優(yōu)的數(shù)據(jù)庫模式,建立數(shù)據(jù)庫及其應(yīng)用系統(tǒng),有效存儲數(shù)據(jù),滿足用戶信息要求和處理要求。
數(shù)據(jù)庫設(shè)計中需求分析階段綜合各個用戶的應(yīng)用需求(現(xiàn)實世界的需求),在概念設(shè)計階段形成獨立于機器特點、獨立于各個DBMS產(chǎn)品的概念模式(信息世界模型),用E-R圖來描述。在邏輯設(shè)計階段將E-R圖轉(zhuǎn)換成具體的數(shù)據(jù)庫產(chǎn)品支持的數(shù)據(jù)模型如關(guān)系模型,形成數(shù)據(jù)庫邏輯模式。然后根據(jù)用戶處理的要求,安全性的考慮,在基本表的基礎(chǔ)上再建立必要的視圖(VIEW)形成數(shù)據(jù)的外模式。在物理設(shè)計階段根據(jù)DBMS特點和處理的需要,進行物理存儲安排,設(shè)計索引,形成數(shù)據(jù)庫內(nèi)模式。
1.?需求分析階段?
需求收集和分析,結(jié)果得到數(shù)據(jù)字典描述的數(shù)據(jù)需求(和數(shù)據(jù)流圖描述的處理需求)。?
需求分析的重點是調(diào)查、收集與分析用戶在數(shù)據(jù)管理中的信息要求、處理要求、安全性與完整性要求。
需求分析的方法:調(diào)查組織機構(gòu)情況、調(diào)查各部門的業(yè)務(wù)活動情況、協(xié)助用戶明確對新系統(tǒng)的各種要求、確定新系統(tǒng)的邊界。?
常用的調(diào)查方法有:?跟班作業(yè)、開調(diào)查會、請專人介紹、詢問、設(shè)計調(diào)查表請用戶填寫、查閱記錄。
分析和表達用戶需求的方法主要包括自頂向下和自底向上兩類方法。自頂向下的結(jié)構(gòu)化分析方法(Structured?Analysis,簡稱SA方法)從最上層的系統(tǒng)組織機構(gòu)入手,采用逐層分解的方式分析系統(tǒng),并把每一層用數(shù)據(jù)流圖和數(shù)據(jù)字典描述。
數(shù)據(jù)流圖表達了數(shù)據(jù)和處理過程的關(guān)系。系統(tǒng)中的數(shù)據(jù)則借助數(shù)據(jù)字典(Data?Dictionary,簡稱DD)來描述。
數(shù)據(jù)字典是各類數(shù)據(jù)描述的集合,它是關(guān)于數(shù)據(jù)庫中數(shù)據(jù)的描述,即元數(shù)據(jù),而不是數(shù)據(jù)本身。數(shù)據(jù)字典通常包括數(shù)據(jù)項、數(shù)據(jù)結(jié)構(gòu)、數(shù)據(jù)流、數(shù)據(jù)存儲和處理過程五個部分(至少應(yīng)該包含每個字段的數(shù)據(jù)類型和在每個表內(nèi)的主外鍵)。
數(shù)據(jù)項描述={數(shù)據(jù)項名,數(shù)據(jù)項含義說明,別名,數(shù)據(jù)類型,長度,?
取值范圍,取值含義,與其他數(shù)據(jù)項的邏輯關(guān)系}?
數(shù)據(jù)結(jié)構(gòu)描述={數(shù)據(jù)結(jié)構(gòu)名,含義說明,組成:{數(shù)據(jù)項或數(shù)據(jù)結(jié)構(gòu)}}?
數(shù)據(jù)流描述={數(shù)據(jù)流名,說明,數(shù)據(jù)流來源,數(shù)據(jù)流去向,?
組成:{數(shù)據(jù)結(jié)構(gòu)},平均流量,高峰期流量}?
數(shù)據(jù)存儲描述={數(shù)據(jù)存儲名,說明,編號,流入的數(shù)據(jù)流,流出的數(shù)據(jù)流,?
組成:{數(shù)據(jù)結(jié)構(gòu)},數(shù)據(jù)量,存取方式}?
處理過程描述={處理過程名,說明,輸入:{數(shù)據(jù)流},輸出:{數(shù)據(jù)流},?
處理:{簡要說明}}?
2.?概念結(jié)構(gòu)設(shè)計階段?
通過對用戶需求進行綜合、歸納與抽象,形成一個獨立于具體DBMS的概念模型,可以用E-R圖表示。?
概念模型用于信息世界的建模。概念模型不依賴于某一個DBMS支持的數(shù)據(jù)模型。概念模型可以轉(zhuǎn)換為計算機上某一DBMS支持的特定數(shù)據(jù)模型。?
概念模型特點:
(1)?具有較強的語義表達能力,能夠方便、直接地表達應(yīng)用中的各種語義知識。?
(2)?應(yīng)該簡單、清晰、易于用戶理解,是用戶與數(shù)據(jù)庫設(shè)計人員之間進行交流的語言。
概念模型設(shè)計的一種常用方法為IDEF1X方法,它就是把實體-聯(lián)系方法應(yīng)用到語義數(shù)據(jù)模型中的一種語義模型化技術(shù),用于建立系統(tǒng)信息模型。
????使用IDEF1X方法創(chuàng)建E-R模型的步驟如下所示:
2.1?第零步——初始化工程
這個階段的任務(wù)是從目的描述和范圍描述開始,確定建模目標,開發(fā)建模計劃,組織建模隊伍,收集源材料,制定約束和規(guī)范。收集源材料是這階段的重點。通過調(diào)查和觀察結(jié)果,業(yè)務(wù)流程,原有系統(tǒng)的輸入輸出,各種報表,收集原始數(shù)據(jù),形成了基本數(shù)據(jù)資料表。
2.2?第一步——定義實體
實體集成員都有一個共同的特征和屬性集,可以從收集的源材料——基本數(shù)據(jù)資料表中直接或間接標識出大部分實體。根據(jù)源材料名字表中表示物的術(shù)語以及具有“代碼”結(jié)尾的術(shù)語,如客戶代碼、代理商代碼、產(chǎn)品代碼等將其名詞部分代表的實體標識出來,從而初步找出潛在的實體,形成初步實體表。
2.3?第二步——定義聯(lián)系
IDEF1X模型中只允許二元聯(lián)系,n元聯(lián)系必須定義為n個二元聯(lián)系。根據(jù)實際的業(yè)務(wù)需求和規(guī)則,使用實體聯(lián)系矩陣來標識實體間的二元關(guān)系,然后根據(jù)實際情況確定出連接關(guān)系的勢、關(guān)系名和說明,確定關(guān)系類型,是標識關(guān)系、非標識關(guān)系(強制的或可選的)還是非確定關(guān)系、分類關(guān)系。如果子實體的每個實例都需要通過和父實體的關(guān)系來標識,則為標識關(guān)系,否則為非標識關(guān)系。非標識關(guān)系中,如果每個子實體的實例都與而且只與一個父實體關(guān)聯(lián),則為強制的,否則為非強制的。如果父實體與子實體代表的是同一現(xiàn)實對象,那么它們?yōu)榉诸愱P(guān)系。
2.4?第三步——定義碼
通過引入交叉實體除去上一階段產(chǎn)生的非確定關(guān)系,然后從非交叉實體和獨立實體開始標識侯選碼屬性,以便唯一識別每個實體的實例,再從侯選碼中確定主碼。為了確定主碼和關(guān)系的有效性,通過非空規(guī)則和非多值規(guī)則來保證,即一個實體實例的一個屬性不能是空值,也不能在同一個時刻有一個以上的值。找出誤認的確定關(guān)系,將實體進一步分解,最后構(gòu)造出IDEF1X模型的鍵基視圖(KB圖)。
2.5?第四步——定義屬性
從源數(shù)據(jù)表中抽取說明性的名詞開發(fā)出屬性表,確定屬性的所有者。定義非主碼屬性,檢查屬性的非空及非多值規(guī)則。此外,還要檢查完全依賴函數(shù)規(guī)則和非傳遞依賴規(guī)則,保證一個非主碼屬性必須依賴于主碼、整個主碼、僅僅是主碼。以此得到了至少符合關(guān)系理論第三范式的改進的IDEF1X模型的全屬性視圖。
2.6?第五步——定義其他對象和規(guī)則
????定義屬性的數(shù)據(jù)類型、長度、精度、非空、缺省值、約束規(guī)則等。定義觸發(fā)器、存儲過程、視圖、角色、同義詞、序列等對象信息。
3.?邏輯結(jié)構(gòu)設(shè)計階段?
????將概念結(jié)構(gòu)轉(zhuǎn)換為某個DBMS所支持的數(shù)據(jù)模型(例如關(guān)系模型),并對其進行優(yōu)化。設(shè)計邏輯結(jié)構(gòu)應(yīng)該選擇最適于描述與表達相應(yīng)概念結(jié)構(gòu)的數(shù)據(jù)模型,然后選擇最合適的DBMS。
將E-R圖轉(zhuǎn)換為關(guān)系模型實際上就是要將實體、實體的屬性和實體之間的聯(lián)系轉(zhuǎn)化為關(guān)系模式,這種轉(zhuǎn)換一般遵循如下原則:?
1)一個實體型轉(zhuǎn)換為一個關(guān)系模式。實體的屬性就是關(guān)系的屬性。實體的碼就是關(guān)系的碼。?
2)一個m:n聯(lián)系轉(zhuǎn)換為一個關(guān)系模式。與該聯(lián)系相連的各實體的碼以及聯(lián)系本身的屬性均轉(zhuǎn)換為關(guān)系的屬性。而關(guān)系的碼為各實體碼的組合。?
3)一個1:n聯(lián)系可以轉(zhuǎn)換為一個獨立的關(guān)系模式,也可以與n端對應(yīng)的關(guān)系模式合并。如果轉(zhuǎn)換為一個獨立的關(guān)系模式,則與該聯(lián)系相連的各實體的碼以及聯(lián)系本身的屬性均轉(zhuǎn)換為關(guān)系的屬性,而關(guān)系的碼為n端實體的碼。?
4)一個1:1聯(lián)系可以轉(zhuǎn)換為一個獨立的關(guān)系模式,也可以與任意一端對應(yīng)的關(guān)系模式合并。
5)三個或三個以上實體間的一個多元聯(lián)系轉(zhuǎn)換為一個關(guān)系模式。與該多元聯(lián)系相連的各實體的碼以及聯(lián)系本身的屬性均轉(zhuǎn)換為關(guān)系的屬性。而關(guān)系的碼為各實體碼的組合。??
6)同一實體集的實體間的聯(lián)系,即自聯(lián)系,也可按上述1:1、1:n和m:n三種情況分別處理。?
7)具有相同碼的關(guān)系模式可合并。?
為了進一步提高數(shù)據(jù)庫應(yīng)用系統(tǒng)的性能,通常以規(guī)范化理論為指導(dǎo),還應(yīng)該適當(dāng)?shù)匦薷?、調(diào)整數(shù)據(jù)模型的結(jié)構(gòu),這就是數(shù)據(jù)模型的優(yōu)化。確定數(shù)據(jù)依賴。消除冗余的聯(lián)系。確定各關(guān)系模式分別屬于第幾范式。確定是否要對它們進行合并或分解。一般來說將關(guān)系分解為3NF的標準,即:
表內(nèi)的每一個值都只能被表達一次。
??表內(nèi)的每一行都應(yīng)該被唯一的標識(有唯一鍵)。
表內(nèi)不應(yīng)該存儲依賴于其他鍵的非鍵信息。???
4.?數(shù)據(jù)庫物理設(shè)計階段?
為邏輯數(shù)據(jù)模型選取一個最適合應(yīng)用環(huán)境的物理結(jié)構(gòu)(包括存儲結(jié)構(gòu)和存取方法)。根據(jù)DBMS特點和處理的需要,進行物理存儲安排,設(shè)計索引,形成數(shù)據(jù)庫內(nèi)模式。
5.?數(shù)據(jù)庫實施階段?
運用DBMS提供的數(shù)據(jù)語言(例如SQL)及其宿主語言(例如C),根據(jù)邏輯設(shè)計和物理設(shè)計的結(jié)果建立數(shù)據(jù)庫,編制與調(diào)試應(yīng)用程序,組織數(shù)據(jù)入庫,并進行試運行。?數(shù)據(jù)庫實施主要包括以下工作:用DDL定義數(shù)據(jù)庫結(jié)構(gòu)、組織數(shù)據(jù)入庫?、編制與調(diào)試應(yīng)用程序、數(shù)據(jù)庫試運行??
6.?數(shù)據(jù)庫運行和維護階段?
數(shù)據(jù)庫應(yīng)用系統(tǒng)經(jīng)過試運行后即可投入正式運行。在數(shù)據(jù)庫系統(tǒng)運行過程中必須不斷地對其進行評價、調(diào)整與修改。包括:數(shù)據(jù)庫的轉(zhuǎn)儲和恢復(fù)、數(shù)據(jù)庫的安全性、完整性控制、數(shù)據(jù)庫性能的監(jiān)督、分析和改進、數(shù)據(jù)庫的重組織和重構(gòu)造。
建模工具的使用
為加快數(shù)據(jù)庫設(shè)計速度,目前有很多數(shù)據(jù)庫輔助工具(CASE工具),如Rational公司的Rational?Rose,CA公司的Erwin和Bpwin,Sybase公司的PowerDesigner以及Oracle公司的Oracle?Designer等。
ERwin主要用來建立數(shù)據(jù)庫的概念模型和物理模型。它能用圖形化的方式,描述出實體、聯(lián)系及實體的屬性。ERwin支持IDEF1X方法。通過使用ERwin建模工具自動生成、更改和分析IDEF1X模型,不僅能得到優(yōu)秀的業(yè)務(wù)功能和數(shù)據(jù)需求模型,而且可以實現(xiàn)從IDEF1X模型到數(shù)據(jù)庫物理設(shè)計的轉(zhuǎn)變。ERwin工具繪制的模型對應(yīng)于邏輯模型和物理模型兩種。在邏輯模型中,IDEF1X工具箱可以方便地用圖形化的方式構(gòu)建和繪制實體聯(lián)系及實體的屬性。在物理模型中,ERwin可以定義對應(yīng)的表、列,并可針對各種數(shù)據(jù)庫管理系統(tǒng)自動轉(zhuǎn)換為適當(dāng)?shù)念愋汀?br />設(shè)計人員可根據(jù)需要選用相應(yīng)的數(shù)據(jù)庫設(shè)計建模工具。例如需求分析完成之后,設(shè)計人員可以使用Erwin畫ER圖,將ER圖轉(zhuǎn)換為關(guān)系數(shù)據(jù)模型,生成數(shù)據(jù)庫結(jié)構(gòu);畫數(shù)據(jù)流圖,生成應(yīng)用程序。
二、數(shù)據(jù)庫設(shè)計技巧
1.?設(shè)計數(shù)據(jù)庫之前(需求分析階段)
1)?理解客戶需求,詢問用戶如何看待未來需求變化。讓客戶解釋其需求,而且隨著開發(fā)的繼續(xù),還要經(jīng)常詢問客戶保證其需求仍然在開發(fā)的目的之中。
2)?了解企業(yè)業(yè)務(wù)可以在以后的開發(fā)階段節(jié)約大量的時間。
3)?重視輸入輸出。
在定義數(shù)據(jù)庫表和字段需求(輸入)時,首先應(yīng)檢查現(xiàn)有的或者已經(jīng)設(shè)計出的報表、查詢和視圖(輸出)以決定為了支持這些輸出哪些是必要的表和字段。
舉例:假如客戶需要一個報表按照郵政編碼排序、分段和求和,你要保證其中包括了單獨的郵政編碼字段而不要把郵政編碼糅進地址字段里。
4)?創(chuàng)建數(shù)據(jù)字典和ER?圖表
ER?圖表和數(shù)據(jù)字典可以讓任何了解數(shù)據(jù)庫的人都明確如何從數(shù)據(jù)庫中獲得數(shù)據(jù)。ER圖對表明表之間關(guān)系很有用,而數(shù)據(jù)字典則說明了每個字段的用途以及任何可能存在的別名。對SQL?表達式的文檔化來說這是完全必要的。
5)?定義標準的對象命名規(guī)范
數(shù)據(jù)庫各種對象的命名必須規(guī)范。
2.?表和字段的設(shè)計(數(shù)據(jù)庫邏輯設(shè)計)
表設(shè)計原則
1)?標準化和規(guī)范化
數(shù)據(jù)的標準化有助于消除數(shù)據(jù)庫中的數(shù)據(jù)冗余。標準化有好幾種形式,但Third?Normal?Form(3NF)通常被認為在性能、擴展性和數(shù)據(jù)完整性方面達到了最好平衡。簡單來說,遵守3NF?標準的數(shù)據(jù)庫的表設(shè)計原則是:“One?Fact?in?One?Place”即某個表只包括其本身基本的屬性,當(dāng)不是它們本身所具有的屬性時需進行分解。表之間的關(guān)系通過外鍵相連接。它具有以下特點:有一組表專門存放通過鍵連接起來的關(guān)聯(lián)數(shù)據(jù)。
舉例:某個存放客戶及其有關(guān)定單的3NF?數(shù)據(jù)庫就可能有兩個表:Customer?和Order。Order?表不包含定單關(guān)聯(lián)客戶的任何信息,但表內(nèi)會存放一個鍵值,該鍵指向Customer?表里包含該客戶信息的那一行。
事實上,為了效率的緣故,對表不進行標準化有時也是必要的。
2)?數(shù)據(jù)驅(qū)動
采用數(shù)據(jù)驅(qū)動而非硬編碼的方式,許多策略變更和維護都會方便得多,大大增強系統(tǒng)的靈活性和擴展性。
舉例,假如用戶界面要訪問外部數(shù)據(jù)源(文件、XML?文檔、其他數(shù)據(jù)庫等),不妨把相應(yīng)的連接和路徑信息存儲在用戶界面支持表里。還有,如果用戶界面執(zhí)行工作流之類的任務(wù)(發(fā)送郵件、打印信箋、修改記錄狀態(tài)等),那么產(chǎn)生工作流的數(shù)據(jù)也可以存放在數(shù)據(jù)庫里。角色權(quán)限管理也可以通過數(shù)據(jù)驅(qū)動來完成。事實上,如果過程是數(shù)據(jù)驅(qū)動的,你就可以把相當(dāng)大的責(zé)任推給用戶,由用戶來維護自己的工作流過程。
3)?考慮各種變化
在設(shè)計數(shù)據(jù)庫的時候考慮到哪些數(shù)據(jù)字段將來可能會發(fā)生變更。
舉例,姓氏就是如此(注意是西方人的姓氏,比如女性結(jié)婚后從夫姓等)。所以,在建立系統(tǒng)存儲客戶信息時,在單獨的一個數(shù)據(jù)表里存儲姓氏字段,而且還附加起始日和終止日等字段,這樣就可以跟蹤這一數(shù)據(jù)條目的變化。
字段設(shè)計原則
4)?每個表中都應(yīng)該添加的3?個有用的字段
??dRecordCreationDate,在VB?下默認是Now(),而在SQL?Server?下默認為GETDATE()
??sRecordCreator,在SQL?Server?下默認為NOT?NULL?DEFAULT?USER
??nRecordVersion,記錄的版本標記;有助于準確說明記錄中出現(xiàn)null?數(shù)據(jù)或者丟失數(shù)據(jù)的原因
5)?對地址和電話采用多個字段
描述街道地址就短短一行記錄是不夠的。Address_Line1、Address_Line2?和Address_Line3?可以提供更大的靈活性。還有,電話號碼和郵件地址最好擁有自己的數(shù)據(jù)表,其間具有自身的類型和標記類別。
6)?使用角色實體定義屬于某類別的列
在需要對屬于特定類別或者具有特定角色的事物做定義時,可以用角色實體來創(chuàng)建特定的時間關(guān)聯(lián)關(guān)系,從而可以實現(xiàn)自我文檔化。
舉例:用PERSON?實體和PERSON_TYPE?實體來描述人員。比方說,當(dāng)John?Smith,?Engineer?提升為John?Smith,?Director?乃至最后爬到John?Smith,?CIO?的高位,而所有你要做的不過是改變兩個表PERSON?和PERSON_TYPE?之間關(guān)系的鍵值,同時增加一個日期/時間字段來知道變化是何時發(fā)生的。這樣,你的PERSON_TYPE?表就包含了所有PERSON?的可能類型,比如Associate、Engineer、Director、CIO?或者CEO?等。還有個替代辦法就是改變PERSON?記錄來反映新頭銜的變化,不過這樣一來在時間上無法跟蹤個人所處位置的具體時間。
7)?選擇數(shù)字類型和文本類型盡量充足
在SQL?中使用smallint?和tinyint?類型要特別小心。比如,假如想看看月銷售總額,總額字段類型是smallint,那么,如果總額超過了$32,767?就不能進行計算操作了。
而ID?類型的文本字段,比如客戶ID?或定單號等等都應(yīng)該設(shè)置得比一般想象更大。假設(shè)客戶ID?為10?位數(shù)長。那你應(yīng)該把數(shù)據(jù)庫表字段的長度設(shè)為12?或者13?個字符長。但這額外占據(jù)的空間卻無需將來重構(gòu)整個數(shù)據(jù)庫就可以實現(xiàn)數(shù)據(jù)庫規(guī)模的增長了。
8)?增加刪除標記字段
在表中包含一個“刪除標記”字段,這樣就可以把行標記為刪除。在關(guān)系數(shù)據(jù)庫里不要單獨刪除某一行;最好采用清除數(shù)據(jù)程序而且要仔細維護索引整體性。?
3.?選擇鍵和索引(數(shù)據(jù)庫邏輯設(shè)計)
鍵選擇原則:
1)?鍵設(shè)計4?原則
??為關(guān)聯(lián)字段創(chuàng)建外鍵。
??所有的鍵都必須唯一。
??避免使用復(fù)合鍵。
??外鍵總是關(guān)聯(lián)唯一的鍵字段。
2)?使用系統(tǒng)生成的主鍵
設(shè)計數(shù)據(jù)庫的時候采用系統(tǒng)生成的鍵作為主鍵,那么實際控制了數(shù)據(jù)庫的索引完整性。這樣,數(shù)據(jù)庫和非人工機制就有效地控制了對存儲數(shù)據(jù)中每一行的訪問。采用系統(tǒng)生成鍵作為主鍵還有一個優(yōu)點:當(dāng)擁有一致的鍵結(jié)構(gòu)時,找到邏輯缺陷很容易。
3)?不要用用戶的鍵(不讓主鍵具有可更新性)
在確定采用什么字段作為表的鍵的時候,可一定要小心用戶將要編輯的字段。通常的情況下不要選擇用戶可編輯的字段作為鍵。
4)?可選鍵有時可做主鍵
把可選鍵進一步用做主鍵,可以擁有建立強大索引的能力。
索引使用原則:
索引是從數(shù)據(jù)庫中獲取數(shù)據(jù)的最高效方式之一。95%的數(shù)據(jù)庫性能問題都可以采用索引技術(shù)得到解決。
1) 邏輯主鍵使用唯一的成組索引,對系統(tǒng)鍵(作為存儲過程)采用唯一的非成組索引,對任何外鍵列采用非成組索引。考慮數(shù)據(jù)庫的空間有多大,表如何進行訪問,還有這些訪問是否主要用作讀寫。
2) 大多數(shù)數(shù)據(jù)庫都索引自動創(chuàng)建的主鍵字段,但是可別忘了索引外鍵,它們也是經(jīng)常使用的鍵,比如運行查詢顯示主表和所有關(guān)聯(lián)表的某條記錄就用得上。
3) 不要索引memo/note?字段,不要索引大型字段(有很多字符),這樣作會讓索引占用太多的存儲空間。
4) 不要索引常用的小型表
不要為小型數(shù)據(jù)表設(shè)置任何鍵,假如它們經(jīng)常有插入和刪除操作就更別這樣作了。對這些插入和刪除操作的索引維護可能比掃描表空間消耗更多的時間。
4.?數(shù)據(jù)完整性設(shè)計(數(shù)據(jù)庫邏輯設(shè)計)
1) 完整性實現(xiàn)機制:
實體完整性:主鍵
參照完整性:
父表中刪除數(shù)據(jù):級聯(lián)刪除;受限刪除;置空值
父表中插入數(shù)據(jù):受限插入;遞歸插入
父表中更新數(shù)據(jù):級聯(lián)更新;受限更新;置空值
DBMS對參照完整性可以有兩種方法實現(xiàn):外鍵實現(xiàn)機制(約束規(guī)則)和觸發(fā)器實現(xiàn)機制
用戶定義完整性:
????NOT?NULL;CHECK;觸發(fā)器
2)?用約束而非商務(wù)規(guī)則強制數(shù)據(jù)完整性
采用數(shù)據(jù)庫系統(tǒng)實現(xiàn)數(shù)據(jù)的完整性。這不但包括通過標準化實現(xiàn)的完整性而且還包括數(shù)據(jù)的功能性。在寫數(shù)據(jù)的時候還可以增加觸發(fā)器來保證數(shù)據(jù)的正確性。不要依賴于商務(wù)層保證數(shù)據(jù)完整性;它不能保證表之間(外鍵)的完整性所以不能強加于其他完整性規(guī)則之上。
3)?強制指示完整性
在有害數(shù)據(jù)進入數(shù)據(jù)庫之前將其剔除。激活數(shù)據(jù)庫系統(tǒng)的指示完整性特性。這樣可以保持數(shù)據(jù)的清潔而能迫使開發(fā)人員投入更多的時間處理錯誤條件。
4)?使用查找控制數(shù)據(jù)完整性
控制數(shù)據(jù)完整性的最佳方式就是限制用戶的選擇。只要有可能都應(yīng)該提供給用戶一個清晰的價值列表供其選擇。這樣將減少鍵入代碼的錯誤和誤解同時提供數(shù)據(jù)的一致性。某些公共數(shù)據(jù)特別適合查找:國家代碼、狀態(tài)代碼等。
5)?采用視圖
為了在數(shù)據(jù)庫和應(yīng)用程序代碼之間提供另一層抽象,可以為應(yīng)用程序建立專門的視圖而不必非要應(yīng)用程序直接訪問數(shù)據(jù)表。這樣做還等于在處理數(shù)據(jù)庫變更時給你提供了更多的自由。
5.?其他設(shè)計技巧
1)?避免使用觸發(fā)器
觸發(fā)器的功能通??梢杂闷渌绞綄崿F(xiàn)。在調(diào)試程序時觸發(fā)器可能成為干擾。假如你確實需要采用觸發(fā)器,你最好集中對它文檔化。
2)?使用常用英語(或者其他任何語言)而不要使用編碼
在創(chuàng)建下拉菜單、列表、報表時最好按照英語名排序。假如需要編碼,可以在編碼旁附上用戶知道的英語。
3)?保存常用信息
讓一個表專門存放一般數(shù)據(jù)庫信息非常有用。在這個表里存放數(shù)據(jù)庫當(dāng)前版本、最近檢查/修復(fù)(對Access)、關(guān)聯(lián)設(shè)計文檔的名稱、客戶等信息。這樣可以實現(xiàn)一種簡單機制跟蹤數(shù)據(jù)庫,當(dāng)客戶抱怨他們的數(shù)據(jù)庫沒有達到希望的要求而與你聯(lián)系時,這樣做對非客戶機/服務(wù)器環(huán)境特別有用。
4)?包含版本機制
在數(shù)據(jù)庫中引入版本控制機制來確定使用中的數(shù)據(jù)庫的版本。時間一長,用戶的需求總是會改變的。最終可能會要求修改數(shù)據(jù)庫結(jié)構(gòu)。把版本信息直接存放到數(shù)據(jù)庫中更為方便。?
5)?編制文檔
對所有的快捷方式、命名規(guī)范、限制和函數(shù)都要編制文檔。
采用給表、列、觸發(fā)器等加注釋的數(shù)據(jù)庫工具。對開發(fā)、支持和跟蹤修改非常有用。
對數(shù)據(jù)庫文檔化,或者在數(shù)據(jù)庫自身的內(nèi)部或者單獨建立文檔。這樣,當(dāng)過了一年多時間后再回過頭來做第2?個版本,犯錯的機會將大大減少。
6)?測試、測試、反復(fù)測試
建立或者修訂數(shù)據(jù)庫之后,必須用用戶新輸入的數(shù)據(jù)測試數(shù)據(jù)字段。最重要的是,讓用戶進行測試并且同用戶一道保證選擇的數(shù)據(jù)類型滿足商業(yè)要求。測試需要在把新數(shù)據(jù)庫投入實際服務(wù)之前完成。
7)?檢查設(shè)計
在開發(fā)期間檢查數(shù)據(jù)庫設(shè)計的常用技術(shù)是通過其所支持的應(yīng)用程序原型檢查數(shù)據(jù)庫。換句話說,針對每一種最終表達數(shù)據(jù)的原型應(yīng)用,保證你檢查了數(shù)據(jù)模型并且查看如何取出數(shù)據(jù)。
三、數(shù)據(jù)庫命名規(guī)范
1.?實體(表)的命名
1)?表以名詞或名詞短語命名,確定表名是采用復(fù)數(shù)還是單數(shù)形式,此外給表的別名定義簡單規(guī)則(比方說,如果表名是一個單詞,別名就取單詞的前4?個字母;如果表名是兩個單詞,就各取兩個單詞的前兩個字母組成4?個字母長的別名;如果表的名字由3?個單詞組成,從頭兩個單詞中各取一個然后從最后一個單詞中再取出兩個字母,結(jié)果還是組成4?字母長的別名,其余依次類推)
對工作用表來說,表名可以加上前綴WORK_?后面附上采用該表的應(yīng)用程序的名字。在命名過程當(dāng)中,根據(jù)語義拼湊縮寫即可。注意,由于ORCLE會將字段名稱統(tǒng)一成大寫或者小寫中的一種,所以要求加上下劃線。
舉例:
定義的縮寫?Sales:?Sal?銷售;
Order:?Ord?訂單;
Detail:?Dtl?明細;
則銷售訂單明細表命名為:Sal_Ord_Dtl;
2)?如果表或者是字段的名稱僅有一個單詞,那么建議不使用縮寫,而是用完整的單詞。
舉例:
定義的縮寫?Material?Ma?物品;
物品表名為:Material,?而不是?Ma.
但是字段物品編碼則是:Ma_ID;而不是Material_ID
3)?所有的存儲值列表的表前面加上前綴Z
目的是將這些值列表類排序在數(shù)據(jù)庫最后。
4)?所有的冗余類的命名(主要是累計表)前面加上前綴X
冗余類是為了提高數(shù)據(jù)庫效率,非規(guī)范化數(shù)據(jù)庫的時候加入的字段或者表
5)?關(guān)聯(lián)類通過用下劃線連接兩個基本類之后,再加前綴R的方式命名,后面按照字母順序羅列兩個表名或者表名的縮寫。
關(guān)聯(lián)表用于保存多對多關(guān)系。
如果被關(guān)聯(lián)的表名大于10個字母,必須將原來的表名的進行縮寫。如果沒有其他原因,建議都使用縮寫。
舉例:表Object與自身存在多對多的關(guān)系,則保存多對多關(guān)系的表命名為:R_Object;
表?Depart和Employee;存在多對多的關(guān)系;則關(guān)聯(lián)表命名為R_Dept_Emp
2.?屬性(列)的命名
1)?采用有意義的列名,表內(nèi)的列要針對鍵采用一整套設(shè)計規(guī)則。每一個表都將有一個自動ID作為主健,邏輯上的主健作為第一組候選主健來定義,如果是數(shù)據(jù)庫自動生成的編碼,統(tǒng)一命名為:ID;如果是自定義的邏輯上的編碼則用縮寫加“ID”的方法命名。如果鍵是數(shù)字類型,你可以用_NO?作為后綴;如果是字符類型則可以采用_CODE?后綴。對列名應(yīng)該采用標準的前綴和后綴。
舉例:銷售訂單的編號字段命名:Sal_Ord_ID;如果還存在一個數(shù)據(jù)庫生成的自動編號,則命名為:ID。
2)?所有的屬性加上有關(guān)類型的后綴,注意,如果還需要其它的后綴,都放在類型后綴之前。
注:?數(shù)據(jù)類型是文本的字段,類型后綴TX可以不寫。有些類型比較明顯的字段,可以不寫類型后綴。
3)?采用前綴命名
給每個表的列名都采用統(tǒng)一的前綴,那么在編寫SQL表達式的時候會得到大大的簡化。這樣做也確實有缺點,比如破壞了自動表連接工具的作用,后者把公共列名同某些數(shù)據(jù)庫聯(lián)系起來。
3.?視圖的命名
1)?視圖以V作為前綴,其他命名規(guī)則和表的命名類似;
2)?命名應(yīng)盡量體現(xiàn)各視圖的功能。
4.?觸發(fā)器的命名
觸發(fā)器以TR作為前綴,觸發(fā)器名為相應(yīng)的表名加上后綴,Insert觸發(fā)器加'_I',Delete觸發(fā)器加'_D',Update觸發(fā)器加'_U',如:TR_Customer_I,TR_Customer_D,TR_Customer_U。
5.?存儲過程名
存儲過程應(yīng)以'UP_'開頭,和系統(tǒng)的存儲過程區(qū)分,后續(xù)部分主要以動賓形式構(gòu)成,并用下劃線分割各個組成部分。如增加代理商的帳戶的存儲過程為'UP_Ins_Agent_Account'。
6.?變量名
變量名采用小寫,若屬于詞組形式,用下劃線分隔每個單詞,如@my_err_no。
7.?命名中其他注意事項
1)??以上命名都不得超過30個字符的系統(tǒng)限制。變量名的長度限制為29(不包括標識字符@)。
2)??數(shù)據(jù)對象、變量的命名都采用英文字符,禁止使用中文命名。絕對不要在對象名的字符之間留空格。
3)?小心保留詞,要保證你的字段名沒有和保留詞、數(shù)據(jù)庫系統(tǒng)或者常用訪問方法沖突
5) 保持字段名和類型的一致性,在命名字段并為其指定數(shù)據(jù)類型的時候一定要保證一致性。假如數(shù)據(jù)類型在一個表里是整數(shù),那在另一個表里可就別變成字符型了。
工具:
????Eclipse3.1、MyEclipse4.03、Tomcat5.5.9、Properties Editor插件、MySql4.1.13
?
新建工程:名稱為 login
?
創(chuàng)建Struts框架
?
創(chuàng)建 index.jsp,增加一鏈接指向 login.jsp
?
按下Ctrl + N,創(chuàng)建 login.jsp、LoginAction,使用MyEclipse的向?qū)Ь涂梢粤耍?strong>記得選對正確的版本
?
在ActionForm配置頁中選擇類型為動態(tài)Form,并繼承于DynaValidatorForm,新增兩個屬性:username、password,在創(chuàng)建jsp文件打上鉤,將路徑改為/login.jsp,然后下一步,改LoginAction的Input source改為/login.jsp,點擊完成
?
按下Ctrl + N 創(chuàng)建一個forwards,記得選對正確的版本
name 輸入 indexGo
路徑選擇 /index.jsp
?
配置validator
先添加Struts插件,使用向?qū)?/div>
Plugin class : org.apache.struts.validator.ValidatorPlugIn
Property : pathnames
Value : /WEB-INF/validator-rules.xml,/WEB-INF/validation.xml
這里需要兩個xml文件
現(xiàn)在創(chuàng)建“
validation.xml
”?文件
?
在這里說明一點,我使用MyEclipse創(chuàng)建的Struts框架中缺少了validator-rules.xml文件,需要動拷貝到WEB-INF目錄中
?
文件內(nèi)容如下:
<
form-validation
>
?
<
formset
>
??
<
form?
name
="loginForm"
>
???
<
field?
property
="username"
?depends
="required"
>
????
<
arg0?
key
="prompt.username"
?
/>
???
</
field
>
???
<
field?
property
="password"
?depends
="required"
>
????
<
arg0?
key
="prompt.password"
?
/>
???
</
field
>
??
</
form
>
?
</
formset
>
</
form-validation
>
?
編輯資源文件“ApplicationResources.properties”
增加以下內(nèi)容
?
prompt.username=User Name
prompt.password=User Password
errors.required={0} is required.
?
再創(chuàng)建中文件資源文件“ApplicationResources_zh_CN.properties”
增加以下內(nèi)容
prompt.username=用戶名稱
prompt.password=登錄密碼
errors.required={0} 必需填寫!
?
修改struts-config.xml文件
在以下位置增加綠色字體部份
<action-mappings >
??? <action
????? attribute="loginForm"
????? input="/login.jsp"
????? name="loginForm"
????? path="/login"
????? scope="request"
????? validate="true"
????? type="com.test.struts.action.LoginAction" />
? </action-mappings>
?
這里說明提交的數(shù)據(jù)必需經(jīng)過驗證,而驗證則是通過validator框架進行的。
?
修改LoginAction.java文件的execute方法,內(nèi)容如下
public ActionForward execute(
??ActionMapping mapping,
??ActionForm form,
??HttpServletRequest request,
??HttpServletResponse response) {
??DynaValidatorForm loginForm = (DynaValidatorForm) form;
??String username=loginForm.getString("username");
??String password=loginForm.getString("password");
??if(username.equals("test")||password.equals("test")){
???return mapping.findForward("indexGo");
??}else{
???return mapping.getInputForward();
??}
?}
?
現(xiàn)在再修改一下login.jsp
增加以下綠色字體部份
<%@ page language="java" contentType="text/html; charset=UTF-8" %>
?
其中charset=UTF-8 是使用UTF-8的字符編碼,這也是為了支持國際化而使用的。
?
好了,現(xiàn)在可以啟動Tomcat進行測試了
?
如果不輸入任何數(shù)據(jù)而直接提交表單的話就可以看到效果了。
?
好了,如果沒有什么問題的話就繼續(xù)往下看吧,如果有問題的話就得往上看了^_^
?
現(xiàn)在創(chuàng)建Spring框架了,在這里我將Spring所有的包全部加載進去,因為我還不知道具體用到哪些類,全部加進去方便點
?
單選框選第二個,這樣的話所有的類庫和標簽等都將拷貝到項目中去,這樣方便以后的布署
下一步后是創(chuàng)建配置文件,將文件放到“WebRoot/WEB-INF”目錄下,文件名稱為“applicationContext.xml”
?
?
配置struts-config.xml文件,添加(spring)的插件
?
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
??? <set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml" />
? </plug-in>
?
?
修改LoginAction配置
?
原:
<action
????? attribute="loginForm"
????? input="/login.jsp"
????? name="loginForm"
????? path="/login"
????? scope="request"
????? validate="true"
????? type="com.test.struts.action.LoginAction" />
?
? </action-mappings>
?
改為:
<action
????? attribute="loginForm"
????? input="/login.jsp"
????? name="loginForm"
????? path="/login"
????? scope="request"
????? validate="true"
????? type="org.springframework.web.struts.DelegatingActionProxy" />
? </action-mappings>
?
?
綠色字體部份為修改內(nèi)容
這里將使用spring的代理器來對Action進行控制
?
當(dāng)提交到/login.do是將控制權(quán)交給了spring,然后由spring來決定是否轉(zhuǎn)回到struts的Action
?
現(xiàn)在來配置spring
?
?
<beans>
?<bean name="/login" class="com.test.struts.action.LoginAction" singleton="false"></bean>
</beans>
?
綠色字體是關(guān)于轉(zhuǎn)交控制權(quán)的配置內(nèi)容
?
屬性singleton="false",指明了Action 的實例獲取方式為每次重新創(chuàng)建。解決了Struts中令人詬病的線程安全問題(Struts中,由一個Action實例處理所有的請求,這就導(dǎo)致了類公用資源在并發(fā)請求中的線程同步問題。)(摘自spring開發(fā)指南)
?
這時如果你要進行測試也是可以的,不過為了省點時間就不進行測試了。
?
建立數(shù)據(jù)庫在 這里我使用的是mysql4.1.13
?
CREATE TABLE `user` (
? `ID` int(11) NOT NULL auto_increment,
? `USERNAME` varchar(50) NOT NULL default '',
? `PASSWORD` varchar(50) NOT NULL default '',
? PRIMARY KEY? (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
?
添加記錄 insert into user (USERNAME,PASSWORD) values ('test','test')
?
創(chuàng)建Hibernate框架
在配置界面中配置數(shù)據(jù)庫的連接部份,重要的是點擊鏈接將jdbc拷貝到lib目錄中
使用MyEclipse的數(shù)據(jù)Database Explorer工具創(chuàng)建User.hmb.xml、AbstractUser.java、User.java映射文件
創(chuàng)建完成后可以將自動生成的hibernate.cfg.xml刪除
?
創(chuàng)建UserDAO.java、UserDAOImp.java
UserDAO.java
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 ,這兩個包的名字就只差一個字,千萬不要有錯,否則找錯誤可是很難的。
Struts應(yīng)用采用兩個基于XML的配置文件來配置,分別是web.xml和struts-cofig.xml文件.web.xml文件是配置所有web應(yīng)用的而struts-config.xml文件是struts專用的配置文件,事實上也是可以根據(jù)需要給這個配置文件起其他名稱的.
Web應(yīng)用的發(fā)布描述文件:web應(yīng)用發(fā)布描述文件可以在應(yīng)用開著者,發(fā)布者和組裝者之間傳遞配置信息,Web容器在啟動的時候從該文件中讀取配置信息,根據(jù)它來裝載和配置web應(yīng)用.文檔類型定義DTD對XML文檔的格式做了定義,DTD吧XML文檔劃分為元素,屬性,實體每一種XML文檔都有獨自的DTD文件.可以從網(wǎng)上下載.<web-app>元素是web.xml的根元素,其他元素必須嵌入在<web-app>元素之內(nèi).要注意的是子元素也是有順序的比如必須是首先<servlet>,然后<servlet-mapping>最后<taglib>.
為Struts應(yīng)用配置Web.xml文件:首先最重要的一步是配置ActionServlet,這個用<servlet>標簽的servlet-name屬性起一個名字叫action,然后用servlet-class屬性指定ActionServlet的類.然后用<servlet-mapping>標簽的servlet-name屬性指定action,在用url-pattern指定接收范圍是*.do的請求.不管應(yīng)用中包含了多少子應(yīng)用,都只需要配置一個ActionServlet,類來出來應(yīng)用中的不同的功能,其實者就是不必要的,因為Servlet本身就是多線程的,而且目前Struts只允許配置一個ActionServlet.聲明ActionServlet的初始化參數(shù):<servlet>的<init-param>子元素用來配置Servlet的初始化參數(shù).param-name設(shè)置config參數(shù)名.param-value設(shè)置struts-config.xml的路徑參數(shù)值.
配置歡迎使用清單:如果客戶訪問Web的時候值是訪問了WEB應(yīng)用的根目錄URL.沒有具體的指定文件,Web會自動調(diào)用Web的歡迎文件.<welcome-file-list>元素來配置的.通過其中的<welcome-file>歡迎頁面</welcome-file>來配置.
配置錯誤處理:盡管Struts框架功能強大的錯誤處理機制,但是不能保證處理所有的錯誤或者異常.當(dāng)錯誤發(fā)生時,如果框架不能處理這種錯誤,把錯誤拋棄給Web容器,在默認的情況下web容器會想客戶端返回錯誤信息.如果想避免讓客戶看到原始的錯誤信息,可以在Web應(yīng)用發(fā)布描述文件中配置<error-page>元素.通過<error-code>404來定義錯誤的類型.然后通過<location>要處理錯誤的JSP頁面來對錯誤進行處理.還可以用<exception-type>來設(shè)置異常,然后通過<location>來處理異常的JSP頁面來處理異常.
配置Struts標簽庫:這個就和以前學(xué)到的JSP自定義標簽類似,配置元素為<taglib>來配置.<taglib-uri>這個指定標簽庫的uri,類似起一個名稱.<taglib-location>這個是標簽庫的位置也就是實際所在的路徑.通過這樣的方法引入一個標簽庫,然后在前臺JSP頁面就可以通過自己定義的URI來調(diào)用標簽.
Struts配置文件:struts-config.xml文件.首先研討一下org.apache.struts.config包,在struts應(yīng)用啟動的時候會把Struts配置文件信息讀取到內(nèi)存中,并把它們存放在config包中相關(guān)的JavaBean類的實例中.包中的每一個類都和struts配置文件中特定的配置元素對應(yīng),ModuleConfig在Struts框架中扮演了十分重要的角色,它是整個config包的核心,在Struts運行時來存放整個應(yīng)用的配置信息.如果有多個子應(yīng)用都會有一個ModuleConfig對象,它和Struts文件根元素的<struts-config>對應(yīng).根元素中包含<form-bean><action><forward>等元素.
<struts-config>元素:時Struts配置文件的根元素,和它對應(yīng)的配置類ModuleConfig類,<struts-config>元素有8個子元素.他們的DTD定義是data-sources?form-bean? global-exception?global-forwards?action-mapping?controller?message-resources?plug-in*在Struts配置文件中,必須按照DTD指定的先手順序來配置<struts-config>元素的各個子元素,如果顛倒了這些子元素的順序,會產(chǎn)生錯誤.
<data-sources>元素:用來配置應(yīng)用所需要的數(shù)據(jù)源,數(shù)據(jù)源負責(zé)創(chuàng)建和特定的數(shù)據(jù)庫的連接.許多數(shù)據(jù)源采用連接池的機制實現(xiàn).以便提高數(shù)據(jù)庫訪問的性能.JAVA語言提供了javax.sql.DataSource接口,所有的數(shù)據(jù)源都必須實現(xiàn)這個接口.許多應(yīng)用服務(wù)器和Web服務(wù)器都提供了數(shù)據(jù)源組件.很多數(shù)據(jù)庫廠商也提供了數(shù)據(jù)源的實現(xiàn).<data-sources>元素包含多個<data-source>子元素永遠配置特定的數(shù)據(jù)源.他們可以包含多個<set-property>子元素用于設(shè)置數(shù)據(jù)源的各種屬性.配置了數(shù)據(jù)源以后,就可以在Action類中訪問數(shù)據(jù)源,在Action中定義了getDataSource(HttpRequest)方法,用于獲取數(shù)據(jù)源對象的引用.然后可以利用DataSource對象調(diào)用getConnection獲取一個連接對象對數(shù)據(jù)庫進行操作.在配置文件中聲明多個數(shù)據(jù)源的時候需要為每一個數(shù)據(jù)源分配唯一的Key值,通過這個來表示特定的數(shù)據(jù)源.獲取特定的數(shù)據(jù)源的時候可以用dataSource = getDataSource(reqeust,”A”);
<form-beans>元素:用來配置多個ActionForm,包含一個或者N個<form-bean>子元素.每個<form-bean>元素都包含多個屬性.className指定和<form-bean>匹配的類.name指定該ActionForm的唯一標識符,這個屬性是必須的以后作為引用使用.type指定ActionForm類的完整類名,這個屬性也是必須的.注意包名也要加上.<form-property>是指定動態(tài)的Form的元素,以后會深入了解.
<global-exception>元素:用于配置異常處理,元素可以包含一個或者多個<exception>元素,用來設(shè)置JAVA異常和異常處理類ExceptionHandler之間的映射.className指定和元素對應(yīng)的配置類,默認的不用動.handler指定異常處理類默認是ExceptionHandler.key指定在本地資源文件中異常的消息Key,path指定當(dāng)前異常發(fā)生的時候轉(zhuǎn)發(fā)的路徑.scope指定ActionMessages實例存放的范圍.type指定需要處理異常類的名字,必須的.bundle指定Resource Bundle.
<global-forwards>元素:用來聲明全局轉(zhuǎn)發(fā),元素可以有一個或者N個<forward>元素組成,用于把一個邏輯名映射到特定的URL,通過這種方法Action類或者JSP頁面無需指定URL,只要指定邏輯名稱就可以實現(xiàn)請求轉(zhuǎn)發(fā)或者重定向.這樣可以減少控制組件和視圖的聚合.易于維護.className對應(yīng)的配置類.contextRelative如果為true表示當(dāng)path屬性以/開頭的時候,給出的是對應(yīng)的上下文URL默認是false.name轉(zhuǎn)發(fā)路徑的邏輯名,必須寫.path轉(zhuǎn)發(fā)或者重定向的URL,必須寫必須是以/開頭.redirect設(shè)置為true的時候表示執(zhí)行重定向操作,此項為false的時候,表示執(zhí)行請求轉(zhuǎn)發(fā)操作.重定向與請求轉(zhuǎn)發(fā)的區(qū)別以后就是重定向是把請求生成應(yīng)答給客戶端然后在重新發(fā)送給定向的URL,瀏覽器地址欄會有顯示.而轉(zhuǎn)發(fā)就是直接把請求轉(zhuǎn)發(fā)給本應(yīng)用的另一個文件,不生成應(yīng)答所以客戶端IE沒顯示.
<action-mapping>元素:包含一個或者N個<action>元素,描述了從特定的請求路徑到響應(yīng)的Action的映射.在<action>元素中可以包含多個<exception>和<forward>子元素,他們分別配置局部異常處理和局部轉(zhuǎn)發(fā).attribute設(shè)置Action關(guān)聯(lián)的ActionForm在request或者session范圍內(nèi)的key.就是在request或者session共享內(nèi)的名稱.className對應(yīng)配置元素的類.默認的是ActionMapping.forward指定轉(zhuǎn)發(fā)URL路徑include指定包含URL路徑.input指定包含表單的URL,當(dāng)表單驗證失敗的時候發(fā)送的URL.name,指定和該Action關(guān)聯(lián)的Form名字.該名字必須是在form-bean中定義過的,可寫可不寫.path必須/開頭的方位Action的路徑.parameter指定Action配置參數(shù).在Action的execute()方法中可以調(diào)用ActionMapping的getParameter()方法來讀取匹配的參數(shù).roles指定允許調(diào)用該Action的安全角色,多個角色之間逗號格開.scope指定Form的存在范圍.默認是session.tyep指定Action的完整類名.unknown如果是true表示可以處理用戶發(fā)出的所有的無效的ActionURL默認是false.validate指定是否調(diào)用ActionForm的validate方法.
<controller>元素:用于配置ActionServlet.buffreSize指定上載文件的輸入緩沖大小.該屬性為可選默認4096.className指定元素對應(yīng)的配置類,ControllerConfig.然后是contentType指定響應(yīng)結(jié)果內(nèi)容類型和字符編碼,該屬性為可選,默認是text/html如果在Action或者JSP網(wǎng)頁也設(shè)置了類型內(nèi)容,會覆蓋這個.locale指定是否把Locale對象保存到當(dāng)前用戶的session中默認false.tempDir指定處理文件上載的臨時工作目錄.nochache如果是true在響應(yīng)結(jié)果中加入特定的頭參數(shù).
<message-resources>元素:用來配置Resource Bundle.用于存放本地文本消息文件.className元素對應(yīng)的配置類.MessageResourcesConfig.factory指定消息的工廠類.key指定文件存放的Servlet對象中采用的屬性Key.null指定如何處理未知消息.parameter指定消息的文件名.
<plug-in>元素:用于配置Struts插件.
配置多應(yīng)用模塊:所有的子應(yīng)用都可以共享同一個ActionServlet實例,但是每個子應(yīng)用都有單獨的配置文件.把應(yīng)用劃分為多個子應(yīng)用模塊.首先為每個應(yīng)用創(chuàng)建單獨的Struts配置文件,在web.xml的ActionServlet配置代碼中添加幾個子應(yīng)用信息.采用<forward>元素來實現(xiàn)應(yīng)用之間的切換.
Digester組件:是一個Apache的另一個開源代碼項目.當(dāng)Struts被初始化的時候,首先會讀取并解析配置文件,框架采用Digester組件來且西配置文件.然后創(chuàng)建config包中的對象.者對象用于存放配置信息.
其實配置文件不難,只要都理其中的原理就OK了.真正實際的項目開發(fā)中,采用的工具例如Eclipse系列,提供了相應(yīng)的插件,在創(chuàng)建一個Struts工程的時候配置文件的標簽都是自動生成的,而我們只需要往里面填寫屬性就OK了. (網(wǎng)友們的支持,是我繼續(xù)寫技術(shù)文章的動力!)
STEP 1:下載和安裝
首先在Subversion的官方網(wǎng)站去下載windows安裝包,最新版是1.3.1,可惜在項目樹上只更新到了1.3.0的二進制包。
下載后安裝在本地機器上,這里注意的是最好將安裝目錄指定為純英文名目錄,安裝在中文目錄下天知道哪天會冒出一個讓你想破頭也想不出的錯誤來。
下載TortoiseSVN進行本地安裝,我安裝的是最新的1.3.2 for svn 1.3.0,這是一個將SVN集成到windows shell中的GUI管理工具,推薦使用。
STEP 2:創(chuàng)建儲存庫
安裝完TortoiseSVN后提示要重啟機器,其實啟不啟都可以正常使用了,首先創(chuàng)建SVN儲存庫(repository),可以選擇命令行方式或者通過TortoiseSVN插件進行GUI操作,命令行運行如下:
svnadmin create E:\svn\repository
e:\svn\repository就是我指定的儲存庫目錄,如果用GUI方式,可以在這個目錄下點擊右鍵選擇[TotoiseSVN]->[Create Repository href...]進行創(chuàng)建,版本庫模式指定為默認的即可。
repository創(chuàng)建完畢后會在目錄下生成若干個文件和文件夾,dav目錄是提供給Apache與mod_dav_svn使用的目錄,讓它們存儲內(nèi)部 數(shù)據(jù);db目錄就是所有版本控制的數(shù)據(jù)文件;hooks目錄放置hook腳本文件的目錄;locks用來放置Subversion文件庫鎖定數(shù)據(jù)的目錄, 用來追蹤存取文件庫的客戶端;format文件是一個文本文件,里面只放了一個整數(shù),表示當(dāng)前文件庫配置的版本號;
STEP 3:配置
打開/conf/目錄,打開svnserve.conf找到一下兩句:
# [general]
# password-db = passwd
去之每行開頭的#,其中第二行是指定身份驗證的文件名,即passwd文件
同樣打開passwd文件,將
# [users]
# harry = harryssecret
# sally = sallyssecret
這幾行的開頭#字符去掉,這是設(shè)置用戶,一行一個,存儲格式為“用戶名 = 密碼”,如可插入一行:admin = admin888,即為系統(tǒng)添加一個用戶名為admin,密碼為admin888的用戶
STEP 4:運行SVN服務(wù)
在命令行執(zhí)行
svnserve --daemon --root E:\svn\repository
服務(wù)啟動,--daemon可簡寫為-d,--root可簡寫為-r,可以建立一個批處理文件并放在windows啟動組中便于開機就運行SVN服務(wù),或者在這個地址
http://clanlib.org/~mbn/svnservice/下載那個
svnservice.exe文件,拷貝到E:\svn\bin目錄下,再從命令行下執(zhí)行:
svnservice -install --daemon --root "E:\svn\Repository"
sc config svnservice start= auto
net start svnservice
此文件會將SVN變成windows系統(tǒng)的一個服務(wù),并默認為自啟動,注意:執(zhí)行第三句時確保前面以命令行方式運行的SVN服務(wù)已經(jīng)停止,如果沒停止可在其窗口中按Ctrl+C中止運行。
STEP 5:創(chuàng)建項目版本樹
確定SVN服務(wù)(命令行或windows服務(wù))運行后,在你需要導(dǎo)入儲存庫的目錄下單擊右鍵選擇[TortoiseSVN]-> [Import...],在彈開的窗口的URL框中輸入 "svn://localhost/myproject" 點擊 "OK" 執(zhí)行導(dǎo)入,如果沒有報錯,數(shù) 據(jù)就全部加入SVN儲存庫目錄樹上了。用命令行也可以完成這些操作,這需要你在系統(tǒng)變量中新建一個“SVN_EDITOR”的系統(tǒng)變量,變量值為本地的一 個文本編輯器執(zhí)行文件路徑,一般指到windows的記事本上就行了 "c:\windows\notepad.exe" ,然后新開一個CMD窗口,執(zhí)行
svn mkdir svn://localhost/myproject
隨即關(guān)閉記事本打開的log文件窗口后按"c"鍵繼續(xù)后生成項目樹。一般情況,我們在創(chuàng)建文件根路徑后應(yīng)該在創(chuàng)建三個目錄:branches、tags、trunk,這三個目錄是Subversion需要的三個目錄。對于check out、commit、update等操作可以通過svn命令行方式執(zhí)行,也可以用TortoiseSVN的windows菜單完成,非常簡單咯。
主站蜘蛛池模板:
亚洲熟妇av一区二区三区|
国产亚洲3p无码一区二区|
亚洲区小说区图片区QVOD|
亚洲精品第五页中文字幕|
亚洲爆乳少妇无码激情|
国产免费一区二区视频|
成人毛片18女人毛片免费视频未
|
亚洲国产人成在线观看69网站
|
亚洲第一精品福利|
亚洲欧美日韩一区二区三区在线|
好吊色永久免费视频大全|
57PAO成人国产永久免费视频|
亚洲 无码 在线 专区|
在线观看特色大片免费网站|
成视频年人黄网站免费视频|
久久久久国产成人精品亚洲午夜|
亚洲女人18毛片水真多|
精品国产污污免费网站入口|
无码高潮少妇毛多水多水免费|
国产亚洲欧洲精品|
亚洲人成色777777老人头|
日本免费久久久久久久网站|
国产aa免费视频|
亚洲狠狠狠一区二区三区|
久久久受www免费人成|
在线观看无码的免费网站|
亚洲国产成人精品不卡青青草原|
色噜噜噜噜亚洲第一|
99久久99久久精品免费看蜜桃|
亚洲精品无码成人片久久|
成人亚洲国产精品久久|
成人黄色免费网址|
亚洲国产精品无码久久一线|
污视频网站在线观看免费|
欧美日韩国产免费一区二区三区|
亚洲VA中文字幕无码毛片|
窝窝影视午夜看片免费|
日韩高清在线高清免费|
亚洲一卡二卡三卡四卡无卡麻豆|
最近中文字幕大全免费版在线|
亚洲国产精品人人做人人爱|