數(shù)據(jù)庫(kù)設(shè)計(jì)經(jīng)驗(yàn)

          (轉(zhuǎn)自--http://www.cnblogs.com/qiubole/articles/157312.html)
          一個(gè)成功的管理系統(tǒng),是由:[50% 的業(yè)務(wù) + 50% 的軟件] 所組成,而 50% 的成功軟件又有 [25% 的數(shù)據(jù)庫(kù) + 25% 的程序] 所組成,數(shù)據(jù)庫(kù)設(shè)計(jì)的好壞是一個(gè)關(guān)鍵。如果把企業(yè)的數(shù)據(jù)比做生命所必需的血液,那么數(shù)據(jù)庫(kù)的設(shè)計(jì)就是應(yīng)用中最重要的一部分。有關(guān)數(shù)據(jù)庫(kù)設(shè)計(jì)的材料汗牛充棟,大學(xué)學(xué)位課程里也有專門的講述。不過,就如我們反復(fù)強(qiáng)調(diào)的那樣,再好的老師也比不過經(jīng)驗(yàn)的教誨。所以我歸納歷年來所走的彎路及體會(huì),并在網(wǎng)上找了些對(duì)數(shù)據(jù)庫(kù)設(shè)計(jì)頗有造詣的專業(yè)人士給大家傳授一些設(shè)計(jì)數(shù)據(jù)庫(kù)的技巧和經(jīng)驗(yàn)。精選了其中的 60 個(gè)最佳技巧,并把這些技巧編寫成了本文,為了方便索引其內(nèi)容劃分為 5 個(gè)部分:

          第 1 部分 - 設(shè)計(jì)數(shù)據(jù)庫(kù)之前
          這一部分羅列了 12 個(gè)基本技巧,包括命名規(guī)范和明確業(yè)務(wù)需求等。
          第 2 部分 - 設(shè)計(jì)數(shù)據(jù)庫(kù)表
          總共 24 個(gè)指南性技巧,涵蓋表內(nèi)字段設(shè)計(jì)以及應(yīng)該避免的常見問題等。
          第 3 部分 - 選擇鍵
          怎么選擇鍵呢?這里有 10 個(gè)技巧專門涉及系統(tǒng)生成的主鍵的正確用法,還有何 時(shí)以及如何索引字段以獲得最佳性能等。
          第 4 部分 - 保證數(shù)據(jù)完整性
          討論如何保持?jǐn)?shù)據(jù)庫(kù)的清晰和健壯,如何把有害數(shù)據(jù)降低到最小程度。
          第 5 部分 - 各種小技巧
          不包括在以上 4 個(gè)部分中的其他技巧,五花八門,有了它們希望你的數(shù)據(jù)庫(kù)開發(fā)工作會(huì)更輕松一些。
          第 1 部分 - 設(shè)計(jì)數(shù)據(jù)庫(kù)之前
          考察現(xiàn)有環(huán)境
          在設(shè)計(jì)一個(gè)新數(shù)據(jù)庫(kù)時(shí),你不但應(yīng)該仔細(xì)研究業(yè)務(wù)需求而且還要考察現(xiàn)有的系統(tǒng)。大多數(shù)數(shù)據(jù)庫(kù)項(xiàng)目都不是從頭開始建立的;通常,機(jī)構(gòu)內(nèi)總會(huì)存在用來滿足特定需求的現(xiàn)有系統(tǒng)(可能沒有實(shí)現(xiàn)自動(dòng)計(jì)算)。顯然,現(xiàn)有系統(tǒng)并不完美,否則你就不必再建立新系統(tǒng)了。但是對(duì)舊系統(tǒng)的研究可以讓你發(fā)現(xiàn)一些可能會(huì)忽略的細(xì)微問題。一般來說,考察現(xiàn)有系統(tǒng)對(duì)你絕對(duì)有好處。
          定義標(biāo)準(zhǔn)的對(duì)象命名規(guī)范
          一定要定義數(shù)據(jù)庫(kù)對(duì)象的命名規(guī)范。對(duì)數(shù)據(jù)庫(kù)表來說,從項(xiàng)目一開始就要確定表名是采用復(fù)數(shù)還是單數(shù)形式。此外還要給表的別名定義簡(jiǎn)單規(guī)則(比方說,如果表名是一個(gè)單詞,別名就取單詞的前 4 個(gè)字母;如果表名是兩個(gè)單詞,就各取兩個(gè)單詞的前兩個(gè)字母組成 4 個(gè)字母長(zhǎng)的別名;如果表的名字由 3 個(gè)單詞組成,你不妨從頭兩個(gè)單詞中各取一個(gè)然后從最后一個(gè)單詞中再取出兩個(gè)字母,結(jié)果還是組成 4 字母長(zhǎng)的別名,其余依次類推)對(duì)工作用表來說,表名可以加上前綴 WORK_ 后面附上采用該表的應(yīng)用程序的名字。表內(nèi)的列[字段]要針對(duì)鍵采用一整套設(shè)計(jì)規(guī)則。比如,如果鍵是數(shù)字類型,你可以用 _N 作為后綴;如果是字符類型則可以采用 _C 后綴。對(duì)列[字段]名應(yīng)該采用標(biāo)準(zhǔn)的前綴和后綴。再如,假如你的表里有好多“money”字段,你不妨給每個(gè)列[字段]增加一個(gè) _M 后綴。還有,日期列[字段]最好以 D_ 作為名字打頭。

          檢查表名、報(bào)表名和查詢名之間的命名規(guī)范。你可能會(huì)很快就被這些不同的數(shù)據(jù)庫(kù)要素的名稱搞糊涂了。假如你堅(jiān)持統(tǒng)一地命名這些數(shù)據(jù)庫(kù)的不同組成部分,至少你應(yīng)該在這些對(duì)象名字的開頭用 Table、Query 或者 Report 等前綴加以區(qū)別。

          如果采用了 Microsoft Access,你可以用 qry、rpt、tbl 和 mod 等符號(hào)來標(biāo)識(shí)對(duì)象(比如 tbl_Employees)。我在和 SQL Server 打交道的時(shí)候還用過 tbl 來索引表,但我用 sp_company (現(xiàn)在用 sp_feft_)標(biāo)識(shí)存儲(chǔ)過程,因?yàn)樵谟械臅r(shí)候如果我發(fā)現(xiàn)了更好的處理辦法往往會(huì)保存好幾個(gè)拷貝。我在實(shí)現(xiàn) SQL Server 2000 時(shí)用 udf_ (或者類似的標(biāo)記)標(biāo)識(shí)我編寫的函數(shù)。
          工欲善其事, 必先利其器
          采用理想的數(shù)據(jù)庫(kù)設(shè)計(jì)工具,比如:SyBase 公司的 PowerDesign,她支持 PB、VB、Delphe 等語言,通過 ODBC 可以連接市面上流行的 30 多個(gè)數(shù)據(jù)庫(kù),包括 dBase、FoxPro、VFP、SQL Server 等,今后有機(jī)會(huì)我將著重介紹 PowerDesign 的使用。
          獲取數(shù)據(jù)模式資源手冊(cè)
          正在尋求示例模式的人可以閱讀《數(shù)據(jù)模式資源手冊(cè)》一書,該書由 Len Silverston、W. H. Inmon 和 Kent Graziano 編寫,是一本值得擁有的最佳數(shù)據(jù)建模圖書。該書包括的章節(jié)涵蓋多種數(shù)據(jù)領(lǐng)域,比如人員、機(jī)構(gòu)和工作效能等。其他的你還可以參考:[1]薩師煊 王珊著 數(shù)據(jù)庫(kù)系統(tǒng)概論(第二版)高等教育出版社 1991、[2][美] Steven M.Bobrowski 著 Oracle 7 與客戶/服務(wù)器計(jì)算技術(shù)從入門到精通 劉建元等譯 電子工業(yè)出版社,1996、[3]周中元 信息系統(tǒng)建模方法(下) 電子與信息化 1999年第3期,1999
          暢想未來,但不可忘了過去的教訓(xùn)
          我發(fā)現(xiàn)詢問用戶如何看待未來需求變化非常有用。這樣做可以達(dá)到兩個(gè)目的:首先,你可以清楚地了解應(yīng)用設(shè)計(jì)在哪個(gè)地方應(yīng)該更具靈活性以及如何避免性能瓶頸;其次,你知道發(fā)生事先沒有確定的需求變更時(shí)用戶將和你一樣感到吃驚。

          一定要記住過去的經(jīng)驗(yàn)教訓(xùn)!我們開發(fā)人員還應(yīng)該通過分享自己的體會(huì)和經(jīng)驗(yàn)互相幫助。即使用戶認(rèn)為他們?cè)僖膊恍枰裁粗С至耍覀円矐?yīng)該對(duì)他們進(jìn)行這方面的教育,我們都曾經(jīng)面臨過這樣的時(shí)刻“當(dāng)初要是這么做了該多好..”。
          在物理實(shí)踐之前進(jìn)行邏輯設(shè)計(jì)
          在深入物理設(shè)計(jì)之前要先進(jìn)行邏輯設(shè)計(jì)。隨著大量的 CASE 工具不斷涌現(xiàn)出來,你的設(shè)計(jì)也可以達(dá)到相當(dāng)高的邏輯水準(zhǔn),你通常可以從整體上更好地了解數(shù)據(jù)庫(kù)設(shè)計(jì)所需要的方方面面。
          了解你的業(yè)務(wù)
          在你百分百地確定系統(tǒng)從客戶角度滿足其需求之前不要在你的 ER(實(shí)體關(guān)系)模式中加入哪怕一個(gè)數(shù)據(jù)表(怎么,你還沒有模式?那請(qǐng)你參看技巧 9)。了解你的企業(yè)業(yè)務(wù)可以在以后的開發(fā)階段節(jié)約大量的時(shí)間。一旦你明確了業(yè)務(wù)需求,你就可以自己做出許多決策了。

          一旦你認(rèn)為你已經(jīng)明確了業(yè)務(wù)內(nèi)容,你最好同客戶進(jìn)行一次系統(tǒng)的交流。采用客戶的術(shù)語并且向他們解釋你所想到的和你所聽到的。同時(shí)還應(yīng)該用可能、將會(huì)和必須等詞匯表達(dá)出系統(tǒng)的關(guān)系基數(shù)。這樣你就可以讓你的客戶糾正你自己的理解然后做好下一步的 ER 設(shè)計(jì)。
          創(chuàng)建數(shù)據(jù)字典和 ER 圖表
          一定要花點(diǎn)時(shí)間創(chuàng)建 ER 圖表和數(shù)據(jù)字典。其中至少應(yīng)該包含每個(gè)字段的數(shù)據(jù)類型和在每個(gè)表內(nèi)的主外鍵。創(chuàng)建 ER 圖表和數(shù)據(jù)字典確實(shí)有點(diǎn)費(fèi)時(shí)但對(duì)其他開發(fā)人員要了解整個(gè)設(shè)計(jì)卻是完全必要的。越早創(chuàng)建越能有助于避免今后面臨的可能混亂,從而可以讓任何了解數(shù)據(jù)庫(kù)的人都明確如何從數(shù)據(jù)庫(kù)中獲得數(shù)據(jù)。

          有一份諸如 ER 圖表等最新文檔其重要性如何強(qiáng)調(diào)都不過分,這對(duì)表明表之間關(guān)系很有用,而數(shù)據(jù)字典則說明了每個(gè)字段的用途以及任何可能存在的別名。對(duì) SQL 表達(dá)式的文檔化來說這是完全必要的。
          創(chuàng)建模式
          一張圖表勝過千言萬語:開發(fā)人員不僅要閱讀和實(shí)現(xiàn)它,而且還要用它來幫助自己和用戶對(duì)話。模式有助于提高協(xié)作效能,這樣在先期的數(shù)據(jù)庫(kù)設(shè)計(jì)中幾乎不可能出現(xiàn)大的問題。模式不必弄的很復(fù)雜;甚至可以簡(jiǎn)單到手寫在一張紙上就可以了。只是要保證其上的邏輯關(guān)系今后能產(chǎn)生效益。
          從輸入輸出下手
          在定義數(shù)據(jù)庫(kù)表和字段需求(輸入)時(shí),首先應(yīng)檢查現(xiàn)有的或者已經(jīng)設(shè)計(jì)出的報(bào)表、查詢和視圖(輸出)以決定為了支持這些輸出哪些是必要的表和字段。舉個(gè)簡(jiǎn)單的例子:假如客戶需要一個(gè)報(bào)表按照郵政編碼排序、分段和求和,你要保證其中包括了單獨(dú)的郵政編碼字段而不要把郵政編碼糅進(jìn)地址字段里。
          報(bào)表技巧
          要了解用戶通常是如何報(bào)告數(shù)據(jù)的:批處理還是在線提交報(bào)表?時(shí)間間隔是每天、每周、每月、每個(gè)季度還是每年?如果需要的話還可以考慮創(chuàng)建總結(jié)表。系統(tǒng)生成的主鍵在報(bào)表中很難管理。用戶在具有系統(tǒng)生成主鍵的表內(nèi)用副鍵進(jìn)行檢索往往會(huì)返回許多重復(fù)數(shù)據(jù)。這樣的檢索性能比較低而且容易引起混亂。
          理解客戶需求
          看起來這應(yīng)該是顯而易見的事,但需求就是來自客戶(這里要從內(nèi)部和外部客戶的角度考慮)。不要依賴用戶寫下來的需求,真正的需求在客戶的腦袋里。你要讓客戶解釋其需求,而且隨著開發(fā)的繼續(xù),還要經(jīng)常詢問客戶保證其需求仍然在開發(fā)的目的之中。一個(gè)不變的真理是:“只有我看見了我才知道我想要的是什么”必然會(huì)導(dǎo)致大量的返工,因?yàn)閿?shù)據(jù)庫(kù)沒有達(dá)到客戶從來沒有寫下來的需求標(biāo)準(zhǔn)。而更糟的是你對(duì)他們需求的解釋只屬于你自己,而且可能是完全錯(cuò)誤的。
          第 2 部分 - 設(shè)計(jì)表和字段
          檢查各種變化
          我在設(shè)計(jì)數(shù)據(jù)庫(kù)的時(shí)候會(huì)考慮到哪些數(shù)據(jù)字段將來可能會(huì)發(fā)生變更。比方說,姓氏就是如此(注意是西方人的姓氏,比如女性結(jié)婚后從夫姓等)。所以,在建立系統(tǒng)存儲(chǔ)客戶信息時(shí),我傾向于在單獨(dú)的一個(gè)數(shù)據(jù)表里存儲(chǔ)姓氏字段,而且還附加起始日和終止日等字段,這樣就可以跟蹤這一數(shù)據(jù)條目的變化。
          采用有意義的字段名
          有一回我參加開發(fā)過一個(gè)項(xiàng)目,其中有從其他程序員那里繼承的程序,那個(gè)程序員喜歡用屏幕上顯示數(shù)據(jù)指示用語命名字段,這也不賴,但不幸的是,她還喜歡用一些奇怪的命名法,其命名采用了匈牙利命名和控制序號(hào)的組合形式,比如 cbo1、txt2、txt2_b 等等。
          除非你在使用只面向你的縮寫字段名的系統(tǒng),否則請(qǐng)盡可能地把字段描述的清楚些。當(dāng)然,也別做過頭了,比如 Customer_Shipping_Address_Street_Line_1,雖然很富有說明性,但沒人愿意鍵入這么長(zhǎng)的名字,具體尺度就在你的把握中。
          采用前綴命名
          如果多個(gè)表里有好多同一類型的字段(比如 FirstName),你不妨用特定表的前綴(比如 CusLastName)來幫助你標(biāo)識(shí)字段。

          時(shí)效性數(shù)據(jù)應(yīng)包括“最近更新日期/時(shí)間”字段。時(shí)間標(biāo)記對(duì)查找數(shù)據(jù)問題的原因、按日期重新處理/重載數(shù)據(jù)和清除舊數(shù)據(jù)特別有用。
          標(biāo)準(zhǔn)化和數(shù)據(jù)驅(qū)動(dòng)
          數(shù)據(jù)的標(biāo)準(zhǔn)化不僅方便了自己而且也方便了其他人。比方說,假如你的用戶界面要訪問外部數(shù)據(jù)源(文件、XML 文檔、其他數(shù)據(jù)庫(kù)等),你不妨把相應(yīng)的連接和路徑信息存儲(chǔ)在用戶界面支持表里。還有,如果用戶界面執(zhí)行工作流之類的任務(wù)(發(fā)送郵件、打印信箋、修改記錄狀態(tài)等),那么產(chǎn)生工作流的數(shù)據(jù)也可以存放在數(shù)據(jù)庫(kù)里。預(yù)先安排總需要付出努力,但如果這些過程采用數(shù)據(jù)驅(qū)動(dòng)而非硬編碼的方式,那么策略變更和維護(hù)都會(huì)方便得多。事實(shí)上,如果過程是數(shù)據(jù)驅(qū)動(dòng)的,你就可以把相當(dāng)大的責(zé)任推給用戶,由用戶來維護(hù)自己的工作流過程。
          標(biāo)準(zhǔn)化不能過頭
          對(duì)那些不熟悉標(biāo)準(zhǔn)化一詞(normalization)的人而言,標(biāo)準(zhǔn)化可以保證表內(nèi)的字段都是最基礎(chǔ)的要素,而這一措施有助于消除數(shù)據(jù)庫(kù)中的數(shù)據(jù)冗余。標(biāo)準(zhǔn)化有好幾種形式,但 Third Normal Form(3NF)通常被認(rèn)為在性能、擴(kuò)展性和數(shù)據(jù)完整性方面達(dá)到了最好平衡。簡(jiǎn)單來說,3NF 規(guī)定:
          * 表內(nèi)的每一個(gè)值都只能被表達(dá)一次。
          * 表內(nèi)的每一行都應(yīng)該被唯一的標(biāo)識(shí)(有唯一鍵)。
          * 表內(nèi)不應(yīng)該存儲(chǔ)依賴于其他鍵的非鍵信息。
          遵守 3NF 標(biāo)準(zhǔn)的數(shù)據(jù)庫(kù)具有以下特點(diǎn):有一組表專門存放通過鍵連接起來的關(guān)聯(lián)數(shù)據(jù)。比方說,某個(gè)存放客戶及其有關(guān)定單的 3NF 數(shù)據(jù)庫(kù)就可能有兩個(gè)表:Customer 和 Order。Order 表不包含定單關(guān)聯(lián)客戶的任何信息,但表內(nèi)會(huì)存放一個(gè)鍵值,該鍵指向 Customer 表里包含該客戶信息的那一行。
          更高層次的標(biāo)準(zhǔn)化也有,但更標(biāo)準(zhǔn)是否就一定更好呢?答案是不一定。事實(shí)上,對(duì)某些項(xiàng)目來說,甚至就連 3NF 都可能給數(shù)據(jù)庫(kù)引入太高的復(fù)雜性。

          為了效率的緣故,對(duì)表不進(jìn)行標(biāo)準(zhǔn)化有時(shí)也是必要的,這樣的例子很多。曾經(jīng)有個(gè)開發(fā)餐飲分析軟件的活就是用非標(biāo)準(zhǔn)化表把查詢時(shí)間從平均 40 秒降低到了兩秒左右。雖然我不得不這么做,但我絕不把數(shù)據(jù)表的非標(biāo)準(zhǔn)化當(dāng)作當(dāng)然的設(shè)計(jì)理念。而具體的操作不過是一種派生。所以如果表出了問題重新產(chǎn)生非標(biāo)準(zhǔn)化的表是完全可能的。
          Microsoft Visual FoxPro 報(bào)表技巧
          如果你正在使用 Microsoft Visual FoxPro,你可以用對(duì)用戶友好的字段名來代替編號(hào)的名稱:比如用 Customer Name 代替 txtCNaM。這樣,當(dāng)你用向?qū)С绦?[Wizards,臺(tái)灣人稱為‘精靈’] 創(chuàng)建表單和報(bào)表時(shí),其名字會(huì)讓那些不是程序員的人更容易閱讀。
          不活躍或者不采用的指示符
          增加一個(gè)字段表示所在記錄是否在業(yè)務(wù)中不再活躍挺有用的。不管是客戶、員工還是其他什么人,這樣做都能有助于再運(yùn)行查詢的時(shí)候過濾活躍或者不活躍狀態(tài)。同時(shí)還消除了新用戶在采用數(shù)據(jù)時(shí)所面臨的一些問題,比如,某些記錄可能不再為他們所用,再刪除的時(shí)候可以起到一定的防范作用。
          使用角色實(shí)體定義屬于某類別的列[字段]
          在需要對(duì)屬于特定類別或者具有特定角色的事物做定義時(shí),可以用角色實(shí)體來創(chuàng)建特定的時(shí)間關(guān)聯(lián)關(guān)系,從而可以實(shí)現(xiàn)自我文檔化。
          這里的含義不是讓 PERSON 實(shí)體帶有 Title 字段,而是說,為什么不用 PERSON 實(shí)體和 PERSON_TYPE 實(shí)體來描述人員呢?比方說,當(dāng) John Smith, Engineer 提升為 John Smith, Director 乃至最后爬到 John Smith, CIO 的高位,而所有你要做的不過是改變兩個(gè)表 PERSON 和 PERSON_TYPE 之間關(guān)系的鍵值,同時(shí)增加一個(gè)日期/時(shí)間字段來知道變化是何時(shí)發(fā)生的。這樣,你的 PERSON_TYPE 表就包含了所有 PERSON 的可能類型,比如 Associate、Engineer、Director、CIO 或者 CEO 等。
          還有個(gè)替代辦法就是改變 PERSON 記錄來反映新頭銜的變化,不過這樣一來在時(shí)間上無法跟蹤個(gè)人所處位置的具體時(shí)間。
          采用常用實(shí)體命名機(jī)構(gòu)數(shù)據(jù)
          組織數(shù)據(jù)的最簡(jiǎn)單辦法就是采用常用名字,比如:PERSON、ORGANIZATION、ADDRESS 和 PHONE 等等。當(dāng)你把這些常用的一般名字組合起來或者創(chuàng)建特定的相應(yīng)副實(shí)體時(shí),你就得到了自己用的特殊版本。開始的時(shí)候采用一般術(shù)語的主要原因在于所有的具體用戶都能對(duì)抽象事物具體化。
          有了這些抽象表示,你就可以在第 2 級(jí)標(biāo)識(shí)中采用自己的特殊名稱,比如,PERSON 可能是 Employee、Spouse、Patient、Client、Customer、Vendor 或者 Teacher 等。同樣的,ORGANIZATION 也可能是 MyCompany、MyDepartment、Competitor、Hospital、Warehouse、Government 等。最后 ADDRESS 可以具體為 Site、Location、Home、Work、Client、Vendor、Corporate 和 FieldOffice 等。
          采用一般抽象術(shù)語來標(biāo)識(shí)“事物”的類別可以讓你在關(guān)聯(lián)數(shù)據(jù)以滿足業(yè)務(wù)要求方面獲得巨大的靈活性,同時(shí)這樣做還可以顯著降低數(shù)據(jù)存儲(chǔ)所需的冗余量。
          用戶來自世界各地
          在設(shè)計(jì)用到網(wǎng)絡(luò)或者具有其他國(guó)際特性的數(shù)據(jù)庫(kù)時(shí),一定要記住大多數(shù)國(guó)家都有不同的字段格式,比如郵政編碼等,有些國(guó)家,比如新西蘭就沒有郵政編碼一說。
          數(shù)據(jù)重復(fù)需要采用分立的數(shù)據(jù)表
          如果你發(fā)現(xiàn)自己在重復(fù)輸入數(shù)據(jù),請(qǐng)創(chuàng)建新表和新的關(guān)系。
          每個(gè)表中都應(yīng)該添加的 3 個(gè)有用的字段
          * dRecordCreationDate,在 VB 下默認(rèn)是 Now(),而在 SQL Server 下默認(rèn)為 GETDATE()
          * sRecordCreator,在 SQL Server 下默認(rèn)為 NOT NULL DEFAULT USER
          * nRecordVersion,記錄的版本標(biāo)記;有助于準(zhǔn)確說明記錄中出現(xiàn) null 數(shù)據(jù)或者丟失數(shù)據(jù)的原因
          對(duì)地址和電話采用多個(gè)字段
          描述街道地址就短短一行記錄是不夠的。Address_Line1、Address_Line2 和 Address_Line3 可以提供更大的靈活性。還有,電話號(hào)碼和郵件地址最好擁有自己的數(shù)據(jù)表,其間具有自身的類型和標(biāo)記類別。

          過分標(biāo)準(zhǔn)化可要小心,這樣做可能會(huì)導(dǎo)致性能上出現(xiàn)問題。雖然地址和電話表分離通常可以達(dá)到最佳狀態(tài),但是如果需要經(jīng)常訪問這類信息,或許在其父表中存放“首選”信息(比如 Customer 等)更為妥當(dāng)些。非標(biāo)準(zhǔn)化和加速訪問之間的妥協(xié)是有一定意義的。
          使用多個(gè)名稱字段
          我覺得很吃驚,許多人在數(shù)據(jù)庫(kù)里就給 name 留一個(gè)字段。我覺得只有剛?cè)腴T的開發(fā)人員才會(huì)這么做,但實(shí)際上網(wǎng)上這種做法非常普遍。我建議應(yīng)該把姓氏和名字當(dāng)作兩個(gè)字段來處理,然后在查詢的時(shí)候再把他們組合起來。

          我最常用的是在同一表中創(chuàng)建一個(gè)計(jì)算列[字段],通過它可以自動(dòng)地連接標(biāo)準(zhǔn)化后的字段,這樣數(shù)據(jù)變動(dòng)的時(shí)候它也跟著變。不過,這樣做在采用建模軟件時(shí)得很機(jī)靈才行。總之,采用連接字段的方式可以有效的隔離用戶應(yīng)用和開發(fā)人員界面。
          提防大小寫混用的對(duì)象名和特殊字符
          過去最令我惱火的事情之一就是數(shù)據(jù)庫(kù)里有大小寫混用的對(duì)象名,比如 CustomerData。這一問題從 Access 到 Oracle 數(shù)據(jù)庫(kù)都存在。我不喜歡采用這種大小寫混用的對(duì)象命名方法,結(jié)果還不得不手工修改名字。想想看,這種數(shù)據(jù)庫(kù)/應(yīng)用程序能混到采用更強(qiáng)大數(shù)據(jù)庫(kù)的那一天嗎?采用全部大寫而且包含下劃符的名字具有更好的可讀性(CUSTOMER_DATA),絕對(duì)不要在對(duì)象名的字符之間留空格。
          小心保留詞
          要保證你的字段名沒有和保留詞、數(shù)據(jù)庫(kù)系統(tǒng)或者常用訪問方法沖突,比如,最近我編寫的一個(gè) ODBC 連接程序里有個(gè)表,其中就用了 DESC 作為說明字段名。后果可想而知!DESC 是 DESCENDING 縮寫后的保留詞。表里的一個(gè) SELECT * 語句倒是能用,但我得到的卻是一大堆毫無用處的信息。
          保持字段名和類型的一致性
          在命名字段并為其指定數(shù)據(jù)類型的時(shí)候一定要保證一致性。假如字段在某個(gè)表中叫做“agreement_number”,你就別在另一個(gè)表里把名字改成“ref1”。假如數(shù)據(jù)類型在一個(gè)表里是整數(shù),那在另一個(gè)表里可就別變成字符型了。記住,你干完自己的活了,其他人還要用你的數(shù)據(jù)庫(kù)呢。
          仔細(xì)選擇數(shù)字類型
          在 SQL 中使用 smallint 和 tinyint 類型要特別小心,比如,假如你想看看月銷售總額,你的總額字段類型是 smallint,那么,如果總額超過了 $32,767 你就不能進(jìn)行計(jì)算操作了。
          刪除標(biāo)記
          在表中包含一個(gè)“刪除標(biāo)記”字段,這樣就可以把行標(biāo)記為刪除。在關(guān)系數(shù)據(jù)庫(kù)里不要單獨(dú)刪除某一行;最好采用清除數(shù)據(jù)程序而且要仔細(xì)維護(hù)索引整體性。
          避免使用觸發(fā)器
          觸發(fā)器的功能通常可以用其他方式實(shí)現(xiàn)。在調(diào)試程序時(shí)觸發(fā)器可能成為干擾。假如你確實(shí)需要采用觸發(fā)器,你最好集中對(duì)它文檔化。
          包含版本機(jī)制
          建議你在數(shù)據(jù)庫(kù)中引入版本控制機(jī)制來確定使用中的數(shù)據(jù)庫(kù)的版本。無論如何你都要實(shí)現(xiàn)這一要求。時(shí)間一長(zhǎng),用戶的需求總是會(huì)改變的。最終可能會(huì)要求修改數(shù)據(jù)庫(kù)結(jié)構(gòu)。雖然你可以通過檢查新字段或者索引來確定數(shù)據(jù)庫(kù)結(jié)構(gòu)的版本,但我發(fā)現(xiàn)把版本信息直接存放到數(shù)據(jù)庫(kù)中不更為方便嗎?。
          給文本字段留足余量
          ID 類型的文本字段,比如客戶 ID 或定單號(hào)等等都應(yīng)該設(shè)置得比一般想象更大,因?yàn)闀r(shí)間不長(zhǎng)你多半就會(huì)因?yàn)橐砑宇~外的字符而難堪不已。比方說,假設(shè)你的客戶 ID 為 10 位數(shù)長(zhǎng)。那你應(yīng)該把數(shù)據(jù)庫(kù)表字段的長(zhǎng)度設(shè)為 12 或者 13 個(gè)字符長(zhǎng)。這算浪費(fèi)空間嗎?是有一點(diǎn),但也沒你想象的那么多:一個(gè)字段加長(zhǎng) 3 個(gè)字符在有 1 百萬條記錄,再加上一點(diǎn)索引的情況下才不過讓整個(gè)數(shù)據(jù)庫(kù)多占據(jù) 3MB 的空間。但這額外占據(jù)的空間卻無需將來重構(gòu)整個(gè)數(shù)據(jù)庫(kù)就可以實(shí)現(xiàn)數(shù)據(jù)庫(kù)規(guī)模的增長(zhǎng)了。身份證的號(hào)碼從 15 位變成 18 位就是最好和最慘痛的例子。
          列[字段]命名技巧
          我們發(fā)現(xiàn),假如你給每個(gè)表的列[字段]名都采用統(tǒng)一的前綴,那么在編寫 SQL 表達(dá)式的時(shí)候會(huì)得到大大的簡(jiǎn)化。這樣做也確實(shí)有缺點(diǎn),比如破壞了自動(dòng)表連接工具的作用,后者把公共列[字段]名同某些數(shù)據(jù)庫(kù)聯(lián)系起來,不過就連這些工具有時(shí)不也連接錯(cuò)誤嘛。舉個(gè)簡(jiǎn)單的例子,假設(shè)有兩個(gè)表:
          Customer 和 Order。Customer 表的前綴是 cu_,所以該表內(nèi)的子段名如下:cu_name_id、cu_surname、cu_initials 和cu_address 等。Order 表的前綴是 or_,所以子段名是:
          or_order_id、or_cust_name_id、or_quantity 和 or_description 等。
          這樣從數(shù)據(jù)庫(kù)中選出全部數(shù)據(jù)的 SQL 語句可以寫成如下所示:
          Select * From Customer, Order Where cu_surname = "MYNAME" ;
          and cu_name_id = or_cust_name_id and or_quantity = 1
          在沒有這些前綴的情況下則寫成這個(gè)樣子(用別名來區(qū)分):
          Select * From Customer, Order Where Customer.surname = "MYNAME" ;
          and Customer.name_id = Order.cust_name_id and Order.quantity = 1
          第 1 個(gè) SQL 語句沒少鍵入多少字符。但如果查詢涉及到 5 個(gè)表乃至更多的列[字段]你就知道這個(gè)技巧多有用了。
          第 3 部分 - 選擇鍵和索引
          數(shù)據(jù)采掘要預(yù)先計(jì)劃
          我所在的某一客戶部門一度要處理 8 萬多份聯(lián)系方式,同時(shí)填寫每個(gè)客戶的必要數(shù)據(jù)(這絕對(duì)不是小活)。我從中還要確定出一組客戶作為市場(chǎng)目標(biāo)。當(dāng)我從最開始設(shè)計(jì)表和字段的時(shí)候,我試圖不在主索引里增加太多的字段以便加快數(shù)據(jù)庫(kù)的運(yùn)行速度。然后我意識(shí)到特定的組查詢和信息采掘既不準(zhǔn)確速度也不快。結(jié)果只好在主索引中重建而且合并了數(shù)據(jù)字段。我發(fā)現(xiàn)有一個(gè)指示計(jì)劃相當(dāng)關(guān)鍵——當(dāng)我想創(chuàng)建系統(tǒng)類型查找時(shí)為什么要采用號(hào)碼作為主索引字段呢?我可以用傳真號(hào)碼進(jìn)行檢索,但是它幾乎就象系統(tǒng)類型一樣對(duì)我來說并不重要。采用后者作為主字段,數(shù)據(jù)庫(kù)更新后重新索引和檢索就快多了。

          可操作數(shù)據(jù)倉(cāng)庫(kù)(ODS)和數(shù)據(jù)倉(cāng)庫(kù)(DW)這兩種環(huán)境下的數(shù)據(jù)索引是有差別的。在 DW 環(huán)境下,你要考慮銷售部門是如何組織銷售活動(dòng)的。他們并不是數(shù)據(jù)庫(kù)管理員,但是他們確定表內(nèi)的鍵信息。這里設(shè)計(jì)人員或者數(shù)據(jù)庫(kù)工作人員應(yīng)該分析數(shù)據(jù)庫(kù)結(jié)構(gòu)從而確定出性能和正確輸出之間的最佳條件。
          使用系統(tǒng)生成的主鍵
          這類同技巧 1,但我覺得有必要在這里重復(fù)提醒大家。假如你總是在設(shè)計(jì)數(shù)據(jù)庫(kù)的時(shí)候采用系統(tǒng)生成的鍵作為主鍵,那么你實(shí)際控制了數(shù)據(jù)庫(kù)的索引完整性。這樣,數(shù)據(jù)庫(kù)和非人工機(jī)制就有效地控制了對(duì)存儲(chǔ)數(shù)據(jù)中每一行的訪問。
          采用系統(tǒng)生成鍵作為主鍵還有一個(gè)優(yōu)點(diǎn):當(dāng)你擁有一致的鍵結(jié)構(gòu)時(shí),找到邏輯缺陷很容易。
          分解字段用于索引
          為了分離命名字段和包含字段以支持用戶定義的報(bào)表,請(qǐng)考慮分解其他字段(甚至主鍵)為其組成要素以便用戶可以對(duì)其進(jìn)行索引。索引將加快 SQL 和報(bào)表生成器腳本的執(zhí)行速度。比方說,我通常在必須使用 SQL LIKE 表達(dá)式的情況下創(chuàng)建報(bào)表,因?yàn)?case number 字段無法分解為 year、serial number、case type 和 defendant code 等要素。性能也會(huì)變壞。假如年度和類型字段可以分解為索引字段那么這些報(bào)表運(yùn)行起來就會(huì)快多了。
          鍵設(shè)計(jì) 4 原則
          * 為關(guān)聯(lián)字段創(chuàng)建外鍵。
          * 所有的鍵都必須唯一。
          * 避免使用復(fù)合鍵。
          * 外鍵總是關(guān)聯(lián)唯一的鍵字段。
          別忘了索引
          索引是從數(shù)據(jù)庫(kù)中獲取數(shù)據(jù)的最高效方式之一。95% 的數(shù)據(jù)庫(kù)性能問題都可以采用索引技術(shù)得到解決。作為一條規(guī)則,我通常對(duì)邏輯主鍵使用唯一的成組索引,對(duì)系統(tǒng)鍵(作為存儲(chǔ)過程)采用唯一的非成組索引,對(duì)任何外鍵列[字段]采用非成組索引。不過,索引就象是鹽,太多了菜就咸了。你得考慮數(shù)據(jù)庫(kù)的空間有多大,表如何進(jìn)行訪問,還有這些訪問是否主要用作讀寫。

          大多數(shù)數(shù)據(jù)庫(kù)都索引自動(dòng)創(chuàng)建的主鍵字段,但是可別忘了索引外鍵,它們也是經(jīng)常使用的鍵,比如運(yùn)行查詢顯示主表和所有關(guān)聯(lián)表的某條記錄就用得上。還有,不要索引 memo/note 字段,不要索引大型字段(有很多字符),這樣作會(huì)讓索引占用太多的存儲(chǔ)空間。
          不要索引常用的小型表
          不要為小型數(shù)據(jù)表設(shè)置任何鍵,假如它們經(jīng)常有插入和刪除操作就更別這樣作了。對(duì)這些插入和刪除操作的索引維護(hù)可能比掃描表空間消耗更多的時(shí)間。
          不要把社會(huì)保障號(hào)碼(SSN)或身份證號(hào)碼(ID)選作鍵
          永遠(yuǎn)都不要使用 SSN 或 ID 作為數(shù)據(jù)庫(kù)的鍵。除了隱私原因以外,須知政府越來越趨向于不準(zhǔn)許把 SSN 或 ID 用作除收入相關(guān)以外的其他目的,SSN 或 ID 需要手工輸入。永遠(yuǎn)不要使用手工輸入的鍵作為主鍵,因?yàn)橐坏┠爿斎脲e(cuò)誤,你唯一能做的就是刪除整個(gè)記錄然后從頭開始。

          我在破解他人的程序時(shí)候,我看到很多人把 SSN 或 ID 還曾被用做系列號(hào),當(dāng)然盡管這么做是非法的。而且人們也都知道這是非法的,但他們已經(jīng)習(xí)慣了。后來,隨著盜取身份犯罪案件的增加,我現(xiàn)在的同行正痛苦地從一大攤子數(shù)據(jù)中把 SSN 或 ID 刪除。
          不要用用戶的鍵
          在確定采用什么字段作為表的鍵的時(shí)候,可一定要小心用戶將要編輯的字段。通常的情況下不要選擇用戶可編輯的字段作為鍵。這樣做會(huì)迫使你采取以下兩個(gè)措施:
          * 在創(chuàng)建記錄之后對(duì)用戶編輯字段的行為施加限制。假如你這么做了,你可能會(huì)發(fā)現(xiàn)你的應(yīng)用程序在商務(wù)需求突然發(fā)生變化,而用戶需要編輯那些不可編輯的字段時(shí)缺乏足夠的靈活性。當(dāng)用戶在輸入數(shù)據(jù)之后直到保存記錄才發(fā)現(xiàn)系統(tǒng)出了問題他們?cè)撛趺聪耄縿h除重建?假如記錄不可重建是否讓用戶走開?
          * 提出一些檢測(cè)和糾正鍵沖突的方法。通常,費(fèi)點(diǎn)精力也就搞定了,但是從性能上來看這樣做的代價(jià)就比較大了。還有,鍵的糾正可能會(huì)迫使你突破你的數(shù)據(jù)和商業(yè)/用戶界面層之間的隔離。
          所以還是重提一句老話:你的設(shè)計(jì)要適應(yīng)用戶而不是讓用戶來適應(yīng)你的設(shè)計(jì)。

          不讓主鍵具有可更新性的原因是在關(guān)系模式下,主鍵實(shí)現(xiàn)了不同表之間的關(guān)聯(lián)。比如,Customer 表有一個(gè)主鍵 CustomerID,而客戶的定單則存放在另一個(gè)表里。Order 表的主鍵可能是 OrderNo 或者 OrderNo、CustomerID 和日期的組合。不管你選擇哪種鍵設(shè)置,你都需要在 Order 表中存放 CustomerID 來保證你可以給下定單的用戶找到其定單記錄。
          假如你在 Customer 表里修改了 CustomerID,那么你必須找出 Order 表中的所有相關(guān)記錄對(duì)其進(jìn)行修改。否則,有些定單就會(huì)不屬于任何客戶——數(shù)據(jù)庫(kù)的完整性就算完蛋了。
          如果索引完整性規(guī)則施加到表一級(jí),那么在不編寫大量代碼和附加刪除記錄的情況下幾乎不可能改變某一條記錄的鍵和數(shù)據(jù)庫(kù)內(nèi)所有關(guān)聯(lián)的記錄。而這一過程往往錯(cuò)誤叢生所以應(yīng)該盡量避免。
          可選鍵(候選鍵)有時(shí)可做主鍵
          記住,查詢數(shù)據(jù)的不是機(jī)器而是人。
          假如你有可選鍵,你可能進(jìn)一步把它用做主鍵。那樣的話,你就擁有了建立強(qiáng)大索引的能力。這樣可以阻止使用數(shù)據(jù)庫(kù)的人不得不連接數(shù)據(jù)庫(kù)從而恰當(dāng)?shù)倪^濾數(shù)據(jù)。在嚴(yán)格控制域表的數(shù)據(jù)庫(kù)上,這種負(fù)載是比較醒目的。如果可選鍵真正有用,那就是達(dá)到了主鍵的水準(zhǔn)。
          我的看法是,假如你有可選鍵,比如國(guó)家表內(nèi)的 state_code,你不要在現(xiàn)有不能變動(dòng)的唯一鍵上創(chuàng)建后續(xù)的鍵。你要做的無非是創(chuàng)建毫無價(jià)值的數(shù)據(jù)。如你因?yàn)檫^度使用表的后續(xù)鍵[別名]建立這種表的關(guān)聯(lián),操作負(fù)載真得需要考慮一下了。
          別忘了外鍵
          大多數(shù)數(shù)據(jù)庫(kù)索引自動(dòng)創(chuàng)建的主鍵字段。但別忘了索引外鍵字段,它們?cè)谀阆氩樵冎鞅碇械挠涗浖捌潢P(guān)聯(lián)記錄時(shí)每次都會(huì)用到。還有,不要索引 memo/notes 字段而且不要索引大型文本字段(許多字符),這樣做會(huì)讓你的索引占據(jù)大量的數(shù)據(jù)庫(kù)空間。
          第 4 部分 - 保證數(shù)據(jù)的完整性
          用約束而非商務(wù)規(guī)則強(qiáng)制數(shù)據(jù)完整性
          如果你按照商務(wù)規(guī)則來處理需求,那么你應(yīng)當(dāng)檢查商務(wù)層次/用戶界面:如果商務(wù)規(guī)則以后發(fā)生變化,那么只需要進(jìn)行更新即可。假如需求源于維護(hù)數(shù)據(jù)完整性的需要,那么在數(shù)據(jù)庫(kù)層面上需要施加限制條件。如果你在數(shù)據(jù)層確實(shí)采用了約束,你要保證有辦法把更新不能通過約束檢查的原因采用用戶理解的語言通知用戶界面。除非你的字段命名很冗長(zhǎng),否則字段名本身還不夠。

          只要有可能,請(qǐng)采用數(shù)據(jù)庫(kù)系統(tǒng)實(shí)現(xiàn)數(shù)據(jù)的完整性。這不但包括通過標(biāo)準(zhǔn)化實(shí)現(xiàn)的完整性而且還包括數(shù)據(jù)的功能性。在寫數(shù)據(jù)的時(shí)候還可以增加觸發(fā)器來保證數(shù)據(jù)的正確性。不要依賴于商務(wù)層保證數(shù)據(jù)完整性;它不能保證表之間(外鍵)的完整性所以不能強(qiáng)加于其他完整性規(guī)則之上。
          分布式數(shù)據(jù)系統(tǒng)
          對(duì)分布式系統(tǒng)而言,在你決定是否在各個(gè)站點(diǎn)復(fù)制所有數(shù)據(jù)還是把數(shù)據(jù)保存在一個(gè)地方之前應(yīng)該估計(jì)一下未來 5 年或者 10 年的數(shù)據(jù)量。當(dāng)你把數(shù)據(jù)傳送到其他站點(diǎn)的時(shí)候,最好在數(shù)據(jù)庫(kù)字段中設(shè)置一些標(biāo)記。在目的站點(diǎn)收到你的數(shù)據(jù)之后更新你的標(biāo)記。為了進(jìn)行這種數(shù)據(jù)傳輸,請(qǐng)寫下你自己的批處理或者調(diào)度程序以特定時(shí)間間隔運(yùn)行而不要讓用戶在每天的工作后傳輸數(shù)據(jù)。本地拷貝你的維護(hù)數(shù)據(jù),比如計(jì)算常數(shù)和利息率等,設(shè)置版本號(hào)保證數(shù)據(jù)在每個(gè)站點(diǎn)都完全一致。
          強(qiáng)制指示完整性(參照完整性?)
          沒有好辦法能在有害數(shù)據(jù)進(jìn)入數(shù)據(jù)庫(kù)之后消除它,所以你應(yīng)該在它進(jìn)入數(shù)據(jù)庫(kù)之前將其剔除。激活數(shù)據(jù)庫(kù)系統(tǒng)的指示完整性特性。這樣可以保持?jǐn)?shù)據(jù)的清潔而能迫使開發(fā)人員投入更多的時(shí)間處理錯(cuò)誤條件。
          關(guān)系
          如果兩個(gè)實(shí)體之間存在多對(duì)一關(guān)系,而且還有可能轉(zhuǎn)化為多對(duì)多關(guān)系,那么你最好一開始就設(shè)置成多對(duì)多關(guān)系。從現(xiàn)有的多對(duì)一關(guān)系轉(zhuǎn)變?yōu)槎鄬?duì)多關(guān)系比一開始就是多對(duì)多關(guān)系要難得多。
          采用視圖
          為了在你的數(shù)據(jù)庫(kù)和你的應(yīng)用程序代碼之間提供另一層抽象,你可以為你的應(yīng)用程序建立專門的視圖而不必非要應(yīng)用程序直接訪問數(shù)據(jù)表。這樣做還等于在處理數(shù)據(jù)庫(kù)變更時(shí)給你提供了更多的自由。
          給數(shù)據(jù)保有和恢復(fù)制定計(jì)劃
          考慮數(shù)據(jù)保有策略并包含在設(shè)計(jì)過程中,預(yù)先設(shè)計(jì)你的數(shù)據(jù)恢復(fù)過程。采用可以發(fā)布給用戶/開發(fā)人員的數(shù)據(jù)字典實(shí)現(xiàn)方便的數(shù)據(jù)識(shí)別同時(shí)保證對(duì)數(shù)據(jù)源文檔化。編寫在線更新來“更新查詢”供以后萬一數(shù)據(jù)丟失可以重新處理更新。
          用存儲(chǔ)過程讓系統(tǒng)做重活
          解決了許多麻煩來產(chǎn)生一個(gè)具有高度完整性的數(shù)據(jù)庫(kù)解決方案之后,我決定封裝一些關(guān)聯(lián)表的功能組,提供一整套常規(guī)的存儲(chǔ)過程來訪問各組以便加快速度和簡(jiǎn)化客戶程序代碼的開發(fā)。數(shù)據(jù)庫(kù)不只是一個(gè)存放數(shù)據(jù)的地方,它也是簡(jiǎn)化編碼之地。
          使用查找
          控制數(shù)據(jù)完整性的最佳方式就是限制用戶的選擇。只要有可能都應(yīng)該提供給用戶一個(gè)清晰的價(jià)值列表供其選擇。這樣將減少鍵入代碼的錯(cuò)誤和誤解同時(shí)提供數(shù)據(jù)的一致性。某些公共數(shù)據(jù)特別適合查找:國(guó)家代碼、狀態(tài)代碼等。
          第 5 部分 - 各種小技巧
          文檔、文檔、文檔
          對(duì)所有的快捷方式、命名規(guī)范、限制和函數(shù)都要編制文檔。

          采用給表、列[字段]、觸發(fā)器等加注釋的數(shù)據(jù)庫(kù)工具。是的,這有點(diǎn)費(fèi)事,但從長(zhǎng)遠(yuǎn)來看,這樣做對(duì)開發(fā)、支持和跟蹤修改非常有用。

          取決于你使用的數(shù)據(jù)庫(kù)系統(tǒng),可能有一些軟件會(huì)給你一些供你很快上手的文檔。你可能希望先開始在說,然后獲得越來越多的細(xì)節(jié)。或者你可能希望周期性的預(yù)排,在輸入新數(shù)據(jù)同時(shí)隨著你的進(jìn)展對(duì)每一部分細(xì)節(jié)化。不管你選擇哪種方式,總要對(duì)你的數(shù)據(jù)庫(kù)文檔化,或者在數(shù)據(jù)庫(kù)自身的內(nèi)部或者單獨(dú)建立文檔。這樣,當(dāng)你過了一年多時(shí)間后再回過頭來做第 2 個(gè)版本,你犯錯(cuò)的機(jī)會(huì)將大大減少。
          使用常用英語(或者其他任何語言)而不要使用編碼
          為什么我們經(jīng)常采用編碼(比如 9935A 可能是‘青島啤酒’的供應(yīng)代碼,4XF788-Q 可能是帳目編碼)?理由很多。但是用戶通常都用英語進(jìn)行思考而不是編碼。工作 5 年的會(huì)計(jì)或許知道 4XF788-Q 是什么東西,但新來的可就不一定了。在創(chuàng)建下拉菜單、列表、報(bào)表時(shí)最好按照英語名排序。假如你需要編碼,那你可以在編碼旁附上用戶知道的英語。
          保存常用信息
          讓一個(gè)表專門存放一般數(shù)據(jù)庫(kù)信息非常有用。我常在這個(gè)表里存放數(shù)據(jù)庫(kù)當(dāng)前版本、最近檢查/修復(fù)(對(duì) FoxPro)、關(guān)聯(lián)設(shè)計(jì)文檔的名稱、客戶等信息。這樣可以實(shí)現(xiàn)一種簡(jiǎn)單機(jī)制跟蹤數(shù)據(jù)庫(kù),當(dāng)客戶抱怨他們的數(shù)據(jù)庫(kù)沒有達(dá)到希望的要求而與你聯(lián)系時(shí),這樣做對(duì)非客戶機(jī)/服務(wù)器環(huán)境特別有用。
          測(cè)試、測(cè)試、反復(fù)測(cè)試
          建立或者修訂數(shù)據(jù)庫(kù)之后,必須用用戶新輸入的數(shù)據(jù)測(cè)試數(shù)據(jù)字段。最重要的是,讓用戶進(jìn)行測(cè)試并且同用戶一道保證你選擇的數(shù)據(jù)類型滿足商業(yè)要求。測(cè)試需要在把新數(shù)據(jù)庫(kù)投入實(shí)際服務(wù)之前完成。
          檢查設(shè)計(jì)
          在開發(fā)期間檢查數(shù)據(jù)庫(kù)設(shè)計(jì)的常用技術(shù)是通過其所支持的應(yīng)用程序原型檢查數(shù)據(jù)庫(kù)。換句話說,針對(duì)每一種最終表達(dá)數(shù)據(jù)的原型應(yīng)用,保證你檢查了數(shù)據(jù)模型并且查看如何取出數(shù)據(jù)。
          Microsoft Visual FoxPro 設(shè)計(jì)技巧
          對(duì)復(fù)雜的 Microsoft Visual FoxPro 數(shù)據(jù)庫(kù)應(yīng)用程序而言,可以把所有的主表放在一個(gè)數(shù)據(jù)庫(kù)容器文件里,然后增加其他數(shù)據(jù)庫(kù)表文件和裝載同原有數(shù)據(jù)庫(kù)有關(guān)的特殊文件。根據(jù)需要用這些文件連接到主文件中的主表。比如數(shù)據(jù)輸入、數(shù)據(jù)索引、統(tǒng)計(jì)分析、向管理層或者政府部門提供報(bào)表以及各類只讀查詢等。這一措施簡(jiǎn)化了用戶和組權(quán)限的分配,而且有利于應(yīng)用程序函數(shù)(存儲(chǔ)過程)的分組和劃分,從而在程序必須修改的時(shí)候易于管理。


          posted @ 2006-08-07 11:14 nbt 閱讀(341) | 評(píng)論 (0)編輯 收藏

          Svn使用手記

          一、 軟件下載并安裝

          1、? 服務(wù)器

          1 )下載 Subversion 服務(wù)器端軟件,網(wǎng)址: http://subversion.tigris.org/ 。在下載頁面找到 Windows NT, 2000, XP and 2003 然后點(diǎn)擊相關(guān)連接進(jìn)入即可下載,目前最新版本是 svn-1.3.2-setup.exe

          2 )下載后,運(yùn)行 svn-1.3.2-setup.exe 直到安裝成功。

          2、? 客戶端

          1 )下載 Subversion windows 客戶端程序 TortoiseSVN 和中文語言包,網(wǎng)址: http://tortoisesvn.tigris.org/ 。目前最新版本是 TortoiseSVN-1.3.5.6804-svn-1.3.2.msi LanguagePack-1.3.5.6804-win32-zh_CN.exe

          2 )下載后,先運(yùn)行 TortoiseSVN-1.3.5.6804-svn-1.3.2.msi 安裝程序,完成后,提示要重啟計(jì)算機(jī),選擇“否”,運(yùn)行中文語言包程序完成后再重啟計(jì)算機(jī)。

          二、 建立版本庫(kù)
          運(yùn)行 Subversion 服務(wù)器需要首先要建立一個(gè)版本庫(kù)( Repository ),可以看作服務(wù)器上存放數(shù)據(jù)的數(shù)據(jù)庫(kù),有兩種方法可以建立版本庫(kù):
          1、? 命令行方法:在命令行模式下,運(yùn)行 svnadmin create f:\repository ,即可在 F 盤下創(chuàng)建一個(gè)版本庫(kù) repository
          2、? 界面操作方法:在 F:\repository 目錄下,右鍵,選擇 TortoiseSVN 下的“在此創(chuàng)建文件庫(kù)”,文件庫(kù)類型選擇默認(rèn)的“本地文件系統(tǒng) (FSFS) ”,這樣就會(huì)在該目錄下創(chuàng)建一個(gè)版本庫(kù)。

          三、 配置用戶和權(quán)限

          1、? F:\repository\conf\svnserve.conf 文件中去掉 # password-db = passwd 項(xiàng)前面的 # 號(hào)和空格(空格一定要去掉,否則會(huì)報(bào)錯(cuò))。

          svnserve.conf 文件內(nèi)容如下:

          [general]

          # anon-access = read

          # auth-access = write

          # password-db = passwd

          # authz-db = authz

          # realm = My First Repository

          各參數(shù)定義如下:

          anon-access :定義非授權(quán)用戶的訪問權(quán)限,有三種方式: none read write ,設(shè)置為 none 限制訪問, read 為只讀, write 為具有讀寫權(quán)限,默認(rèn)為 read

          auth-access :定義授權(quán)用戶的訪問權(quán)限,有三種方式: none read write ,設(shè)置為 none 限制訪問, read 為只讀, write 為具有讀寫權(quán)限,默認(rèn)為 write

          password-db :定義保存用戶名和密碼的文件名稱,這里為 passwd ,和該文件位于同一目錄。

          authz-db :定義保存授權(quán)信息的文件名稱,這里為 authz ,和該文件位于同一目錄。

          realm :定義客戶端連接是的“認(rèn)證命名空間”, Subversion 會(huì)在認(rèn)證提示里顯示,并且作為憑證緩存的關(guān)鍵字。

          2、? F:\repository\conf\ passwd 文件中去掉 # harry = harryssecret # sally = sallyssecret 兩項(xiàng)前面的 # 號(hào)和空格。

          passwd 文件內(nèi)容如下:

          [users]

          # harry = harryssecret

          # sally = sallyssecret

          這里定義了兩個(gè)用戶 harry sally ,用戶密碼分別是 harryssecret sallyssecret 。同樣,我們還可以定義自己的用戶名和密碼。

          四、 運(yùn)行服務(wù)器

          在命令行模式下,運(yùn)行 svnserve –d –r f:\repository ,服務(wù)器即可啟動(dòng)。

          五、 初始文件導(dǎo)入
          1、
          在我們想要做版本控制的項(xiàng)目根目錄下,右鍵,選擇 TortoiseSVN 中的導(dǎo)入,

          2、然后提示輸入文件庫(kù)路徑,如: svn://localhost/repository

          3、確定后提示要輸入用戶名和密碼,輸入我們?cè)?/span> passwd 文件中定義的用戶名和密碼后(如用戶名為 harry ,密碼為 harryssecret ),數(shù)據(jù)就導(dǎo)入到我們定義的版本庫(kù) repository 中了。

          六、 客戶端操作

          1、? 從版本庫(kù)中取出項(xiàng)目:

          在右鍵菜單中選擇“ SVN 取出”, 然后在“文件庫(kù) URL ”一欄填寫 Subversion 服務(wù)器上文件庫(kù)的路徑,如: svn://localhost/repository ,確定后,就可以取出文件庫(kù) repository 中的文件。 ?

          2、? 更新項(xiàng)目:

          在右鍵菜單中選擇“ SVN 更新”就可以將文件庫(kù)中最新版本的文件取到本地計(jì)算機(jī)上。

          3、? 提交修改:

          對(duì)修改過的文件確定沒有問題后即可提交到文件庫(kù)中, 確定后,即可將修改過的文件提交到版本庫(kù)中。

          4、? 查看文件庫(kù)

          選擇“文件庫(kù)瀏覽器”菜單,就可以打開 Subversion 服務(wù)器上可見的文件庫(kù), 并可以對(duì)文件庫(kù)中的文件及文件夾進(jìn)行操作。

          posted @ 2006-08-07 10:29 nbt 閱讀(315) | 評(píng)論 (0)編輯 收藏

          Excel報(bào)表之js版

          (轉(zhuǎn)自--http://www.aygfsteel.com/beyondduke/archive/2006/08/05/61911.html)
          半年以前做過server端生成excel的簡(jiǎn)單引擎,總感覺不夠輕便,尤其在一些固定格式,數(shù)據(jù)量又不是很大的情況下,上周寫了一

          個(gè)根據(jù)表單數(shù)據(jù)在client端用js生成excle的demo,令我我激動(dòng)了半天------js太強(qiáng)了!

          下面分享一下這段js:
          ?
          ?1var?excel??=?new?ActiveXObject("Excel.Application");?//創(chuàng)建AX對(duì)象excel
          ?2excel.visible?=true;?//設(shè)置excel可見屬性
          ?3var?workbook?=?excel.Workbooks.Add;?//獲取workbook對(duì)象
          ?4var?sheet1?=?xlBook.Worksheets(2);??//創(chuàng)建sheet1
          ?5var?sheet2?=?xlBook.Worksheets(1);??//創(chuàng)建sheet2
          ?6sheet1.Range(sheet1.Cells(1,1),sheet1.Cells(1,14)).mergecells=true;?//合并單元格
          ?7sheet1.Range(sheet1.Cells(1,1),sheet1.Cells(1,14)).value="員工月考核成績(jī)";?//設(shè)置單元格內(nèi)容
          ?8sheet1.Range(sheet1.Cells(1,1),sheet1.Cells(1,14)).Interior.ColorIndex=6;//設(shè)置底色?
          ?9sheet1.Range(sheet1.Cells(1,1),sheet1.Cells(1,14)).Font.ColorIndex=5;//設(shè)置字體色?
          10sheet1.Rows(1).RowHeight?=?20;?//設(shè)置列高
          11sheet1.Rows(1).Font.Size=16;??//設(shè)置文字大小
          12sheet1.Rows(1).Font.Name="宋體";?//設(shè)置字體
          13//設(shè)置每一列的標(biāo)題
          14sheet1.Cells(2,1).Value="工程師考核項(xiàng)";
          15sheet1.Cells(2,2).Value="總分";
          16sheet1.Cells(2,3).Value="研發(fā)進(jìn)度";
          17sheet1.Cells(2,4).Value="出勤率";
          18sheet1.Cells(2,5).Value="執(zhí)行力";
          19sheet1.Cells(2,6).Value="責(zé)任心";
          20sheet1.Cells(2,7).Value="工作規(guī)范";
          21sheet1.Cells(2,8).Value="協(xié)作精神";
          22sheet1.Cells(2,9).Value="進(jìn)取性";
          23sheet1.Cells(2,10).Value="工作合理性";
          24sheet1.Cells(2,11).Value="解決問題能力";
          25sheet1.Cells(2,12).Value="應(yīng)變能力";
          26sheet1.Cells(2,13).Value="人際技能";
          27sheet1.Cells(2,14).Value="理解能力";
          28//從表單循環(huán)控件中取出數(shù)據(jù)逐行插入對(duì)應(yīng)列的數(shù)據(jù)
          29var?count?=?sfform.GetAttributeValue('Repeat','Count');
          30for(var?line=1;line<=count;line++){?//begin?for
          31??var?name??=?sfform.GetValue('Repeat['+line+'].name');
          32??var?total=?sfform.GetValue('Repeat['+line+'].total');
          33??var?yfjd?=?sfform.GetValue('Repeat['+line+'].yfjd');
          34??var?jh?=?sfform.GetValue('Repeat['+line+'].jh');
          35??var?gcgj?=?sfform.GetValue('Repeat['+line+'].gcgj');
          36??var?cql?=?sfform.GetValue('Repeat['+line+'].cql');
          37??var?zxl?=?sfform.GetValue('Repeat['+line+'].zxl');
          38??var?gzgf?=?sfform.GetValue('Repeat['+line+'].gzgf');
          39??var?zrx?=?sfform.GetValue('Repeat['+line+'].zrx');
          40??var?xzjs?=?sfform.GetValue('Repeat['+line+'].xzjs');
          41??var?jqx?=?sfform.GetValue('Repeat['+line+'].jqx');
          42??var?gzhl?=?sfform.GetValue('Repeat['+line+'].gzh');
          43??var?jjwt?=?sfform.GetValue('Repeat['+line+'].jjwt');
          44??var?ybnl?=?sfform.GetValue('Repeat['+line+'].ybnl');
          45??var?rjjn?=?sfform.GetValue('Repeat['+line+'].rjjn');
          46??var?ljnl?=?sfform.GetValue('Repeat['+line+'].ljnl');
          47??sheet1.Cells(2+line,1).Value=name;
          48??sheet1.Cells(2+line,2).Value=total;
          49??sheet1.Cells(2+line,3).Value=yfjd;
          50??sheet1.Cells(2+line,4).Value=cql;
          51??sheet1.Cells(2+line,5).Value=zxl;
          52??sheet1.Cells(2+line,6).Value=gzgf;
          53??sheet1.Cells(2+line,7).Value=zrx;
          54??sheet1.Cells(2+line,8).Value=xzjs;
          55??sheet1.Cells(2+line,9).Value=jqx;
          56??sheet1.Cells(2+line,10).Value=gzhl;
          57??sheet1.Cells(2+line,11).Value=jjwt;
          58??sheet1.Cells(2+line,12).Value=ybnl;
          59??sheet1.Cells(2+line,13).Value=rjjn;
          60??sheet1.Cells(2+line,14).Value=ljnl;
          61
          62}
          //end?for
          63
          64

          基本的代碼已經(jīng)實(shí)現(xiàn)了,生成excel的格式和一些統(tǒng)計(jì)計(jì)算,用js寫應(yīng)該是很方便的,以后有例子再作補(bǔ)充。

          從代碼角度來看這種寫法不是很靈活,但在能滿足用戶的需求前提下,這種生成方式還是很受歡迎的,給用戶的感覺就是輕

          便。個(gè)人認(rèn)為簡(jiǎn)單就是美!

          posted @ 2006-08-07 10:16 nbt 閱讀(408) | 評(píng)論 (0)編輯 收藏

          java enum 枚舉類

          (轉(zhuǎn)自http://www.aygfsteel.com/dazuiba/archive/2006/08/04/j2se_enum.html)

          1 定義在常量類中
          ????
          ??? 經(jīng)常碰到要將枚舉類當(dāng)成常量使用的情況,這不僅可以將相關(guān)的常量定義到一個(gè)枚舉類中,而且還可以利用枚舉類強(qiáng)大而又靈活的功能,在加上編譯器內(nèi)置的支持,使得在eclipse下的編程更方便,引入的bug更少。
          ??? 一般規(guī)模的項(xiàng)目中都會(huì)用一個(gè)單獨(dú)的類來定義系統(tǒng)中用到的常量,起碼筆者經(jīng)歷的幾個(gè)項(xiàng)目都是有此種做法,該做法的好處就是便于集中管理,雖然這違背類封裝的原則,但鑒于其易用性,我們還是會(huì)常常這么做。
          ??? 例子:

          public?class?SystemConstant?{
          ????
          /**
          ?????*?金庫(kù) sourceortarget?系統(tǒng)相關(guān)
          ?????
          */

          ????
          public?static?final?String?CASHWASTEBOOK_SOURCEORTARGET_SYS?=?"系統(tǒng)";
          ????
          /**
          ?????*?附件上傳路徑
          ?????
          */
          ?
          ????
          public?static?String?UPLOAD_ATTACHMENT_DIR="upload\\";
          ????
          public?static?String?CONFIG_DIR="config\\";
          ????
          /**
          ?????*?臨時(shí)文件路徑
          ?????
          */

          ????
          public?static?String?TEMP_DIR="temp\\";
          ????
          /**
          ?????*?會(huì)員關(guān)系
          ?????
          */

          ????
          public?static?enum?Relationship?{
          ????????GoodFriend(
          "親密好友"),
          ????????CommonFriend(
          "普通朋友"),
          ????????BLACK(
          "不受歡迎");
          ????????
          private???String?v;
          ????????
          ????????Relationship(String?value)?
          {
          ??????????v?
          =?value;
          ????????}

          ????????@Override
          ????????
          public?String?toString()?{????????
          ????????????
          return?v;
          ????????}
          ?
          ??????}
          ??
          ????
          public?static?final?String?SUCCESS?=?"OK";
          ????
          /**用戶選擇管理員登錄*/
          ????
          public?static?final?String?MESSAGE_LOGIN_TYPEERROR1?=?"您不能選擇管理員登錄";
          ????
          /**管理員選擇會(huì)員或家長(zhǎng)登錄*/
          ????
          public?static?final?String?MESSAGE_LOGIN_TYPEERROR2?=?"您應(yīng)該選擇管理員登錄";
          ????
          /**會(huì)員或家長(zhǎng)重復(fù)登陸*/
          ????
          public?static?final?String?MESSAGE_LOGIN_REPEAT?=?"可能因?yàn)橐韵略颍鸁o法登陸系統(tǒng)\n\t1 有人盜用您的帳號(hào)\n2?您的{0}正在使用本帳號(hào)";
          ????
          public?static?final?String?MESSAGE_LONGIN_PASSWORDERROR?=?"用戶名或密碼無效";
          ????
          public?static?final?String?MESSAGE_INSUFFICIENT_FUNDS?=?"您的帳戶余額不足";
          ????
          public?static?final?String?MESSAGE_MEMBER_ONLINETIME_FULL?=?"您今日的累計(jì)上線時(shí)間已超過1.5小時(shí)";
          ????
          /**會(huì)員每天最大登錄時(shí)限?單位分鐘?默認(rèn)90**/
          ????
          public?static?final?int?MEMBER_MAX_DAY_ONLINE_MINUTES?=?90;
          ????
          }

          ??
          ??? 可以看到,枚舉類型Relationship是定義一些會(huì)員關(guān)系之間的東東,其實(shí)我可以把它單獨(dú)定義一個(gè)類,或者放到Member(會(huì)員)這個(gè)類中,但綜合考慮,我還是覺得放到SystemConstant比較好,并且今后重構(gòu)SystemConstant,會(huì)添加從xml文件讀取屬性的功能。
          ?? ? 雖然Relationship是一個(gè)內(nèi)部類,但由于是靜態(tài)的,所以可以直接import,而無須每次都用SystemConstant.Relationship;
          ?例如:
          ?? ?public Relationship getRelationship() {
          ????????? ?return Relationship.valueOf(relationship);
          ?????? ?}

          ? 2 說到從xml文件讀取屬性來動(dòng)態(tài)配置枚舉類,我下面就舉個(gè)例子,演示演示
          ???? 一些web系統(tǒng)中涉及到文件上傳,根據(jù)文件類型顯示相應(yīng)圖標(biāo),并且有些jsp,asp等等的文件不允許上傳,下面就是一個(gè)滿足這種需求的枚舉類,它最大的特點(diǎn)就是可以從xml中讀取配置信息
          /**
          ?*?系統(tǒng)中用到的文件擴(kuò)展名?枚舉類
          ?*?
          @author?zgy
          ?*
          ?
          */

          public?enum?FileExtension?{
          ????doc,?jsp,?jpeg,?jpg,?rar,?zip,?txt,unknown;

          ????
          private?boolean?allow;
          ?

          ????
          private?String?comment;

          ????
          private?String?iconPath;
          ????
          static?{
          ????????loadFromXml();?
          ????}
          ?
          ????FileExtension()?
          {
          ????????
          this.iconPath?=?"\\"?+?name();
          ????????
          this.allow?=?true;
          ????????
          this.comment?=?"comment?for"?+?name();
          ????}
          ????
          ????
          /**
          ?????*?從config目錄中l(wèi)oad
          ?????*?
          ?????
          */

          ????
          private?static?void?loadFromXml()?{
          ????????
          try?{
          ????????????Document?doc?
          =?XmlUtil.parseXmlFile(SystemConstant.CONFIG_DIR
          ????????????????????
          +?"fileExtension.xml");
          ????????????NodeList?extensionList?
          =?doc.getElementsByTagName("FileExtension");
          ????????????
          for?(int?i?=?0;?i?<?extensionList.getLength();?i++)?{
          ????????????????Element?item?
          =?(Element)?extensionList.item(i);
          ????????????????String?name?
          =?item.getAttribute("name");
          ????????????????FileExtension?em?
          =?FileExtension.valueOf(name);
          ????????????????em.allow?
          =?Boolean.parseBoolean(item.getAttribute("allow"));
          ????????????????em.iconPath?
          =?item.getAttribute("iconPath");
          ????????????????em.comment?
          =?item.getAttribute("comment");?
          ????????????}

          ????????}
          ?catch?(Exception?e)?{?
          ????????????
          throw?new?RuntimeException(e);
          ????????}

          ????}


          ????
          public?boolean?isAllow()?{
          ????????
          return?allow;
          ????}


          ????
          public?String?getComment()?{
          ????????
          return?comment;
          ????}
          ?
          ????
          public?String?getUploadIcon()?{
          ????????
          return?iconPath;
          ????}


          ????
          public?static?void?main(String[]?args)?{
          ????????System.out.println(FileExtension.doc.comment);
          ????}

          }


          配置文件如下:config/fileExtension.xml
          <?xml version="1.0" encoding="UTF-8"?>
          <FileExtensions>
          ?<FileExtension name="doc" iconPath="doc.jpg" allow="true"?? comment="文本"/>
          ?<FileExtension name="jpg" iconPath="jpg.jpg" allow="true"?? comment=""/>
          ?<FileExtension name="jpeg" iconPath="jpeg.jpg" allow="true" comment=""/>
          ?<FileExtension name="rar" iconPath="rar.jpg" allow="true"?? comment=""/>
          ?<FileExtension name="zip" iconPath="zip.jpg" allow="true"?? comment=""/>
          ?<FileExtension name="txt" iconPath="txt.jpg" allow="true"?? comment=""/>
          ??? <FileExtension name="jsp" iconPath="jsp.jpg" allow="false"? comment=""/>
          </FileExtensions>

          可能系統(tǒng)中其他的一些枚舉類(比如1 中提到的RelationShip)也會(huì)用到非常類似的做法,這時(shí)候我們就可以重構(gòu)了,將一些共同的特點(diǎn)抽取到一個(gè)抽象類中。這將會(huì)在以后的文章中提到。
          有不同的觀點(diǎn),請(qǐng)聯(lián)系come2u at gmail.com? ,歡迎交流。

          posted @ 2006-08-07 09:38 nbt 閱讀(658) | 評(píng)論 (0)編輯 收藏

          Java文件操作詳解

          輸入輸出流?
          在Java中,我們把能夠讀取一個(gè)字節(jié)序列的對(duì)象稱作一個(gè)輸入流;而我們把夠?qū)懸粋€(gè)字節(jié)序列稱作一個(gè)輸出流。它們分別由抽象類?
          InputStream和OutputStream類表示。因?yàn)槊嫦蜃止?jié)的流不方便用來處理存儲(chǔ)為Unicode(每個(gè)字符使用兩個(gè)字節(jié))的信息。所以Java?
          引入了用來處理Unicode字符的類層次,這些類派生自抽象類Reader和Writer,它們用于讀寫雙字節(jié)的Unicode字符,而不是單字節(jié)字符。?
          Java.io包簡(jiǎn)介?
          JDK標(biāo)準(zhǔn)幫助文檔是這樣解釋Java.io包的,通過數(shù)據(jù)流、序列和文件系統(tǒng)為系統(tǒng)提供輸入輸出。?
          InputStream類和OutputStream類?
          InputStream類是所有輸入數(shù)據(jù)流的父類,它是一個(gè)抽象類,定義了所有輸入數(shù)據(jù)流都具有的共通特性。?
          java.io.InputStream的方法如下:?
          public?abstract?read()throws?IOException?
          讀取一個(gè)字節(jié)并返回該字節(jié),如果到輸入源的末則返回-1。一個(gè)具體的輸入流類需要重載此方法,以提供?有用的功能。例如:在FileInputStream類中,該方法從一個(gè)文件讀取一個(gè)字節(jié)。?
          public?int?read(byte[]?b)throws?IOException?
          把數(shù)據(jù)讀入到一個(gè)字節(jié)數(shù)據(jù)中,并返回實(shí)際讀取的字節(jié)數(shù)目。如果遇到流末?則返回-1,該方法最多讀取b.length個(gè)字節(jié)。?
          public?abstract?int?read(byte[]?b,int?off,int?len)throws?IOException?
          把數(shù)據(jù)讀入到一個(gè)字節(jié)數(shù)組中并返回實(shí)際讀取的字節(jié)數(shù)目。如果遇到流的末尾則的返回-1。?其中參數(shù)off表示第一個(gè)字節(jié)在b中的位置,len表示讀取的最大字節(jié)數(shù)。?
          public?long?skip(long?n)throws?IOException?
          略過N個(gè)字節(jié)不讀取,會(huì)返回實(shí)際略過的字節(jié)數(shù)目。因?yàn)閿?shù)據(jù)流中剩下的數(shù)據(jù)可能不到N?個(gè)字節(jié)那么多,所以此時(shí)返回值會(huì)小于N。?
          public?int?available()throws?IOException?
          read方法(包括后面要講的OutputStream類的Write方法)都能夠陰塞一個(gè)線程,直到字節(jié)被?實(shí)際讀取或?qū)懭搿_@意味著如果一個(gè)流不能立即被讀或被寫?
          /*?
          *?Created?on?2005-3-10?
          *?To?change?the?template?for?this?generated?file?go?to?
          *?Window>Preferences>Java>Code?Generation>Code?and?Comments?
          */?

          import?java.io.BufferedReader;?
          import?java.io.File;?
          import?java.io.FileReader;?
          import?java.io.FileWriter;?
          import?java.io.IOException;?
          import?java.io.PrintWriter;?
          import?java.io.FileInputStream;;?
          /**?
          *?@author?zhangqinglin?
          *?To?change?the?template?for?this?generated?type?comment?go?to?
          *?Window>Preferences>Java>Code?Generation>Code?and?Comments?
          */?
          public?class?Files?
          {?
          public?static?void?main(String[]?args)?throws?IOException?
          {?
          Files?f?=?new?Files();?
          //?System.out.println(f.readFile("f:\\LinkFile.java"));?
          f.fileIsNull("D:\\java\\","ejb");?
          //f.readLineFile("D:\\java\\","TestFile.txt");?
          //?System.out.println(f.fileIsNull("f:\\","122.txt"));?
          //f.readFolderByFile("F:\\Login");?//不區(qū)分大小寫
          //?System.out.println(f.createAndDeleteFolder("ss","f:\\"));?
          //?System.out.println(f.createAndDeleteFile("f:\\ss\\","TestFile.dat"));?
          //f.createAndDeleteFolder("1","D:\\java\\");
          String[]?ss?=?new?String[50];?//定義對(duì)象數(shù)組
          for(int?i=0;i<ss.length;i++)?
          {?
          ss?=?"信息技術(shù)和互聯(lián)網(wǎng)(計(jì)算機(jī)軟硬件,通訊)?"+i;?
          }?
          f.writeFile("D:\\java\\","TestFile.txt",ss);?

          }?
          /**?
          *?文件的寫入?
          *?@param?filePath(文件路徑)?
          *?@param?fileName(文件名)?
          *?@param?args[]?
          *?@throws?IOException?
          */?
          public?void?writeFile(String?filePath,String?fileName,String[]?args)?throws?IOException?
          {?
          FileWriter?fw?=?new?FileWriter(filePath+fileName);?
          PrintWriter?out=new?PrintWriter(fw);?
          for(int?i=0;i<args.length;i++)?
          {?
          out.write(args);?
          out.println();?
          //out.flush();?
          }
          System.out.println("寫入成功!");?
          fw.close();?
          out.close();?
          }?
          /**?
          *?文件的寫入?
          *?@param?filePath(文件路徑)?
          *?@param?fileName(文件名)?
          *?@param?args?
          *?@throws?IOException?
          */?
          public?void?writeFile(String?filePath,String?fileName,String?args)?throws?IOException?
          {?
          FileWriter?fw?=?new?FileWriter(filePath+fileName);?
          fw.write(args);?
          fw.close();?
          }?
          /**?
          *?創(chuàng)建與刪除文件?
          *?@param?filePath?
          *?@param?fileName?
          *?@return?創(chuàng)建成功返回true?
          *?@throws?IOException?
          */?
          public?boolean?createAndDeleteFile(String?filePath,String?fileName)?throws?IOException?
          {?
          boolean?result?=?false;?
          File?file?=?new?File(filePath,fileName);?
          if(file.exists()){
          if(file.isFile())?
          {?
          file.delete();?
          result?=?true;?
          System.out.println("文件已經(jīng)刪除!");?
          }?
          else?
          {
          ???System.out.println("對(duì)不起,該路徑為目錄!");?
          ???
          }
          }
          else?
          {?
          file.createNewFile();?//jdk5.0的新方法
          result?=?true;?
          System.out.println("文件已經(jīng)創(chuàng)建!");?
          }?
          return?result;?
          }?
          /**?
          *?創(chuàng)建和刪除目錄?
          *?@param?folderName?
          *?@param?filePath?
          *?@return?刪除成功返回true?
          */?
          public?boolean?createAndDeleteFolder(String?folderName,String?filePath)?
          {?
          boolean?result?=?false;?
          try?
          {?
          File?file?=?new?File(filePath+folderName);?
          if(file.exists())?
          {?
          if(file.isDirectory()){
          file.delete();?
          System.out.println("目錄已經(jīng)存在,已刪除!");?
          result?=?true;?
          }
          else{
          System.out.println("對(duì)不起,該路徑為文件!");?
          }
          }?
          else?
          {?
          file.mkdir();?
          System.out.println("目錄不存在,已經(jīng)建立!");?
          result?=?true;?
          }?
          }?
          catch(Exception?ex)?
          {?
          result?=?false;?
          System.out.println("CreateAndDeleteFolder?is?error:"+ex);?
          }?
          return?result;?
          }?
          /**?
          *?輸出目錄中的所有文件及目錄名字?
          *?@param?filePath?
          */?
          public?void?readFolderByFile(String?filePath)
          {?
          File?file?=?new?File(filePath);?
          File[]?tempFile?=?file.listFiles();?
          for(int?i?=?0;i<tempFile.length;i++)?
          {?
          if(tempFile.isFile())?
          {?
          System.out.println("File?:?"+tempFile.getName());?
          }?
          if(tempFile.isDirectory())?
          {?
          System.out.println("Directory?:?"+tempFile.getName());?
          }?
          }?
          }?
          /**?
          *?檢查文件中是否為一個(gè)空?
          *?@param?filePath?
          *?@param?fileName?
          *?@return?為空返回true?
          *?@throws?IOException?
          */?
          public?boolean?fileIsNull(String?filePath,String?fileName)?throws?IOException?
          {?
          boolean?result?=?false;?
          FileReader?fr?=?new?FileReader(filePath+fileName);?
          if(fr.read()?==?-1)?
          {?
          result?=?true;?
          System.out.println(fileName+"?文件中沒有數(shù)據(jù)!");?
          }?
          else?
          {?
          System.out.println(fileName+"?文件中有數(shù)據(jù)!");?
          }?
          fr.close();?
          return?result;?
          }?
          /**?
          *?讀取文件中的所有內(nèi)容?
          *?@param?filePath?
          *?@param?fileName?
          *?@throws?IOException?
          */?
          public?void?readAllFile(String?filePath,String?fileName)?throws?IOException?
          {?
          FileReader?fr?=?new?FileReader(filePath+fileName);?
          //PrintWriter?pr=new?PrintWriter(fr);
          //pr.print
          int?count?=?fr.read();?
          while(count?!=?-1)?
          {?
          System.out.print((char)count);?
          count?=?fr.read();?
          //System.out.println();
          if(count?==?13)?
          {?
          fr.skip(1);?
          System.out.print("跳過!");?
          }
          }?
          System.out.println();?
          fr.close();?
          }?
          /**?
          *?一行一行的讀取文件中的數(shù)據(jù)?
          *?@param?filePath?
          *?@param?fileName?
          *?@throws?IOException?
          */?
          public?void?readLineFile(String?filePath,String?fileName)?throws?IOException?
          {?
          FileReader?fr?=?new?FileReader(filePath+fileName);?
          BufferedReader?br?=?new?BufferedReader(fr);?
          String?line?=?br.readLine();?
          while(line?!=?null)?
          {?
          System.out.println(line);?
          line?=?br.readLine();?
          }?
          br.close();?
          fr.close();?
          }
          }


          /***************************以下是常用的文件操作方法******************************/

          /**?
          ???? *? @see 新建目錄?
          ???? *? @param? folderPath? String? 如? c:/fqf?
          ???? *? @return? boolean?
          ???? */?
          ?? public? void? newFolder(String? folderPath)?
          {?
          ?????? try? {?
          ?????????? String? filePath? =? folderPath;?
          ?????????? filePath? =? filePath.toString();?
          ?????????? java.io.File? myFilePath? =? new? java.io.File(filePath);?
          ?????????? if? (!myFilePath.exists())??
          ????????????{?
          ?????????????? myFilePath.mkdir();?
          ?????????? }?
          ?????? }?
          ?????? catch? (Exception? e)?
          ???????{?
          ?????????? System.out.println("新建目錄操作出錯(cuò)");?
          ?????????? e.printStackTrace();?
          ?????? }?
          ?? }?
          ?
          ?? /**?
          ???? *? @see 新建文件?
          ???? *? @param? filePathAndName? String? 文件路徑及名稱? 如c:/fqf.txt?
          ???? *? @param? fileContent? String? 文件內(nèi)容?
          ???? *? @return? boolean?
          ???? */?
          ?? public? void? newFile(String? filePathAndName,? String? fileContent)? {?
          ?
          ?????? try? {?
          ?????????? String? filePath? =? filePathAndName;?
          ?????????? filePath? =? filePath.toString();?
          ?????????? File? myFilePath? =? new? File(filePath);?
          ?????????? if? (!myFilePath.exists())? {?
          ?????????????? myFilePath.createNewFile();?
          ?????????? }?
          ?????????? FileWriter? resultFile? =? new? FileWriter(myFilePath);?
          ?????????? PrintWriter? myFile? =? new? PrintWriter(resultFile);?
          ?????????? String? strContent? =? fileContent;?
          ?????????? myFile.println(strContent);?
          ?????????? resultFile.close();?
          ?
          ?????? }?
          ?????? catch? (Exception? e)? {?
          ?????????? System.out.println("新建文件操作出錯(cuò)");?
          ?????????? e.printStackTrace();?
          ?
          ?????? }?
          ?
          ?? }?
          ?
          ?? /**?
          ???? *? @see 刪除文件?
          ???? *? @param? filePathAndName? String? 文件路徑及名稱? 如c:/fqf.txt?
          ???? *? @param? fileContent? String?
          ???? *? @return? boolean?
          ???? */?
          ?? public? void? delFile(String? filePathAndName)? {?
          ?????? try? {?
          ?????????? String? filePath? =? filePathAndName;?
          ?????????? filePath? =? filePath.toString();?
          ?????????? java.io.File? myDelFile? =? new? java.io.File(filePath);?
          ?????????? myDelFile.delete();?
          ?????????? System.out.println(myDelFile + "\\文件存在,已刪除。");
          ?
          ?????? }?
          ?????? catch? (Exception? e)? {?
          ?????????? System.out.println("刪除文件操作出錯(cuò)");?
          ?????????? e.printStackTrace();?
          ?
          ?????? }?
          ?
          ?? }?
          ?
          ?? /**?
          ???? *? @see 刪除文件夾?
          ???? *? @param? filePathAndName? String? 文件夾路徑及名稱? 如c:/fqf?
          ???? *? @param? fileContent? String?
          ???? *? @return? boolean?
          ???? */?
          ?? public? void? delFolder(String? folderPath)? {?
          ?????? try? {?
          ?????????? delAllFile(folderPath);? //刪除完里面所有內(nèi)容?
          ?????????? String? filePath? =? folderPath;?
          ?????????? filePath? =? filePath.toString();?
          ?????????? java.io.File? myFilePath? =? new? java.io.File(filePath);?
          ?????????? myFilePath.delete();? //刪除空文件夾?
          ?
          ?????? }?
          ?????? catch? (Exception? e)? {?
          ?????????? System.out.println("刪除文件夾操作出錯(cuò)");?
          ?????????? e.printStackTrace();?
          ?
          ?????? }?
          ?
          ?? }?
          ?
          ?? /**?
          ???? *? @see 刪除文件夾里面的所有文件?
          ???? *? @param? path? String? 文件夾路徑? 如? c:/fqf?
          ???? */?
          ?? public? void? delAllFile(String? path)? {?
          ?????? File? file? =? new? File(path);?
          ?????? if? (!file.exists())? {?
          ?????????? return;?
          ?????? }?
          ?????? if? (!file.isDirectory())? {?
          ?????????? return;?
          ?????? }?
          ?????? String[]? tempList? =? file.list();?
          ?????? File? temp? =? null;?
          ?????? for? (int? i? =? 0;? i? <? tempList.length;? i++)? {?
          ?????????? if? (path.endsWith(File.separator))? {?
          ?????????????? temp? =? new? File(path? +? tempList[i]);?
          ?????????? }?
          ?????????? else? {?
          ?????????????? temp? =? new? File(path? +? File.separator? +? tempList[i]);?
          ?????????? }?
          ?????????? if? (temp.isFile())? {?
          ?????????????? temp.delete();?
          ?????????? }?
          ?????????? if? (temp.isDirectory())? {?
          ?????????????? delAllFile(path+"/"+? tempList[i]);//先刪除文件夾里面的文件?
          ?????????????? delFolder(path+"/"+? tempList[i]);//再刪除空文件夾?
          ?????????? }?
          ?????? }?
          ?? }?
          ?
          ?? /**?
          ???? *? @see 復(fù)制單個(gè)文件?
          ???? *? @param? oldPath? String? 原文件路徑? 如:c:/fqf.txt?
          ???? *? @param? newPath? String? 復(fù)制后路徑? 如:f:/fqf.txt?
          ???? *? @return? boolean?
          ???? */?
          ?? public? void? copyFile(String? oldPath,? String? newPath)? {?
          ?????? try? {?
          ?????????? int? bytesum? =? 0;?
          ?????????? int? byteread? =? 0;?
          ?????????? File? oldfile? =? new? File(oldPath);?
          ?????????? if? (oldfile.exists())? {? //文件存在時(shí)?
          ?????????????? InputStream? inStream? =? new? FileInputStream(oldPath);? //讀入原文件?
          ?????????????? FileOutputStream? fs? =? new? FileOutputStream(newPath);?
          ?????????????? byte[]? buffer? =? new? byte[1444];?
          ?????????????? //int? length = 0;?
          ?????????????? while? (? (byteread? =? inStream.read(buffer))? !=? -1)? {?
          ?????????????????? bytesum? +=? byteread;? //字節(jié)數(shù)? 文件大小?
          ?????????????????? System.out.println(bytesum);?
          ?????????????????? fs.write(buffer,? 0,? byteread);?
          ?????????????? }?
          ?????????????? inStream.close();?
          ?????????? }?
          ?????? }?
          ?????? catch? (Exception? e)? {?
          ?????????? System.out.println("復(fù)制單個(gè)文件操作出錯(cuò)");?
          ?????????? e.printStackTrace();?
          ?
          ?????? }?
          ?
          ?? }?
          ?
          ?? /**?
          ???? *? @see 復(fù)制整個(gè)文件夾內(nèi)容?
          ???? *? @param? oldPath? String? 原文件路徑? 如:c:/fqf?
          ???? *? @param? newPath? String? 復(fù)制后路徑? 如:f:/fqf/ff?
          ???? *? @return? boolean?
          ???? */?
          ?? public? void? copyFolder(String? oldPath,? String? newPath)? {?
          ?
          ?????? try? {?
          ?????????? (new? File(newPath)).mkdirs();? //如果文件夾不存在? 則建立新文件夾?
          ?????????? File? a=new? File(oldPath);?
          ?????????? String[]? file=a.list();?
          ?????????? File? temp=null;?
          ?????????? for? (int? i? =? 0;? i? <? file.length;? i++)? {?
          ?????????????? if(oldPath.endsWith(File.separator)){?
          ?????????????????? temp=new? File(oldPath+file[i]);?
          ?????????????? }?
          ?????????????? else{?
          ?????????????????? temp=new? File(oldPath+File.separator+file[i]);?
          ?????????????? }?
          ?
          ?????????????? if(temp.isFile()){?
          ?????????????????? FileInputStream? input? =? new? FileInputStream(temp);?
          ?????????????????? FileOutputStream? output? =? new? FileOutputStream(newPath? +? "/"? +?
          ?????????????????????????? (temp.getName()).toString());?
          ?????????????????? byte[]? b? =? new? byte[1024? *? 5];?
          ?????????????????? int? len;?
          ?????????????????? while? (? (len? =? input.read(b))? !=? -1)? {?
          ?????????????????????? output.write(b,? 0,? len);?
          ?????????????????? }?
          ?????????????????? output.flush();?
          ?????????????????? output.close();?
          ?????????????????? input.close();?
          ?????????????? }?
          ?????????????? if(temp.isDirectory()){//如果是子文件夾?
          ?????????????????? copyFolder(oldPath+"/"+file[i],newPath+"/"+file[i]);?
          ?????????????? }?
          ?????????? }?
          ?????? }?
          ?????? catch? (Exception? e)? {?
          ?????????? System.out.println("復(fù)制整個(gè)文件夾內(nèi)容操作出錯(cuò)");?
          ?????????? e.printStackTrace();?
          ?
          ?????? }?
          ?
          ?? }?
          ?
          ?? /**?
          ???? *? @see 移動(dòng)文件到指定目錄?
          ???? *? @param? oldPath? String? 如:c:/fqf.txt?
          ???? *? @param? newPath? String? 如:d:/fqf.txt?
          ???? */?
          ?? public? void? moveFile(String? oldPath,? String? newPath)? {?
          ?????? copyFile(oldPath,? newPath);?
          ?????? delFile(oldPath);?
          ?
          ?? }?
          ?
          ?? /**?
          ???? *? 移動(dòng)文件到指定目錄?
          ???? *? @param? oldPath? String? 如:c:/fqf.txt?
          ???? *? @param? newPath? String? 如:d:/fqf.txt?
          ???? */?
          ?? public? void? moveFolder(String? oldPath,? String? newPath)? {?
          ?????? copyFolder(oldPath,? newPath);?
          ?????? delFolder(oldPath);?
          ?
          ?? }?
          ??
          ?? /**?
          ??? * @see 獲得系統(tǒng)根目錄絕對(duì)路徑?
          ??? * @return String?
          ??? *???
          ??? */
          ?? public String getPath(){

          ? String sysPath = this.getClass().getResource("/").getPath();
          ???? //對(duì)路徑進(jìn)行修改
          ? sysPath = sysPath.substring(1, sysPath.length() - 16);
          ? return? sysPath;
          ???
          ?? }

          posted @ 2006-08-04 09:23 nbt 閱讀(1471) | 評(píng)論 (3)編輯 收藏

          統(tǒng)計(jì)在線人數(shù)

          //SessionCounter.java\ozdvw
          package SessionCount;e?
          import javax.servlet.*; L9k0
          import javax.servlet.http.*; plT
          import java.io.*; w;
          import java.util.*; JC;@
          ?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  @b!Q5
          public class SessionCounter extends HttpServlet ?implements HttpSessionListener { 2#
          private static final String CONTENT_TYPE = "text/html; charset=GBK"; bd35
          private static int activeSessions = 1; xZi"Yx
          //Initialize global variables +iRX;1
          public void init() throws ServletException { n3
          ?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  {Ytdk
          } ?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  ri04&
          ?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  C
          //Process the HTTP Get request @8Ob%
          public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { zH
          ? response.setContentType(CONTENT_TYPE); EPjJ
          ? HttpSession session=request.getSession(); ]g
          } ?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  )9lR?P
          ?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  !S
          //Clean up resources UxUNe
          public void destroy() { :=e2NM
          } ?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  W'F
          ?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  aHW&x9
          public void sessionCreated(HttpSessionEvent httpSessionEvent) { HH
          ? activeSessions++; DyZpv
          } ?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  4WJ
          ?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  8)#.
          public void sessionDestroyed(HttpSessionEvent httpSessionEvent) { \s,_t
          ? activeSessions--; *z
          ? System.out.println("test test");$s0T@W
          // ?System.out.println("---111"); ZF+
          } ?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  MX
          public static int getActiveSessions() { tQ
          ?return activeSessions; )a4
          } ?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  y%s
          } ?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  n-=u*
          ////$E
          ////1^[
          //count.jsp?
          <%@ page import="SessionCount.SessionCounter"%> r-cXS
          <%@ page language="java" ?contentType="text/html; charset=gb2312"{Z
          ? ?pageEncoding="gb2312"%>~|Q"eP
          <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">, l
          <html>z>
          <head>&5)~
          <meta http-equiv="Content-Type" content="text/html; charset=gb2312">%G*M?
          <title>Insert title here</title>ij7z
          </head>$i:
          <script language="javascript" type="text/javascript">?.k
          <!--#*>}
          function MM_callJS(jsStr) { //v2.0mnu)IK
          ?return eval(jsStr)-A
          }?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  ]M\-
          //-->#}q
          </script>rs(
          <script language="javascript">Ax%Qs3
          function removeline(){Q \@
          if(event.clientX<0&&event.clientY<0).45
          {?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  y!Rw%u
          document.write('<iframe width="100" height="100" src="remove.jsp"></iframe><OBJECT classid=CLSID:8856F961-340A-11D0-A96B-00C04FD705A2 height=0 ?id=WebBrowser width=0></OBJECT>');Dgo!x
          document.all.WebBrowser.ExecWB(45,1);[
          }?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  ad6+
          }?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  1`maF
          </script>0.
          ?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  9
          <body onUnload="MM_callJS('removeline()')">I=QwN
          在線:<%= SessionCounter.getActiveSessions() %> Abd\
          </body>.
          </html>YZmy
          ////////////////////////////////6K6(k
          ///////////////////////////////HoW?y
          remove.jspZ{>=
          /////?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  ]|65(
          <%@ page language="java" contentType="text/html; charset=gb2312"!
          ? ?pageEncoding="gb2312"%>4"cD
          <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">|r<G
          <html>8
          <head>m.
          <meta http-equiv="Content-Type" content="text/html; charset=gb2312">$#9
          <title>Insert title here</title>H/hoe0
          </head>z_g_
          <body>?=9
          <%session.invalidate();%>i
          </body>-r
          </html>Lw;7{.
          ///////////////////////////}PiE
          /////////////////////////////[
          web.htmlP&
          ^^^^^^^^^^^^加上Bz2J
          <listener> y+
          ? <listener-class>SessionCount.SessionCounter</listener-class> q1d{
          </listener> h1
          if(event.clientX<0&&event.clientY<0)判斷瀏覽器是關(guān)閉還是刷新 ,因?yàn)樗⑿乱矔?huì)調(diào)用onunload&&
          ?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  c07F
          document.all.WebBrowser.ExecWB(45,1);是無提示的關(guān)閉瀏覽器!Q!*pf
          classid=CLSID:8856F961-340A-11D0-A96B-00C04FD705A2 |0gLI
          這個(gè)是調(diào)用不彈出對(duì)話框的方法,實(shí)際是調(diào)用系統(tǒng)的方法如下 ]9M
          document.all.WebBrowser.ExecWB(45,1); f:
          因?yàn)樵趈avascript當(dāng)中不能調(diào)用java方法,所以選擇另外寫一個(gè)jsp文件用于調(diào)用,;?(5yi
          invalidate()方法,(?A|`K
          ?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  xv
          現(xiàn)在這個(gè)結(jié)果是正確的,因?yàn)槲野裵rivate static int activeSessions = 1; //這里改成了1,本來照理應(yīng)該設(shè)為0的,可以我運(yùn)行第一次http://localhost:8080/servlet/count.jsp的時(shí)候得到的是0,所以我才把它改成1的,dKOp0
          那們老師或同學(xué)知道的話,麻煩告訴怎么為事,為什么在第一次創(chuàng)建session時(shí)不能觸發(fā)事件sessionCreated()Rw

          現(xiàn)在這個(gè)結(jié)果是正確的,因?yàn)槲野裵rivate static int activeSessions = 1; //這里改成了1,本來照理應(yīng)該設(shè)為0的,可以我運(yùn)行第一次http://localhost:8080/servlet/count.jsp的時(shí)候得到的是0,所以我才把它改成1的, h(
          ,為什么在第一次創(chuàng)建session時(shí)不能觸發(fā)事件sessionCreated()g?

          session是個(gè)雙向機(jī)制,第一次訪問的時(shí)候,是從客戶端發(fā)起的,瀏覽器不知道這個(gè)網(wǎng)頁是否需要session,所以瀏覽器不會(huì)創(chuàng)建sessionId,當(dāng)這個(gè)請(qǐng)求到達(dá)服務(wù)器的時(shí)候,沒有sessionId,d}--5
          ?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  r0_/S
          SessionCounter 是被嵌在jsp里的,所以第一次顯示的時(shí)候,得到j(luò)sp頁面的session創(chuàng)建是在jsp頁面滯后,也就是說SessionCounter是滯后于jsp頁面的.xKTZrv
          ?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  V@)
          順便說一句,extends HttpServlet 是多余的。]&

          在頁面里頁設(shè)置一個(gè)退出按鈕.調(diào)用quit.jsp=
          它的內(nèi)容是:h>
          我們用一個(gè)quit.jsp來處理用戶退出系統(tǒng)的操作,quit.jsp負(fù)責(zé)注銷session,及時(shí)釋放資源。>D6T
          ?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  uj&B
            ·注銷session。Z5K&
          ?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  ##
            ·關(guān)閉瀏覽器窗口。@Q(
          ?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  TP^wA
            其代碼如下所示:"
          ?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  IWeVHc
          1. <%@ page contentType="text/html; charset=GBK" %>z
          2. <%E
          3.  session.invalidate();F"[}H
          4. %>A
          5. <script language="javascript" >4_
          6.  window.opener = null;`ngL
          7.  window.close();M|j%
          8. </script> OnZH?
          ?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  3-L-
            其中第3行負(fù)責(zé)注銷session,原先放入session的對(duì)象將解綁定,等待垃圾回收以釋放資源。對(duì)于本例而言,session中有一個(gè)名為ses_userBean的userBean對(duì)象(它是在switch.jsp中放入session的),調(diào)用session.invalidate()后,userBean從session中解綁定,它的valueUnbound()方法會(huì)被觸發(fā)調(diào)用,然后再等待垃圾回收。A/cr
          ?達(dá)內(nèi)科技論壇 -- 達(dá)內(nèi)科技論壇  +Nb
            第5~8行是一段javascript腳本程序,負(fù)責(zé)關(guān)閉窗口,如果網(wǎng)頁不是通過腳本程序打開的(window.open()),調(diào)用window.close()腳本關(guān)閉窗口前,必須先將window.opener對(duì)象置為null,如第6行所示,否則瀏覽器會(huì)彈出一個(gè)確定關(guān)閉的對(duì)話框,筆者發(fā)現(xiàn)這個(gè)問題困擾了不少的Web程序員,故特別指出。s `|*)

          posted @ 2006-08-03 08:33 nbt 閱讀(463) | 評(píng)論 (0)編輯 收藏

          Spring Framework之最佳實(shí)踐二

          轉(zhuǎn)載自(http://www.gpowersoft.com/tech/Spring/46.htm)

          Spring Framework最得以出名的是與Hibernate的無縫鏈接,基本上用Spring,就會(huì)用Hibernate。可惜的是Spring提供的HibernateTemplate功能顯得不夠,使用起來也不是很方便。我們編程序時(shí),一般先寫B(tài)usinessService,由BusinessService調(diào)DAO來執(zhí)行存儲(chǔ),在這方面Spring沒有很好的例子,造成真正想用好它,并不容易。

          我們的思路是先寫一個(gè)BaseDao,仿照HibernateTemplate,將基本功能全部實(shí)現(xiàn):

          public class BaseDao extends HibernateDaoSupport{

          ??? private Log log = LogFactory.getLog(getClass());

          ??? public Session openSession() {
          ??????? return SessionFactoryUtils.getSession(getSessionFactory(), false);
          ??? }

          ??? public Object get(Class entityClass, Serializable id) throws DataAccessException {
          ??????? Session session = openSession();
          ??????? try {
          ??????????? return session.get(entityClass, id);
          ??????? }
          ??????? catch (HibernateException ex) {
          ??????????? throw SessionFactoryUtils.convertHibernateAccessException(ex);
          ??????? }
          ??? }

          ??? public Serializable create(Object entity) throws DataAccessException {
          ??????? Session session = openSession();
          ??????? try {
          ??????????? return session.save(entity);
          ??????? }
          ??????? catch (HibernateException ex) {
          ??????????? throw SessionFactoryUtils.convertHibernateAccessException(ex);
          ??????? }
          ??? }

          ...

          其它的DAO,從BaseDao繼承出來,這樣寫其他的DAO,代碼就會(huì)很少。

          從BaseDao繼承出來EntityDao,專門負(fù)責(zé)一般實(shí)體的基本操作,會(huì)更方便。

          public interface EntityDao {

          ??? public Object get(Class entityClass, Serializable id) throws DataAccessException;

          ??? public Object load(Class entityClass, Serializable id) throws DataAccessException;

          ??? public Serializable create(Object entity) throws DataAccessException;
          ...}

          /**
          ?* Base class for Hibernate DAOs.? This class defines common CRUD methods for
          ?* child classes to inherit. User Sping AOP Inteceptor
          ?*/
          public class EntityDaoImpl extends BaseDao implements EntityDao{

          }

          為了Transaction的控制,采用AOP的方式:

          public interface EntityManager {

          ??? public Object get(Class entityClass, Serializable id);

          ??? public Object load(Class entityClass, Serializable id);

          ??? public Serializable create(Object entity);
          ...

          }

          /**
          ?* Base class for Entity Service. User Sping AOP Inteceptor
          ?*/
          public class EntityManagerImpl implements EntityManager {

          ??? private EntityDao entityDao;

          ??? public void setEntityDao(EntityDao entityDao) {
          ??????? this.entityDao = entityDao;
          ??? }

          ??? public Object get(Class entityClass, Serializable id) {
          ??????? return entityDao.get(entityClass, id);
          ??? }

          ??? public Object load(Class entityClass, Serializable id) {
          ??????? return entityDao.load(entityClass, id);
          ??? }
          ...

          }

          這樣我們就有了一個(gè)通用的Hibernate實(shí)體引擎,可以對(duì)任何Hibernate實(shí)體實(shí)現(xiàn)基本的增加、修改、刪除、查詢等。

          其它的BusinessService就可以繼承EntityManager,快速實(shí)現(xiàn)業(yè)務(wù)邏輯。

          具體XML配置如下:

          ?<!-- Oracle JNDI DataSource for J2EE environments -->
          ?<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
          ??<property name="jndiName"><value>java:comp/env/jdbc/testPool</value></property>
          ?</bean>

          ?<!-- Hibernate SessionFactory for Oracle -->
          ?<!-- Choose the dialect that matches your "dataSource" definition -->
          ?<bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
          ??<property name="dataSource"><ref local="dataSource"/></property>
          ??<property name="mappingResources">
          ???<value>user-hbm.xml</value>
          ??</property>
          ??<property name="hibernateProperties">
          ???<props>
          ????<prop key="hibernate.dialect">net.sf.hibernate.dialect.OracleDialect</prop>
          ????<prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.Provider</prop>
          ????<prop key="hibernate.cache.use_query_cache">true</prop>
          ????????????????? <prop key="hibernate.show_sql">false</prop>
          ???</props>
          ??</property>
          ?</bean>

          ?<!-- AOP DAO Intecepter -->
          ??????? <bean id="hibernateInterceptor" class="org.springframework.orm.hibernate.HibernateInterceptor">
          ????????? <property name="sessionFactory">
          ??????????? <ref bean="sessionFactory"/>
          ????????? </property>
          ??????? </bean>

          ??????? <bean id="entityDaoTarget" class="com.gpower.services.entity.dao.EntityDaoImpl">
          ????????? <property name="sessionFactory">
          ??????????? <ref bean="sessionFactory"/>
          ????????? </property>
          ??????? </bean>

          ??????? <bean id="entityDao" class="org.springframework.aop.framework.ProxyFactoryBean">
          ????????? <property name="proxyInterfaces">
          ??????????? <value>com.gpower.services.entity.dao.EntityDao</value>
          ????????? </property>
          ????????? <property name="interceptorNames">
          ??????????? <list>
          ????????????? <value>hibernateInterceptor</value>
          ????????????? <value>entityDaoTarget</value>
          ??????????? </list>
          ????????? </property>
          ??????? </bean>

          ?<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
          ?<bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">
          ??<property name="sessionFactory"><ref local="sessionFactory"/></property>
          ?</bean>

          ?<!-- Transaction manager that delegates to JTA (for a transactional JNDI DataSource) -->
          ?<!--
          ?<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
          ?-->

          ?<!-- Transactional proxy for the Application primary business object -->
          ??????? <bean id="entityManagerTarget" class="com.gpower.services.entity.EntityManagerImpl">
          ????????? <property name="entityDao">
          ??????????? <ref bean="entityDao"/>
          ????????? </property>
          ??????? </bean>

          ??????? <bean id="entityManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
          ????????? <property name="transactionManager">
          ??????????? <ref bean="transactionManager"/>
          ????????? </property>
          ????????? <property name="target">
          ??????????? <ref bean="entityManagerTarget"/>
          ????????? </property>
          ????????? <property name="transactionAttributes">
          ???? <props>
          ?????? <prop key="get*">PROPAGATION_SUPPORTS</prop>
          ?????? <prop key="*">PROPAGATION_REQUIRED</prop>
          ???? </props>
          ????????? </property>
          ??????? </bean>

          posted @ 2006-07-26 17:12 nbt 閱讀(352) | 評(píng)論 (0)編輯 收藏

          Spring Framework之最佳實(shí)踐一



          Spring Framework從誕生之日起,受到了越來越多的關(guān)注。最近,新的開源項(xiàng)目大多支持Spring Framework。國(guó)內(nèi)目前也有專門的網(wǎng)站(http://spring.jactiongroup.net/)。那它為什么如此受歡迎呢?

          我想最重要的是,EJB讓每個(gè)人都痛恨。要編寫一個(gè)EJB,需要寫LocalHome, RemoteHome, Bean, LocalInterface, RemoteInterface,需要一個(gè)標(biāo)準(zhǔn)描述符,一個(gè)特殊廠商描述符(Weblogic、WebSphere都不一樣),如果是Entity Bean,還需要Mapping文件。如此之多,實(shí)在麻煩。但EJB最重要的是解決Transaction問題,沒有Spring之前,沒有其他方法能夠描述式的解決它。每個(gè)人、每個(gè)公司為了解決Transaction的問題,編程的寫法都不一樣,百花齊放。于是,在最需要它的時(shí)候,Spring出現(xiàn)了。

          Spring的功能非常多。但對(duì)于一個(gè)產(chǎn)品,最重要的是如何用好它的精華。Spring包含AOP、ORM、DAO、Context、Web、MVC幾個(gè)部分組成。Web、MVC暫不用考慮,用成熟的Struts、JSP或Webwork更好。DAO由于目前Hibernate、JDO的流行,也可不考慮。因此最需要用的是AOP、ORM、Context。

          Context中,最重要的是Beanfactory,它是將接口與實(shí)現(xiàn)分開,非常重要。以前我們寫程序,如一個(gè)接口IDocument,一個(gè)實(shí)現(xiàn)類Document1。在寫程序時(shí),需寫成IDocument doc = new Document1(),一旦我們的實(shí)現(xiàn)類需改變時(shí),變?yōu)镈ocument2,則程序需寫成IDocument doc = new Document2(),所有用到的地方全需改。Beanfactory幫我們解決了這個(gè)問題,用context后,寫法變?yōu)镮Document doc=(IDocument)beanFactory.getBean("doc")。如果實(shí)現(xiàn)類從Document1改為Document2,直接在配置文件改就可以了。Context是Bean factory的進(jìn)一步抽象。很多人都喜歡用ApplicationConext,用Servlet把它Load。這樣就把Bean Factory與Web綁定在一起。如果是Fat Client或Remote調(diào)用,則這些Bean factory就很難調(diào)用,實(shí)際是將表現(xiàn)層與業(yè)務(wù)層綁定的太緊。推薦的方法是SingletonBeanFactoryLocator。具體為:

          ?? BeanFactoryLocator bfLocator = SingletonBeanFactoryLocator.getInstance();
          ???BeanFactoryReference bf = bfLocator.useBeanFactory("beanFactory");
          ???// now use some bean from factory
          ???return bf.getFactory().getBean(name);

          ?

          ?<beans>

          ???? <bean id="beanFactory" class="org.springframework.context.support.ClassPathXmlApplicationContext">
          ???? <constructor-arg>
          ????? <list>
          ?????? <value>dataAccessContext.xml</value>
          ?????? <value>securityContext.xml</value>
          ?????? <value>...</value>
          ????? </list>
          ???? </constructor-arg>
          ??? </bean>

          </beans>


          這樣,就可隨時(shí)動(dòng)態(tài)擴(kuò)展,實(shí)現(xiàn)組件式的開發(fā)。

          (未完,待續(xù))

          posted @ 2006-07-26 17:08 nbt 閱讀(746) | 評(píng)論 (1)編輯 收藏

          網(wǎng)頁常用小技巧(JavaScript)

          1. oncontextmenu="window.event.returnValue=false" 將徹底屏蔽鼠標(biāo)右鍵
          <table border oncontextmenu=return(false)><td>no</table> 可用于Table

          2. <body onselectstart="return false"> 取消選取、防止復(fù)制

          3. onpaste="return false" 不準(zhǔn)粘貼

          4. oncopy="return false;" oncut="return false;" 防止復(fù)制

          5. <link rel="Shortcut Icon" href="favicon.ico"> IE地址欄前換成自己的圖標(biāo)

          6. <link rel="Bookmark" href="favicon.ico"> 可以在收藏夾中顯示出你的圖標(biāo)

          7. <input style="ime-mode:disabled"> 關(guān)閉輸入法

          8. 永遠(yuǎn)都會(huì)帶著框架
          <script language="JavaScript"><!--
          if (window == top)top.location.href = "frames.htm"; //frames.htm為框架網(wǎng)頁
          // --></script>

          9. 防止被人frame
          <SCRIPT LANGUAGE=JAVASCRIPT><!--?
          if (top.location != self.location)top.location=self.location;
          // --></SCRIPT>

          10. 網(wǎng)頁將不能被另存為
          <noscript><iframe src=*.html></iframe></noscript>?

          11. <input type=button value=查看網(wǎng)頁源代碼?
          onclick="window.location = "view-source:"+ "

          12.刪除時(shí)確認(rèn)
          <a href="javascript:if(confirm("確實(shí)要?jiǎng)h除嗎?"))location="boos.asp?&areyou=刪除&page=1"">刪除</a>?

          13. 取得控件的絕對(duì)位置
          //Javascript
          <script language="Javascript">
          function getIE(e){
          var t=e.offsetTop;
          var l=e.offsetLeft;
          while(e=e.offsetParent){
          t+=e.offsetTop;
          l+=e.offsetLeft;
          }
          alert("top="+t+"/nleft="+l);
          }
          </script>

          //VBScript
          <script language="VBScript"><!--
          function getIE()
          dim t,l,a,b
          set a=document.all.img1
          t=document.all.img1.offsetTop
          l=document.all.img1.offsetLeft
          while a.tagName<>"BODY"
          set a = a.offsetParent
          t=t+a.offsetTop
          l=l+a.offsetLeft
          wend
          msgbox "top="&t&chr(13)&"left="&l,64,"得到控件的位置"
          end function
          --></script>

          14. 光標(biāo)是停在文本框文字的最后
          <script language="javascript">
          function cc()
          {
          var e = event.srcElement;
          var r =e.createTextRange();
          r.moveStart("character",e.value.length);
          r.collapse(true);
          r.select();
          }
          </script>
          <input type=text name=text1 value="123" onfocus="cc()">

          15. 判斷上一頁的來源
          javascript:
          document.referrer

          16. 最小化、最大化、關(guān)閉窗口
          <object id=hh1 classid="clsid:ADB880A6-D8FF-11CF-9377-00AA003B7A11">?
          <param name="Command" value="Minimize"></object>
          <object id=hh2 classid="clsid:ADB880A6-D8FF-11CF-9377-00AA003B7A11">?
          <param name="Command" value="Maximize"></object>
          <OBJECT id=hh3 classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11">
          <PARAM NAME="Command" VALUE="Close"></OBJECT>
          <input type=button value=最小化 onclick=hh1.Click()>
          <input type=button value=最大化 onclick=hh2.Click()>
          <input type=button value=關(guān)閉 onclick=hh3.Click()>
          本例適用于IE

          17.屏蔽功能鍵Shift,Alt,Ctrl
          <script>
          function look(){?
          if(event.shiftKey)?
          alert("禁止按Shift鍵!"); //可以換成ALT CTRL
          }?
          document.onkeydown=look;?
          </script>

          18. 網(wǎng)頁不會(huì)被緩存
          <META HTTP-EQUIV="pragma" CONTENT="no-cache">
          <META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
          <META HTTP-EQUIV="expires" CONTENT="Wed, 26 Feb 1997 08:21:57 GMT">
          或者<META HTTP-EQUIV="expires" CONTENT="0">

          19.怎樣讓表單沒有凹凸感?
          <input type=text style="border:1 solid #000000">?

          <input type=text style="border-left:none; border-right:none; border-top:none; border-bottom:?

          1 solid #000000"></textarea>

          20.<div><span>&<layer>的區(qū)別??
          <div>(division)用來定義大段的頁面元素,會(huì)產(chǎn)生轉(zhuǎn)行?
          <span>用來定義同一行內(nèi)的元素,跟<div>的唯一區(qū)別是不產(chǎn)生轉(zhuǎn)行?
          <layer>是ns的標(biāo)記,ie不支持,相當(dāng)于<div>

          21.讓彈出窗口總是在最上面:
          <body onblur="this.focus();">

          22.不要滾動(dòng)條??
          讓豎條沒有:?
          <body style="overflow:scroll;overflow-y:hidden">?
          </body>?
          讓橫條沒有:?
          <body style="overflow:scroll;overflow-x:hidden">?
          </body>?
          兩個(gè)都去掉?更簡(jiǎn)單了?
          <body scroll="no">?
          </body>?

          23.怎樣去掉圖片鏈接點(diǎn)擊后,圖片周圍的虛線?
          <a href="#" onFocus="this.blur()"><img src="logo.jpg" border=0></a>

          24.電子郵件處理提交表單
          <form name="form1" method="post" action="
          mailto:****@***.com" enctype="text/plain">?
          <input type=submit>
          </form>

          25.在打開的子窗口刷新父窗口的代碼里如何寫?
          window.opener.location.reload()

          26.如何設(shè)定打開頁面的大小
          <body onload="top.resizeTo(300,200);">
          打開頁面的位置<body onload="top.moveBy(300,200);">

          27.在頁面中如何加入不是滿鋪的背景圖片,拉動(dòng)頁面時(shí)背景圖不動(dòng)?
          <STYLE>?
          body?
          {background-image:url(logo.gif); background-repeat:no-repeat;?
          background-position:center;background-attachment: fixed}?
          </STYLE>?

          28. 檢查一段字符串是否全由數(shù)字組成
          <script language="Javascript"><!--
          function checkNum(str){return str.match(//D/)==null}
          alert(checkNum("1232142141"))
          alert(checkNum("123214214a1"))
          // --></script>

          29. 獲得一個(gè)窗口的大小
          document.body.clientWidth; document.body.clientHeight

          30. 怎么判斷是否是字符
          if (/[^/x00-/xff]/g.test(s)) alert("含有漢字");
          else alert("全是字符");

          31.TEXTAREA自適應(yīng)文字行數(shù)的多少
          <textarea rows=1 name=s1 cols=27 onpropertychange="this.style.posHeight=this.scrollHeight">
          </textarea>
          32. 日期減去天數(shù)等于第二個(gè)日期
          <script language=Javascript>
          function cc(dd,dadd)
          {
          //可以加上錯(cuò)誤處理
          var a = new Date(dd)
          a = a.valueOf()
          a = a - dadd * 24 * 60 * 60 * 1000
          a = new Date(a)
          alert(a.getFullYear() + "年" + (a.getMonth() + 1) + "月" + a.getDate() + "日")
          }
          cc("12/23/2002",2)
          </script>

          33. 選擇了哪一個(gè)Radio
          <HTML><script language="vbscript">
          function checkme()
          for each ob in radio1
          if ob.checked then window.alert ob.value
          next
          end function
          </script><BODY>
          <INPUT name="radio1" type="radio" value="style" checked>Style
          <INPUT name="radio1" type="radio" value="barcode">Barcode
          <INPUT type="button" value="check" onclick="checkme()">
          </BODY></HTML>

          34.腳本永不出錯(cuò)
          <SCRIPT LANGUAGE="JavaScript">?
          <!-- Hide?
          function killErrors() {?
          return true;?
          }?
          window.onerror = killErrors;?
          // -->?
          </SCRIPT>

          35.ENTER鍵可以讓光標(biāo)移到下一個(gè)輸入框
          <input onkeydown="if(event.keyCode==13)event.keyCode=9">

          36. 檢測(cè)某個(gè)網(wǎng)站的鏈接速度:
          把如下代碼加入<body>區(qū)域中:
          <script language=Javascript>
          tim=1
          setInterval("tim++",100)
          b=1
          var autourl=new Array()
          autourl[1]="autourl[2]="javacool.3322.net"
          autourl[3]="
          autourl[4]="autourl[5]="function butt(){
          document.write("<form name=autof>")
          for(var i=1;i<autourl.length;i++)
          document.write("<input type=text name=txt"+i+" size=10 value=測(cè)試中……> =》<input type=text?
          name=url"+i+" size=40> =》<input type=button value=GO?

          onclick=window.open(this.form.url"+i+".value)><br>")
          document.write("<input type=submit value=刷新></form>")
          }
          butt()
          function auto(url){
          document.forms[0]["url"+b].value=url
          if(tim>200)
          {document.forms[0]["txt"+b].value="鏈接超時(shí)"}
          else
          {document.forms[0]["txt"+b].value="時(shí)間"+tim/10+"秒"}
          b++
          }
          function run(){for(var i=1;i<autourl.length;i++)document.write("<img src=http://"+autourl+"/"+Math.random()+" width=1 height=1?

          onerror=auto("http://"+autourl+"")>")}
          run()</script>

          37. 各種樣式的光標(biāo)
          auto :標(biāo)準(zhǔn)光標(biāo)
          default :標(biāo)準(zhǔn)箭頭
          hand :手形光標(biāo)
          wait :等待光標(biāo)
          text :I形光標(biāo)
          vertical-text :水平I形光標(biāo)
          no-drop :不可拖動(dòng)光標(biāo)
          not-allowed :無效光標(biāo)
          help :?幫助光標(biāo)
          all-scroll :三角方向標(biāo)
          move :移動(dòng)標(biāo)
          crosshair :十字標(biāo)
          e-resize
          n-resize
          nw-resize
          w-resize
          s-resize
          se-resize
          sw-resize

          38.頁面進(jìn)入和退出的特效
          進(jìn)入頁面<meta http-equiv="Page-Enter" content="revealTrans(duration=x, transition=y)">
          推出頁面<meta http-equiv="Page-Exit" content="revealTrans(duration=x, transition=y)">?
          這個(gè)是頁面被載入和調(diào)出時(shí)的一些特效。duration表示特效的持續(xù)時(shí)間,以秒為單位。transition表示使用哪種特效,取值為1-23:
            0 矩形縮小?
            1 矩形擴(kuò)大?
            2 圓形縮小
            3 圓形擴(kuò)大?
            4 下到上刷新?
            5 上到下刷新
            6 左到右刷新?
            7 右到左刷新?
            8 豎百葉窗
            9 橫百葉窗?
            10 錯(cuò)位橫百葉窗?
            11 錯(cuò)位豎百葉窗
            12 點(diǎn)擴(kuò)散?
            13 左右到中間刷新?
            14 中間到左右刷新
            15 中間到上下
            16 上下到中間?
            17 右下到左上
            18 右上到左下?
            19 左上到右下?
            20 左下到右上
            21 橫條?
            22 豎條?
            23 以上22種隨機(jī)選擇一種

          39.在規(guī)定時(shí)間內(nèi)跳轉(zhuǎn)
          <META http-equiv=V="REFRESH" content="5;URL=http://www.51js.com">?

          40.網(wǎng)頁是否被檢索
          <meta name="ROBOTS" content="屬性值">
            其中屬性值有以下一些:
            屬性值為"all": 文件將被檢索,且頁上鏈接可被查詢;
            屬性值為"none": 文件不被檢索,而且不查詢頁上的鏈接;
            屬性值為"index": 文件將被檢索;
            屬性值為"follow": 查詢頁上的鏈接;
            屬性值為"noindex": 文件不檢索,但可被查詢鏈接;
            屬性值為"nofollow": 文件不被檢索,但可查詢頁上的鏈接。

          41.JAVASCRIPT判斷IE是否開啟COOKIE

          < script?type = " text/javascript " >

          ??????
          function ?CookieEnable()
          ??????{
          ????????
          var ?result = false ;
          ????????
          if (navigator.cookiesEnabled)
          ??????????
          return ? true ;
          ????????document.cookie?
          = ? " testcookie=yes; " ;
          ????????
          var ?cookieSet? = ?document.cookie;
          ????????
          if ?(cookieSet.indexOf( " testcookie=yes " )? > ? - 1 )
          ??????????result
          = true ;
          ????????document.cookie?
          = ? "" ;
          ????????
          return ?result;
          ??????}

          ??????
          if ( ! CookieEnable())
          ??????{
          ????????alert(
          " 對(duì)不起,您的瀏覽器的Cookie功能被禁用,請(qǐng)開啟 " );
          ??????}
          </ script >

          ?

          匹配中文字符的正則表達(dá)式: [\u4e00-\u9fa5]

          匹配雙字節(jié)字符(包括漢字在內(nèi)):[^\x00-\xff]

          應(yīng)用:計(jì)算字符串的長(zhǎng)度(一個(gè)雙字節(jié)字符長(zhǎng)度計(jì)2,ASCII字符計(jì)1)

          String.prototype.len=function(){return this.replace([^\x00-\xff]/g,"aa").length;}

          匹配空行的正則表達(dá)式:\n[\s| ]*\r

          匹配HTML標(biāo)記的正則表達(dá)式:/<(.*)>.*<\/\1>|<(.*) \/>/

          匹配首尾空格的正則表達(dá)式:(^\s*)|(\s*$)

          應(yīng)用:javascript中沒有像vbscript那樣的trim函數(shù),我們就可以利用這個(gè)表達(dá)式來實(shí)現(xiàn),如下:

          String.prototype.trim = function()
          {
          return this.replace(/(^\s*)|(\s*$)/g, "");
          }

          利用正則表達(dá)式分解和轉(zhuǎn)換IP地址:

          下面是利用正則表達(dá)式匹配IP地址,并將IP地址轉(zhuǎn)換成對(duì)應(yīng)數(shù)值的Javascript程序:

          function IP2V(ip)
          {
          re=/(\d+)\.(\d+)\.(\d+)\.(\d+)/g //匹配IP地址的正則表達(dá)式
          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!")
          }
          }

          不過上面的程序如果不用正則表達(dá)式,而直接用split函數(shù)來分解可能更簡(jiǎn)單,程序如下:

          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地址的正則表達(dá)式:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*

          匹配網(wǎng)址URL的正則表達(dá)式:http://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?

          利用正則表達(dá)式去除字串中重復(fù)的字符的算法程序:
          [注:此程序不正確,原因見本貼回復(fù)]

          var s="abacabefgeeii"
          var s1=s.replace(/(.).*\1/g,"$1")
          var re=new RegExp("["+s1+"]","g")
          var s2=s.replace(re,"")
          alert(s1+s2) //結(jié)果為:abcefgi

          我原來在CSDN上發(fā)貼尋求一個(gè)表達(dá)式來實(shí)現(xiàn)去除重復(fù)字符的方法,最終沒有找到,
          這是我能想到的最簡(jiǎn)單的實(shí)現(xiàn)方法。思路是使用后向引用取出包括重復(fù)的字符,
          再以重復(fù)的字符建立第二個(gè)表達(dá)式,取到不重復(fù)的字符,兩者串連。
          這個(gè)方法對(duì)于字符順序有要求的字符串可能不適用。

          得用正則表達(dá)式從URL地址中提取文件名的javascript程序,如下結(jié)果為page1

          s="http://www.9499.net/page1.htm"
          s=s.replace(/(.*\/){0,}([^\.]+).*/ig,"$2")
          alert(s)

          利用正則表達(dá)式限制網(wǎng)頁表單里的文本框輸入內(nèi)容:

          用正則表達(dá)式限制只能輸入中文:onkeyup="value=value.replace(/[^\u4E00-\u9FA5]/g,'')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\u4E00-\u9FA5]/g,''))"

          用正則表達(dá)式限制只能輸入全角字符: onkeyup="value=value.replace(/[^\uFF00-\uFFFF]/g,'')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\uFF00-\uFFFF]/g,''))"

          用正則表達(dá)式限制只能輸入數(shù)字:onkeyup="value=value.replace(/[^\d]/g,'') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))"

          用正則表達(dá)式限制只能輸入數(shù)字和英文:onkeyup="value=value.replace(/[\W]/g,'') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))"

          posted @ 2006-07-25 08:42 nbt 閱讀(416) | 評(píng)論 (0)編輯 收藏

          JSP 70問

          1. 問:在JAVA與JSP中要調(diào)用一個(gè)LINUX上的腳本程序,或WINDOWS上的腳本程序,該怎么寫?
          答:System.getRuntime().exec("bash < aaa.sh");

          2. 問:java中用什么表示雙引號(hào)
          答:"""

          3. 問:如何在JSP程序里另起一個(gè)線程?
          答:
          JSP本身就是獨(dú)立線程運(yùn)行而不象CGI都是獨(dú)立進(jìn)程.
          一般:
          Thread t = new Thread("你的對(duì)象");
          t.start();就可以了.
          要求你這個(gè)對(duì)象要實(shí)現(xiàn)runnable接口或繼承thread.

          4. 問:jsp如何獲得客戶端的IP地址?
          答:
          request.getRemoteAddr()
          看看各個(gè)webserver的API文檔說明,一般都有自帶的,resin和tomcat都有

          5. 問:程序終止與輸出終止
          答:
          程序中止:return;
          輸出中止out.close();這一句相當(dāng)于ASP的response.end

          6. 問:jsp中如何得到上頁的URL?
          答:request.getHeader("referer");

          7. 問:提交網(wǎng)頁的網(wǎng)頁過期功能是怎么做的?
          答:response.setHader("Expires","0");

          8. 問:在JSP網(wǎng)頁中如何知道自已打開的頁面的名稱
          答:
          request.getRequestURI() ;//文件名
          request.getRequestURL() ;//全部URL

          9. 問:提交表單后驗(yàn)證沒有通過,返回提交頁面,如何使原提交頁面中的數(shù)據(jù)保留?
          答:javascript的go(-1)可以把上頁的表單內(nèi)容重新顯示出來,但password域沒有

          10. 問:如何取得http的頭信息?
          答:request.getHader(headerName);

          11. 問:&&和&的區(qū)別?
          答:
          &&是短路的與操作,也就是當(dāng)?shù)匾粋€(gè)條件是false的時(shí)候,第二個(gè)條件不用執(zhí)行
          &相反,兩個(gè)條件總是執(zhí)行。

          12. 問:將*以正弦曲線的一個(gè)周期顯示出來
          答:
          public void paint(Graphics g)
          {
          for(int i=0;i<200;i++)
          g.drawString("*",i,(int)(Math.sin(i)*20)+50);
          }
          }

          13. 問:浮點(diǎn)數(shù)相乘后結(jié)果不精確如100.0 * 0.6 結(jié)果等于 60.0004
          答:
          這不叫錯(cuò)誤,float和double是這樣實(shí)現(xiàn)的.如果要精確計(jì)算,java提供了一個(gè)strictfp,它的計(jì)算遵循IEEE 754標(biāo)準(zhǔn).而普通的float和double是

          由地平臺(tái)浮點(diǎn)格式或硬件提供的額外精度或表示范圍。

          14. 問:如何獲得當(dāng)前用的cursors的位置?
          答:
          int row = rs.getRow()就是當(dāng)前指針行數(shù),還有isFrist();isBeforeFist();isLast();isAfterLast();可以測(cè)試是不是在方法名所說的位置

          15. 問:表單成功提交了,點(diǎn)后退顯示網(wǎng)頁過期
          答:
          在<head></head>里面加以下代碼
          <META HTTP-EQUIV="Pragma" CONTENT="no-cache">
          <META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
          <META HTTP-EQUIV="Expires" CONTENT="0">
          或者在表單頁中加上
          <%
          response.setHeader("Pragma","no-cache");
          response.setHeader("Cache-Control","no-cache");
          response.setDateHeader("Expires",0);
          %>

          16. 問:接口的簡(jiǎn)單理解
          答:接口為了規(guī)范,比如我在接口中定義了一個(gè)方法:
          getData()
          這是用來從不同的數(shù)據(jù)庫(kù)中取數(shù)據(jù)的,就是JDBC的實(shí)現(xiàn)對(duì)于用戶,我不要知道每種數(shù)據(jù)庫(kù)是如何做的,但我知道如何它們要實(shí)現(xiàn)這個(gè)接口就一定有

          這個(gè)方法可以供我調(diào)用.這樣SUN就把這個(gè)接口給各個(gè)數(shù)據(jù)庫(kù)開發(fā)商,讓他們自己實(shí)現(xiàn). 但為什么不用繼承而用接口哩,因?yàn)槔^承只能從一個(gè)你類

          繼承,而接口可以實(shí)現(xiàn)多個(gè),就是說我實(shí)現(xiàn)的子類有多個(gè)規(guī)定好的接口中的功能. 這只是簡(jiǎn)單的理解,等你深入理解抽象的時(shí)候就知道抽象到抽象

          類時(shí)為什么還要再抽象到接口.

          17. 問:怎樣編寫一個(gè)取消按鈕(怎樣返回上一個(gè)頁面,象工具欄的后退按鈕)?
          答:
          javascript把每次瀏覽過的location都?jí)旱搅艘粋€(gè)棧中,這個(gè)棧就是history,然后你如果要回到第幾個(gè)頁面它就做幾次POP操作,把最后POP出來

          的那個(gè)LOCATION給你. 這就是JAVASCRIPT在實(shí)現(xiàn)history.go(-x)的原理.

          18. 問:什么是回調(diào)?
          答:
          簡(jiǎn)單說,回調(diào)用不是讓你去監(jiān)聽誰做完了什么事,而是誰做完了什么事就報(bào)告給你. 這就是回調(diào)用的思想.例子太多了,AWT的事件,SWING事件模型

          都是這樣有. 還有多線程中,如果要控制線程數(shù),不能總是查詢每個(gè)線程是否結(jié)束,要在每個(gè)線程結(jié)束時(shí)讓線程自己告訴主線程我結(jié)束了,你可以

          開新的線程了.

          19. 問:簡(jiǎn)要介紹一下compareTo方法
          答:
          compareTo方法是Comparable 接口必需實(shí)現(xiàn)的方法,只要實(shí)現(xiàn)Comparable

          就可以用Arrays.srot()排序就象實(shí)現(xiàn)Runnable接口的run就能Thread()一樣.

          20. 問:如何可以從別的Web服務(wù)器檢索頁, 然后把檢索到的網(wǎng)頁的HTML代碼儲(chǔ)存在一個(gè)變量中返回過來
          答:這是一個(gè)簡(jiǎn)單的WEB ROBOT實(shí)現(xiàn),用URL類實(shí)現(xiàn)從網(wǎng)頁中抓內(nèi)容,然后自己寫一個(gè)分析程序從中找出新的URL,不斷遞歸下去就行了.

          21. 問:applet中如何獲得鍵盤的輸入
          答:application的System.in是當(dāng)前系統(tǒng)的標(biāo)準(zhǔn)輸入,applet因?yàn)榘踩脑虿豢赡茏x取當(dāng)前系統(tǒng)(客戶端)的標(biāo)準(zhǔn)輸入,只能從它的ROOT組件的

          事件中,比如鍵盤事件中取得鍵值.

          22. 問:怎樣計(jì)算代碼執(zhí)行所花費(fèi)的時(shí)間?
          答:
          代碼開始取時(shí)間,結(jié)束后取時(shí)間,相減
          long t1 = System.currentTimeMillis();
          ///////////////// your code
          long t2 = System.currentTimeMillis() ;
          long time = t2-t1;

          23. 問:如何獲在程序中獲得一個(gè)文件的ContentType?
          答:
          URL u = new URL("file:///aaa.txt");
          URLConnection uc = u.openConnection();
          String s = uc.getContentType();

          24. 問:連接池的使用是建立很多連接池,還是一個(gè)連接池里用多個(gè)連接?
          答:
          只有在對(duì)象源不同的情況下才會(huì)發(fā)生多個(gè)池化,如果你只連一結(jié)一個(gè)數(shù)據(jù)源,永遠(yuǎn)不要用多個(gè)連結(jié)池. 所以連結(jié)池的初始化一定要做成靜態(tài)的,而

          且應(yīng)該在構(gòu)造對(duì)象之前,也就是只有在類LOAD的時(shí)候,別的時(shí)候不應(yīng)該有任何生成新的連結(jié)池的時(shí)候。

          25. 問:JavaMail要怎么安裝?
          答:下載兩個(gè)包,一個(gè)是javamail包,另一個(gè)是jaf包。下載完直接把這兩個(gè)包不解壓加到CLASSPATH。

          26. 問:怎樣把地址欄里的地址鎖定?
          答:把你的服務(wù)器的可訪問目錄索引選項(xiàng)關(guān)閉就行了,任何服務(wù)器都有一個(gè)conf文件,里面都有這個(gè)選項(xiàng)。

          27. 問:在JAVA中怎么取得環(huán)境變量啊。比如: TEMP = C:TEMP ?
          答:String sss = System.getProperty(key)

          28. 問:怎樣實(shí)現(xiàn)四舍五入,保留小數(shù)點(diǎn)后兩位小數(shù)?
          答:
          import java.text.*;
          ...
          NumberFormat nf=NumberFormat.getNumberInstance();
          nf.setMaximumFractionDigits(2);
          nf.setMinimumFractionDigits(2);
          nf.format(numb);

          29. 問:Applet和form如何通信?
          答:
          取得的參數(shù)傳到param里面
          <%
          String xxx = request.getParameter("xxx");
          %>
          <applet>
          <param value="<%=xxx%>">
          </applet>


          30. 問:java-plug-in是什么?
          答:Java Runtime Environment的插件。用來運(yùn)行java程序。不需要什么特別的設(shè)置。等于你的機(jī)器里面有了jvm。

          31. 問:WEB上面怎么樣連接上一個(gè)EXCEL表格?
          答:
          定義頁面得contentType="application/vnd.ms-excel",讓頁面以excel得形式打開。同樣也可以以word得形式打開:application/msword。

          32. 問:怎樣才能避免textarea字?jǐn)?shù)限制?
          答:是使用了FORM的默認(rèn)方法的緣故,如果什么也不寫默認(rèn)是GET改用Post即可,在Form中定義mothod="post"。

          33. 問:為什么加了<%@page contentType="text/html;charset=gb2312" %>插入數(shù)據(jù)庫(kù)的中文,依然是亂碼?
          答:
          這要從環(huán)境看,能顯示說明你的JSP引擎沒有問題,但寫入數(shù)據(jù)庫(kù)時(shí)你的JDBC能不能處理中文,同一公司不同版本的JDBC都有支持中文和不支持中

          文的情況,RESIN自帶的MYSQL JDBC就不支持,MM的就支持,還有你的數(shù)據(jù)庫(kù)類型是否支持中文?CHAR的一般支持,但是否用binary存儲(chǔ)雙字節(jié)碼

          34. 問:對(duì)于JFrame,hide(),show()與setVisibel()有什么區(qū)別嗎?
          答:
          setVisible()從Component繼承過來,而hide(),show()從Window里面繼承過來。
          Makes the Window visible. If the Window and/or its owner are not yet displa yable, both are made displayable. The Window will

          be validated prior to being made visible. If t he Window is already visible, this will bring the Window to the front. 區(qū)別在

          這。
          36. 問:sendRedirect為什么不可以轉(zhuǎn)到mms協(xié)議的地址的?response.sendRedirect("mms://missiah.adsldns.org:9394");
          答:java平臺(tái)目前實(shí)現(xiàn)的protocol中并沒有mms,你可以取系統(tǒng)屬性java.protocol.handler.pkgs看看它的值中有沒有mms,所以如果要想重定向

          到mms://host這樣和URL,只有生成客戶端的JAVASCRIPT讓它來重定向

          37. 問:JTable中怎樣定義各個(gè)Columns和Width和怎樣設(shè)置表格的內(nèi)容靠做靠右或居中?
          答:
          TableColumn tc = table.getColumn("Name");//取得列名為"Name"的列Handle
          int currentWidth = tc.getPreferredWidth(); //取得該列當(dāng)前的寬度
          tc.setPreferredWidth(200); //設(shè)置當(dāng)前列寬
          tc.setMaxWidth(200); //設(shè)置該列最大寬度
          tc.setMinWidth(50); //設(shè)置該列最小寬度

          38. 問:批操作是否可用于select語句?
          答:批操作其實(shí)是指成批理更新的操作,絕對(duì)不可能用于select操作。

          39. 問:為什么jsp路徑太深文件名太長(zhǎng)就無法讀取文件?
          答:path不能超過255長(zhǎng)度,不然就找不到了.這是作業(yè)系統(tǒng)的事。

          40. 問:如何讓頁面不保留緩存?
          答:
          <%
          response.setHeader("Pragma","No-cache");
          response.setHeader("Cache-Control","no-cache");
          response.setDateHeader("Expires", 0);
          %>

          41. 問:我的applet code 中用到j(luò)button 時(shí)就出錯(cuò)是否由于ie不支持swing package 請(qǐng)問應(yīng)怎么辦?
          答:JBUTTON是SWING基本包啊,只要把jdk/jre/lib/rt.jar放在classpath就行了.不要加載任何別的庫(kù)。

          42. 問:不知道java是否支持midi格式,如果支持,應(yīng)該怎么把wave格式轉(zhuǎn)換成midi格式?
          答:目前還不行,可以看一下JMF三個(gè)版中對(duì)MIDI的格式支持是read only,而WAVE是read/write,MIDI只能播放,不能生成。

          43. 問:在jsp里面防止用戶直接輸入url進(jìn)去頁面,應(yīng)該怎么做呢?
          答:
          一是從web服務(wù)器控制,對(duì)某一目錄的所有訪問要通過驗(yàn)證.
          二是在要訪問的頁面中加入控制.這個(gè)一般用session,也可以用請(qǐng)求狀態(tài)碼實(shí)現(xiàn)

          44. 問:
          例如后臺(tái)有一計(jì)算應(yīng)用程序(此程序運(yùn)算起來很慢,可持續(xù)幾分鐘到幾小時(shí),這不管,主要是能激活它),客戶機(jī)講任務(wù)提交后,服務(wù)器對(duì)任

          務(wù)進(jìn)行檢測(cè)無誤后將向服務(wù)器后臺(tái)程序發(fā)送信息,并將其激活。要求如下:
          1)首先將后臺(tái)程序激活,讓它執(zhí)行此任務(wù)(比如,前臺(tái)將計(jì)算的C代碼提交上后,后臺(tái)程序程序能馬上調(diào)用,并將其運(yùn)行)
          2)要在前臺(tái)JSP頁面中顯示運(yùn)行過程信息(由于運(yùn)行時(shí)間長(zhǎng),希望讓客戶看到運(yùn)行過程中產(chǎn)生的信息)如何完成?

          答:
          活是可以的,運(yùn)行一個(gè)shell讓它去運(yùn)行后臺(tái)就行,但不可能取出運(yùn)行信息,因?yàn)镠TTP的超時(shí)限制不可能永遠(yuǎn)等你后臺(tái)運(yùn)行的,而且信息如果要?jiǎng)討B(tài)

          實(shí)時(shí)推出來就得用SERVER PUSH技術(shù)。

          45. 問:數(shù)據(jù)庫(kù)是datetime 型 ,插入當(dāng)前時(shí)間到數(shù)據(jù)庫(kù)?
          答:
          java.sql.Date sqlDate = new java.sql.Date();
          PreparedStatement pstmt = conn.prepareStatement("insert into foo(time) values(?)");
          pstmt.setDate(1,sqlDate);
          pstmt.executeUpdate();

          46. 問:怎樣去掉字符串前后的空格。
          答:String.trim()

          47. 問:session怎樣存取int類型的變量?
          答:
          session.setAttribute("int", i+"");
          int i = Integer.parseInt(session.getAttribute("int"));

          48. 問:在javascript中如何使輸出的float類型的數(shù)據(jù)保留兩位小數(shù)。
          答:Math.round(aaaaa*100)/100。

          49. 問:在bean種如何調(diào)用session
          答:
          你可把session對(duì)象作為一個(gè)參數(shù)傳給bean
          在BEAN中定義HttpServletRequest request;HttpSession session;
          然后
          session = request.getSession(false);
          false為如果session為空,不建立新的session
          將session作為參數(shù)傳入.其實(shí)只要將request傳入就可以

          50. 問:如何把txt或word文件按原格式顯示在jsp頁面或servlet上?
          答:
          其實(shí)一個(gè)非常簡(jiǎn)單的解決方法就是在服務(wù)器的MIME中指點(diǎn)定TEXT和WORD的解釋方式,然后用JSP或SERVLET生成它就行了,客戶端就會(huì)自動(dòng)調(diào)用相

          應(yīng)程序打開你的文檔。
          如果是希望按原格式的顯示在頁面上,而不是調(diào)用其他程序打開那么你可以試試用WEBDEV協(xié)議,可以說這是MS的一個(gè)亮點(diǎn).它是在WEB方式下打開

          文檔,和共享一樣.完全符合的要求。

          51. 問:object的clone方法為什么不能直接調(diào)用?
          答:
          這個(gè)方法在object中是protected
          為什么要把這個(gè)方法定義為protected,這是一個(gè)折中,它的目的是想知道你這個(gè)方法在Object里只是一個(gè)標(biāo)記,而不是一個(gè)實(shí)現(xiàn),比如

          public class Object
          {
          .............
          protected Object clone()
          {}
          }

          所以直接繼承的clone()方法并不能做任何時(shí),你要使用這個(gè)方法就要重載這個(gè)方法并放寬訪問權(quán)限為public,或?qū)崿F(xiàn)cloneable接口. 但它沒法

          這樣告訴你它沒有真的實(shí)現(xiàn),只好用protected 方法加以警示

          52. 問:一個(gè)頁面中如何刷新另外一個(gè)頁面?
          答:
          要求是這些面頁必須有關(guān)聯(lián),一是它們都有一個(gè)共同的頂層幀,也就是說是一個(gè)幀內(nèi)的分級(jí)頁面,當(dāng)然可以是任意級(jí),幀內(nèi)再分幀也可以,另一個(gè)可

          能是當(dāng)前窗口彈出的窗口,如果沒有聯(lián)系,那就不可能用一個(gè)頁面刷新另一個(gè)頁面. 幀內(nèi)只要一級(jí)一級(jí)引用就行了.

          比如在左幀中一個(gè)頁面中寫top.right.location.reload();那么名為right的右?guī)械捻撁婢蜁?huì)刷新. 彈出的一樣,用open時(shí)的名稱刷新子窗口,

          子窗口用opener刷新主窗口

          53. 問:如何在jsp中怎么樣向客戶端寫cookies?
          答:
          Cookie coo = new Cookie(name, value);
          HttpServletResponse.addCookie(name);

          54. 問:為什么jTextField1.setText("aaabbb");jTextField2.setText("AAABBB"); 得到的字體寬度不一樣?
          答:就是說如果不是指定為等寬字體,每個(gè)字體的寬度都是不一樣的.因此JAVA中用FontMetrics 類來取字符寬度。

          55. 問:String kk=application/octet-stream; name="G:/SMBCrack.exe";如何得到SMBCrack.exe?
          答:
          這應(yīng)該是解析上傳時(shí)候的二進(jìn)制流得到的這一行里面格式是固定的,取到name="后面的字符串,然后把";去掉。然后取最后一個(gè)/后面的所有字

          符組成一個(gè)新字符串就行了。

          56. 問:如何傳值并不刷新頁面?
          答:
          彈出一個(gè)頁面進(jìn)行值的選擇或者輸入,ok后使用將值傳給原窗口,使用javascript關(guān)閉打開的窗口即可:
          window.close();opener.focus();

          57. 問:有一個(gè)字符串:"EF0C114EA4",如何變?yōu)閍[0] = 0xEF a[1] = 0x0C a[2] = 0x11 a[3] = 0x4E a[4] = 0xA4?
          答:
          String str="EF0C114EA4F";
          out.print(str+"<br>");
          int l=str.length()/2+str.length()%2,j=0,k=0;
          String[] a=new String[l];
          for(int i=0;i<l;i++){
          if(str.length()-j==1)
          k=str.length();
          else
          k=j+2;
          a="0x"+str.substring(j,k);
          out.print("a["+Integer.toString(i)+"]="+a+"<br>");
          j+=2;
          }

          58. 問:怎樣將一個(gè)int轉(zhuǎn)換成一個(gè)四字節(jié)的byte數(shù)組?
          答:
          int x = 1234567;
          byte[] b = new byte[4];
          for(int i=0;i<b.length;i++)
          {
          b = (x >>( i*8)) & 0xFF;
          }

          59. 問:indexOf()的使用需要注意什么?
          答:參數(shù)是指從第幾位(1,2,3,...)開始搜索,而返回值是指搜索到的位置(0,1,2,3.......)注意是從零算起的。

          60. 問:在Java應(yīng)用程序中如何動(dòng)態(tài)的添加一個(gè)按鈕?
          答:
          這里涉及一個(gè)組件重繪的問題,組件要先于panel被顯示之處存在,如果一panel已經(jīng)顯示了,那么加在上面你能看到嗎?但如果在同一個(gè)panel上,

          先有button A,假如按下它加了butt on B,這時(shí)你如果使整個(gè)panel重給,那么A本身要重繪,它的事件監(jiān)聽就沒有了,當(dāng)然也就加不成B了,所以如

          果要先有另一個(gè)panel,當(dāng)按A時(shí)把B加在這個(gè)panel上并重繪這個(gè)paenl,其實(shí)更好的方法是先把B加在panel中,同一個(gè)也行.把它setVisiable(flas

          e),按A時(shí)設(shè)為 true。

          61. 問:book mybook=new book(bookid);book是servlet,出錯(cuò)。
          答:
          book是servlet,能book mybook=new book(bookid);
          說明自己實(shí)現(xiàn)了servlet容器?不然,servlet能讓你自己去調(diào)用? servlet如果調(diào)用其實(shí)和EJB連1%的區(qū)別都沒有,它們都是自己繼承或?qū)崿F(xiàn)一些接

          口,在這些父類或接口中實(shí)現(xiàn)了如果和容器"打交道"的方法,然后容器調(diào)用這些方法來管理它,讓它生成實(shí)例,池化,鈍化,銷毀,再生等.所以這樣

          寫是錯(cuò)誤的。

          62. 問:給定一個(gè)字符串5*(5+9)/7怎樣計(jì)算出結(jié)果?
          答:
          可有兩種方法
          1。用堆棧完成
          2。最簡(jiǎn)單的方法,不用編程,如果有任何一個(gè)數(shù)據(jù)庫(kù)的化,用select (5*(5+9)/7) from oneTable

          63. 問:如何實(shí)現(xiàn)遞交表單內(nèi)容的加密解密?
          答:
          如果你用IE目前只能用SSL協(xié)議,這一層不要你考慮,否則只你用你自己的工具加密傳輸,接收后再解密友,至于如何加解,如果要和公認(rèn)的系統(tǒng)結(jié)

          合,就用通用的MD5,RAS等公開算法,如果你只是自己傳自己解,你隨便按你的想法把數(shù)據(jù)加上一些東西,取回來按規(guī)則減掉這些東西,我敢保證除

          你自己沒有任何人能知道解密方法.

          64. 問:為什么Integer.parseInt("+1");會(huì)拋出NumberFormatException的異常?
          答:因?yàn)?+"運(yùn)行算在JAVA中被重載.系統(tǒng)無法確定你用的是算術(shù)加還是字符+。
          這一點(diǎn)可以在JAVASCRIPT中更好地理解:
          <form name="t"><input name=s value=1234></form>
          var a = document.t.s.value+1;
          這時(shí)a = 12345,因?yàn)閐ocument.t.s.value作為字符串.但var a = document.t.s.value-1;
          a 就是1233,因?yàn)橄到y(tǒng)知道-運(yùn)算肯定是算術(shù)運(yùn)行.所以把document.t.s.value轉(zhuǎn)換成數(shù)字.


          65. 問:hashCode() 有什么用為什么有時(shí)候需要覆蓋Object里的hashcode()方法?
          答:這就是這個(gè)對(duì)象的身份證啊,要不如何區(qū)分哪個(gè)對(duì)象。

          66. 問:怎樣在tomcat中實(shí)現(xiàn)一個(gè)定時(shí)執(zhí)行的東東?
          答:
          在應(yīng)用程序啟動(dòng)時(shí)自動(dòng)運(yùn)行。servlet2.3中定義了ServletListener,監(jiān)聽Servlet Con text的啟動(dòng)或則關(guān)閉(可在配置文件中配置),啟動(dòng)時(shí)

          觸發(fā)一個(gè)守護(hù)程序的運(yùn)行(可以實(shí)現(xiàn)java.util.Timer或則 javax.swing.Timer).

          67. 問:程序可以輸出自己?jiǎn)幔?br />答:孔德悖論這個(gè)非常有名的法則.就是說任何程序都不可能輸出自己.

          68. 問:能夠把字符轉(zhuǎn)化成ASCII碼?比如將 A 轉(zhuǎn)化成 65?
          答:
          int a='A';
          out.println(a);

          69. 問:如何區(qū)分輸入的文字中的全角與半角?
          答:由于不能分辨出全角和半角字符的值有什么規(guī)律,只好把全角符號(hào)牧舉出來了.

          70. 問:用戶注冊(cè)后的自動(dòng)發(fā)信程序該怎么做?
          答:
          這種發(fā)信程序不考慮性能,因?yàn)椴豢赡?秒就有一個(gè)人注冊(cè),我們說的考慮性能的發(fā)信程序是指上百萬封信在隊(duì)列里要不停發(fā)送的那種,象你這個(gè)

          隨便怎么寫一個(gè)程序都行,沒有必要用JAVAMAIL.只要指定一個(gè)發(fā)信的服務(wù)器然后用cocket連它的25口就行了.自己用SOCKET連SMTP的25口發(fā)一封

          信就好象兩個(gè)鄰居之間送一樣?xùn)|西,直接遞過去得了,用JAVAMAIL,消息機(jī)制就是你把這個(gè)東西從郵局寄給你的鄰居了.

          posted @ 2006-07-24 12:04 nbt 閱讀(884) | 評(píng)論 (0)編輯 收藏

          僅列出標(biāo)題
          共9頁: 上一頁 1 2 3 4 5 6 7 8 9 下一頁 
          <2025年5月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿(3)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          相冊(cè)

          收藏夾

          Java技術(shù)網(wǎng)站

          友情鏈接

          國(guó)內(nèi)一些開源網(wǎng)站

          最新隨筆

          搜索

          積分與排名

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 邢台县| 五寨县| 南乐县| 贡嘎县| 绥德县| 东阿县| 康定县| 青川县| 高陵县| 三台县| 盈江县| 墨竹工卡县| 汉沽区| 衢州市| 东城区| 芒康县| 铜陵市| 黄山市| 白水县| 铁岭市| 贺州市| 吉林省| 定西市| 新干县| 西林县| 竹北市| 泰顺县| 疏附县| 常州市| 简阳市| 谢通门县| 榆树市| 诸城市| 桃江县| 鄯善县| 固安县| 曲沃县| 灌南县| 芮城县| 木兰县| 元氏县|