數據庫設計經驗

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

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

          檢查表名、報表名和查詢名之間的命名規范。你可能會很快就被這些不同的數據庫要素的名稱搞糊涂了。假如你堅持統一地命名這些數據庫的不同組成部分,至少你應該在這些對象名字的開頭用 Table、Query 或者 Report 等前綴加以區別。

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

          一定要記住過去的經驗教訓!我們開發人員還應該通過分享自己的體會和經驗互相幫助。即使用戶認為他們再也不需要什么支持了,我們也應該對他們進行這方面的教育,我們都曾經面臨過這樣的時刻“當初要是這么做了該多好..”。
          在物理實踐之前進行邏輯設計
          在深入物理設計之前要先進行邏輯設計。隨著大量的 CASE 工具不斷涌現出來,你的設計也可以達到相當高的邏輯水準,你通常可以從整體上更好地了解數據庫設計所需要的方方面面。
          了解你的業務
          在你百分百地確定系統從客戶角度滿足其需求之前不要在你的 ER(實體關系)模式中加入哪怕一個數據表(怎么,你還沒有模式?那請你參看技巧 9)。了解你的企業業務可以在以后的開發階段節約大量的時間。一旦你明確了業務需求,你就可以自己做出許多決策了。

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

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

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

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

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

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

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

          大多數數據庫都索引自動創建的主鍵字段,但是可別忘了索引外鍵,它們也是經常使用的鍵,比如運行查詢顯示主表和所有關聯表的某條記錄就用得上。還有,不要索引 memo/note 字段,不要索引大型字段(有很多字符),這樣作會讓索引占用太多的存儲空間。
          不要索引常用的小型表
          不要為小型數據表設置任何鍵,假如它們經常有插入和刪除操作就更別這樣作了。對這些插入和刪除操作的索引維護可能比掃描表空間消耗更多的時間。
          不要把社會保障號碼(SSN)或身份證號碼(ID)選作鍵
          永遠都不要使用 SSN 或 ID 作為數據庫的鍵。除了隱私原因以外,須知政府越來越趨向于不準許把 SSN 或 ID 用作除收入相關以外的其他目的,SSN 或 ID 需要手工輸入。永遠不要使用手工輸入的鍵作為主鍵,因為一旦你輸入錯誤,你唯一能做的就是刪除整個記錄然后從頭開始。

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

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

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

          采用給表、列[字段]、觸發器等加注釋的數據庫工具。是的,這有點費事,但從長遠來看,這樣做對開發、支持和跟蹤修改非常有用。

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


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

          Svn使用手記

          一、 軟件下載并安裝

          1、? 服務器

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

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

          2、? 客戶端

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

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

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

          三、 配置用戶和權限

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

          svnserve.conf 文件內容如下:

          [general]

          # anon-access = read

          # auth-access = write

          # password-db = passwd

          # authz-db = authz

          # realm = My First Repository

          各參數定義如下:

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

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

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

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

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

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

          passwd 文件內容如下:

          [users]

          # harry = harryssecret

          # sally = sallyssecret

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

          四、 運行服務器

          在命令行模式下,運行 svnserve –d –r f:\repository ,服務器即可啟動。

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

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

          3、確定后提示要輸入用戶名和密碼,輸入我們在 passwd 文件中定義的用戶名和密碼后(如用戶名為 harry ,密碼為 harryssecret ),數據就導入到我們定義的版本庫 repository 中了。

          六、 客戶端操作

          1、? 從版本庫中取出項目:

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

          2、? 更新項目:

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

          3、? 提交修改:

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

          4、? 查看文件庫

          選擇“文件庫瀏覽器”菜單,就可以打開 Subversion 服務器上可見的文件庫, 并可以對文件庫中的文件及文件夾進行操作。

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

          Excel報表之js版

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

          個根據表單數據在client端用js生成excle的demo,令我我激動了半天------js太強了!

          下面分享一下這段js:
          ?
          ?1var?excel??=?new?ActiveXObject("Excel.Application");?//創建AX對象excel
          ?2excel.visible?=true;?//設置excel可見屬性
          ?3var?workbook?=?excel.Workbooks.Add;?//獲取workbook對象
          ?4var?sheet1?=?xlBook.Worksheets(2);??//創建sheet1
          ?5var?sheet2?=?xlBook.Worksheets(1);??//創建sheet2
          ?6sheet1.Range(sheet1.Cells(1,1),sheet1.Cells(1,14)).mergecells=true;?//合并單元格
          ?7sheet1.Range(sheet1.Cells(1,1),sheet1.Cells(1,14)).value="員工月考核成績";?//設置單元格內容
          ?8sheet1.Range(sheet1.Cells(1,1),sheet1.Cells(1,14)).Interior.ColorIndex=6;//設置底色?
          ?9sheet1.Range(sheet1.Cells(1,1),sheet1.Cells(1,14)).Font.ColorIndex=5;//設置字體色?
          10sheet1.Rows(1).RowHeight?=?20;?//設置列高
          11sheet1.Rows(1).Font.Size=16;??//設置文字大小
          12sheet1.Rows(1).Font.Name="宋體";?//設置字體
          13//設置每一列的標題
          14sheet1.Cells(2,1).Value="工程師考核項";
          15sheet1.Cells(2,2).Value="總分";
          16sheet1.Cells(2,3).Value="研發進度";
          17sheet1.Cells(2,4).Value="出勤率";
          18sheet1.Cells(2,5).Value="執行力";
          19sheet1.Cells(2,6).Value="責任心";
          20sheet1.Cells(2,7).Value="工作規范";
          21sheet1.Cells(2,8).Value="協作精神";
          22sheet1.Cells(2,9).Value="進取性";
          23sheet1.Cells(2,10).Value="工作合理性";
          24sheet1.Cells(2,11).Value="解決問題能力";
          25sheet1.Cells(2,12).Value="應變能力";
          26sheet1.Cells(2,13).Value="人際技能";
          27sheet1.Cells(2,14).Value="理解能力";
          28//從表單循環控件中取出數據逐行插入對應列的數據
          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

          基本的代碼已經實現了,生成excel的格式和一些統計計算,用js寫應該是很方便的,以后有例子再作補充。

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

          便。個人認為簡單就是美!

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

          java enum 枚舉類

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

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

          public?class?SystemConstant?{
          ????
          /**
          ?????*?金庫 sourceortarget?系統相關
          ?????
          */

          ????
          public?static?final?String?CASHWASTEBOOK_SOURCEORTARGET_SYS?=?"系統";
          ????
          /**
          ?????*?附件上傳路徑
          ?????
          */
          ?
          ????
          public?static?String?UPLOAD_ATTACHMENT_DIR="upload\\";
          ????
          public?static?String?CONFIG_DIR="config\\";
          ????
          /**
          ?????*?臨時文件路徑
          ?????
          */

          ????
          public?static?String?TEMP_DIR="temp\\";
          ????
          /**
          ?????*?會員關系
          ?????
          */

          ????
          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?=?"您不能選擇管理員登錄";
          ????
          /**管理員選擇會員或家長登錄*/
          ????
          public?static?final?String?MESSAGE_LOGIN_TYPEERROR2?=?"您應該選擇管理員登錄";
          ????
          /**會員或家長重復登陸*/
          ????
          public?static?final?String?MESSAGE_LOGIN_REPEAT?=?"可能因為以下原因,您無法登陸系統\n\t1 有人盜用您的帳號\n2?您的{0}正在使用本帳號";
          ????
          public?static?final?String?MESSAGE_LONGIN_PASSWORDERROR?=?"用戶名或密碼無效";
          ????
          public?static?final?String?MESSAGE_INSUFFICIENT_FUNDS?=?"您的帳戶余額不足";
          ????
          public?static?final?String?MESSAGE_MEMBER_ONLINETIME_FULL?=?"您今日的累計上線時間已超過1.5小時";
          ????
          /**會員每天最大登錄時限?單位分鐘?默認90**/
          ????
          public?static?final?int?MEMBER_MAX_DAY_ONLINE_MINUTES?=?90;
          ????
          }

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

          ? 2 說到從xml文件讀取屬性來動態配置枚舉類,我下面就舉個例子,演示演示
          ???? 一些web系統中涉及到文件上傳,根據文件類型顯示相應圖標,并且有些jsp,asp等等的文件不允許上傳,下面就是一個滿足這種需求的枚舉類,它最大的特點就是可以從xml中讀取配置信息
          /**
          ?*?系統中用到的文件擴展名?枚舉類
          ?*?
          @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目錄中load
          ?????*?
          ?????
          */

          ????
          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>

          可能系統中其他的一些枚舉類(比如1 中提到的RelationShip)也會用到非常類似的做法,這時候我們就可以重構了,將一些共同的特點抽取到一個抽象類中。這將會在以后的文章中提到。
          有不同的觀點,請聯系come2u at gmail.com? ,歡迎交流。

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

          Java文件操作詳解

          輸入輸出流?
          在Java中,我們把能夠讀取一個字節序列的對象稱作一個輸入流;而我們把夠寫一個字節序列稱作一個輸出流。它們分別由抽象類?
          InputStream和OutputStream類表示。因為面向字節的流不方便用來處理存儲為Unicode(每個字符使用兩個字節)的信息。所以Java?
          引入了用來處理Unicode字符的類層次,這些類派生自抽象類Reader和Writer,它們用于讀寫雙字節的Unicode字符,而不是單字節字符。?
          Java.io包簡介?
          JDK標準幫助文檔是這樣解釋Java.io包的,通過數據流、序列和文件系統為系統提供輸入輸出。?
          InputStream類和OutputStream類?
          InputStream類是所有輸入數據流的父類,它是一個抽象類,定義了所有輸入數據流都具有的共通特性。?
          java.io.InputStream的方法如下:?
          public?abstract?read()throws?IOException?
          讀取一個字節并返回該字節,如果到輸入源的末則返回-1。一個具體的輸入流類需要重載此方法,以提供?有用的功能。例如:在FileInputStream類中,該方法從一個文件讀取一個字節。?
          public?int?read(byte[]?b)throws?IOException?
          把數據讀入到一個字節數據中,并返回實際讀取的字節數目。如果遇到流末?則返回-1,該方法最多讀取b.length個字節。?
          public?abstract?int?read(byte[]?b,int?off,int?len)throws?IOException?
          把數據讀入到一個字節數組中并返回實際讀取的字節數目。如果遇到流的末尾則的返回-1。?其中參數off表示第一個字節在b中的位置,len表示讀取的最大字節數。?
          public?long?skip(long?n)throws?IOException?
          略過N個字節不讀取,會返回實際略過的字節數目。因為數據流中剩下的數據可能不到N?個字節那么多,所以此時返回值會小于N。?
          public?int?available()throws?IOException?
          read方法(包括后面要講的OutputStream類的Write方法)都能夠陰塞一個線程,直到字節被?實際讀取或寫入。這意味著如果一個流不能立即被讀或被寫?
          /*?
          *?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");?//不區分大小寫
          //?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];?//定義對象數組
          for(int?i=0;i<ss.length;i++)?
          {?
          ss?=?"信息技術和互聯網(計算機軟硬件,通訊)?"+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();?
          }?
          /**?
          *?創建與刪除文件?
          *?@param?filePath?
          *?@param?fileName?
          *?@return?創建成功返回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("文件已經刪除!");?
          }?
          else?
          {
          ???System.out.println("對不起,該路徑為目錄!");?
          ???
          }
          }
          else?
          {?
          file.createNewFile();?//jdk5.0的新方法
          result?=?true;?
          System.out.println("文件已經創建!");?
          }?
          return?result;?
          }?
          /**?
          *?創建和刪除目錄?
          *?@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("目錄已經存在,已刪除!");?
          result?=?true;?
          }
          else{
          System.out.println("對不起,該路徑為文件!");?
          }
          }?
          else?
          {?
          file.mkdir();?
          System.out.println("目錄不存在,已經建立!");?
          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());?
          }?
          }?
          }?
          /**?
          *?檢查文件中是否為一個空?
          *?@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+"?文件中沒有數據!");?
          }?
          else?
          {?
          System.out.println(fileName+"?文件中有數據!");?
          }?
          fr.close();?
          return?result;?
          }?
          /**?
          *?讀取文件中的所有內容?
          *?@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();?
          }?
          /**?
          *?一行一行的讀取文件中的數據?
          *?@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("新建目錄操作出錯");?
          ?????????? e.printStackTrace();?
          ?????? }?
          ?? }?
          ?
          ?? /**?
          ???? *? @see 新建文件?
          ???? *? @param? filePathAndName? String? 文件路徑及名稱? 如c:/fqf.txt?
          ???? *? @param? fileContent? String? 文件內容?
          ???? *? @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("新建文件操作出錯");?
          ?????????? 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("刪除文件操作出錯");?
          ?????????? e.printStackTrace();?
          ?
          ?????? }?
          ?
          ?? }?
          ?
          ?? /**?
          ???? *? @see 刪除文件夾?
          ???? *? @param? filePathAndName? String? 文件夾路徑及名稱? 如c:/fqf?
          ???? *? @param? fileContent? String?
          ???? *? @return? boolean?
          ???? */?
          ?? public? void? delFolder(String? folderPath)? {?
          ?????? try? {?
          ?????????? delAllFile(folderPath);? //刪除完里面所有內容?
          ?????????? String? filePath? =? folderPath;?
          ?????????? filePath? =? filePath.toString();?
          ?????????? java.io.File? myFilePath? =? new? java.io.File(filePath);?
          ?????????? myFilePath.delete();? //刪除空文件夾?
          ?
          ?????? }?
          ?????? catch? (Exception? e)? {?
          ?????????? System.out.println("刪除文件夾操作出錯");?
          ?????????? 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 復制單個文件?
          ???? *? @param? oldPath? String? 原文件路徑? 如:c:/fqf.txt?
          ???? *? @param? newPath? String? 復制后路徑? 如: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())? {? //文件存在時?
          ?????????????? 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;? //字節數? 文件大小?
          ?????????????????? System.out.println(bytesum);?
          ?????????????????? fs.write(buffer,? 0,? byteread);?
          ?????????????? }?
          ?????????????? inStream.close();?
          ?????????? }?
          ?????? }?
          ?????? catch? (Exception? e)? {?
          ?????????? System.out.println("復制單個文件操作出錯");?
          ?????????? e.printStackTrace();?
          ?
          ?????? }?
          ?
          ?? }?
          ?
          ?? /**?
          ???? *? @see 復制整個文件夾內容?
          ???? *? @param? oldPath? String? 原文件路徑? 如:c:/fqf?
          ???? *? @param? newPath? String? 復制后路徑? 如: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("復制整個文件夾內容操作出錯");?
          ?????????? e.printStackTrace();?
          ?
          ?????? }?
          ?
          ?? }?
          ?
          ?? /**?
          ???? *? @see 移動文件到指定目錄?
          ???? *? @param? oldPath? String? 如:c:/fqf.txt?
          ???? *? @param? newPath? String? 如:d:/fqf.txt?
          ???? */?
          ?? public? void? moveFile(String? oldPath,? String? newPath)? {?
          ?????? copyFile(oldPath,? newPath);?
          ?????? delFile(oldPath);?
          ?
          ?? }?
          ?
          ?? /**?
          ???? *? 移動文件到指定目錄?
          ???? *? @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 獲得系統根目錄絕對路徑?
          ??? * @return String?
          ??? *???
          ??? */
          ?? public String getPath(){

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

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

          統計在線人數

          //SessionCounter.java\ozdvw
          package SessionCount;e?
          import javax.servlet.*; L9k0
          import javax.servlet.http.*; plT
          import java.io.*; w;
          import java.util.*; JC;@
          ?達內科技論壇 -- 達內科技論壇  @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
          ?達內科技論壇 -- 達內科技論壇  {Ytdk
          } ?達內科技論壇 -- 達內科技論壇  ri04&
          ?達內科技論壇 -- 達內科技論壇  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
          } ?達內科技論壇 -- 達內科技論壇  )9lR?P
          ?達內科技論壇 -- 達內科技論壇  !S
          //Clean up resources UxUNe
          public void destroy() { :=e2NM
          } ?達內科技論壇 -- 達內科技論壇  W'F
          ?達內科技論壇 -- 達內科技論壇  aHW&x9
          public void sessionCreated(HttpSessionEvent httpSessionEvent) { HH
          ? activeSessions++; DyZpv
          } ?達內科技論壇 -- 達內科技論壇  4WJ
          ?達內科技論壇 -- 達內科技論壇  8)#.
          public void sessionDestroyed(HttpSessionEvent httpSessionEvent) { \s,_t
          ? activeSessions--; *z
          ? System.out.println("test test");$s0T@W
          // ?System.out.println("---111"); ZF+
          } ?達內科技論壇 -- 達內科技論壇  MX
          public static int getActiveSessions() { tQ
          ?return activeSessions; )a4
          } ?達內科技論壇 -- 達內科技論壇  y%s
          } ?達內科技論壇 -- 達內科技論壇  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
          }?達內科技論壇 -- 達內科技論壇  ]M\-
          //-->#}q
          </script>rs(
          <script language="javascript">Ax%Qs3
          function removeline(){Q \@
          if(event.clientX<0&&event.clientY<0).45
          {?達內科技論壇 -- 達內科技論壇  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);[
          }?達內科技論壇 -- 達內科技論壇  ad6+
          }?達內科技論壇 -- 達內科技論壇  1`maF
          </script>0.
          ?達內科技論壇 -- 達內科技論壇  9
          <body onUnload="MM_callJS('removeline()')">I=QwN
          在線:<%= SessionCounter.getActiveSessions() %> Abd\
          </body>.
          </html>YZmy
          ////////////////////////////////6K6(k
          ///////////////////////////////HoW?y
          remove.jspZ{>=
          /////?達內科技論壇 -- 達內科技論壇  ]|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)判斷瀏覽器是關閉還是刷新 ,因為刷新也會調用onunload&&
          ?達內科技論壇 -- 達內科技論壇  c07F
          document.all.WebBrowser.ExecWB(45,1);是無提示的關閉瀏覽器!Q!*pf
          classid=CLSID:8856F961-340A-11D0-A96B-00C04FD705A2 |0gLI
          這個是調用不彈出對話框的方法,實際是調用系統的方法如下 ]9M
          document.all.WebBrowser.ExecWB(45,1); f:
          因為在javascript當中不能調用java方法,所以選擇另外寫一個jsp文件用于調用,;?(5yi
          invalidate()方法,(?A|`K
          ?達內科技論壇 -- 達內科技論壇  xv
          現在這個結果是正確的,因為我把private static int activeSessions = 1; //這里改成了1,本來照理應該設為0的,可以我運行第一次http://localhost:8080/servlet/count.jsp的時候得到的是0,所以我才把它改成1的,dKOp0
          那們老師或同學知道的話,麻煩告訴怎么為事,為什么在第一次創建session時不能觸發事件sessionCreated()Rw

          現在這個結果是正確的,因為我把private static int activeSessions = 1; //這里改成了1,本來照理應該設為0的,可以我運行第一次http://localhost:8080/servlet/count.jsp的時候得到的是0,所以我才把它改成1的, h(
          ,為什么在第一次創建session時不能觸發事件sessionCreated()g?

          session是個雙向機制,第一次訪問的時候,是從客戶端發起的,瀏覽器不知道這個網頁是否需要session,所以瀏覽器不會創建sessionId,當這個請求到達服務器的時候,沒有sessionId,d}--5
          ?達內科技論壇 -- 達內科技論壇  r0_/S
          SessionCounter 是被嵌在jsp里的,所以第一次顯示的時候,得到jsp頁面的session創建是在jsp頁面滯后,也就是說SessionCounter是滯后于jsp頁面的.xKTZrv
          ?達內科技論壇 -- 達內科技論壇  V@)
          順便說一句,extends HttpServlet 是多余的。]&

          在頁面里頁設置一個退出按鈕.調用quit.jsp=
          它的內容是:h>
          我們用一個quit.jsp來處理用戶退出系統的操作,quit.jsp負責注銷session,及時釋放資源。>D6T
          ?達內科技論壇 -- 達內科技論壇  uj&B
            ·注銷session。Z5K&
          ?達內科技論壇 -- 達內科技論壇  ##
            ·關閉瀏覽器窗口。@Q(
          ?達內科技論壇 -- 達內科技論壇  TP^wA
            其代碼如下所示:"
          ?達內科技論壇 -- 達內科技論壇  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?
          ?達內科技論壇 -- 達內科技論壇  3-L-
            其中第3行負責注銷session,原先放入session的對象將解綁定,等待垃圾回收以釋放資源。對于本例而言,session中有一個名為ses_userBean的userBean對象(它是在switch.jsp中放入session的),調用session.invalidate()后,userBean從session中解綁定,它的valueUnbound()方法會被觸發調用,然后再等待垃圾回收。A/cr
          ?達內科技論壇 -- 達內科技論壇  +Nb
            第5~8行是一段javascript腳本程序,負責關閉窗口,如果網頁不是通過腳本程序打開的(window.open()),調用window.close()腳本關閉窗口前,必須先將window.opener對象置為null,如第6行所示,否則瀏覽器會彈出一個確定關閉的對話框,筆者發現這個問題困擾了不少的Web程序員,故特別指出。s `|*)

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

          Spring Framework之最佳實踐二

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

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

          我們的思路是先寫一個BaseDao,仿照HibernateTemplate,將基本功能全部實現:

          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,代碼就會很少。

          從BaseDao繼承出來EntityDao,專門負責一般實體的基本操作,會更方便。

          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);
          ??? }
          ...

          }

          這樣我們就有了一個通用的Hibernate實體引擎,可以對任何Hibernate實體實現基本的增加、修改、刪除、查詢等。

          其它的BusinessService就可以繼承EntityManager,快速實現業務邏輯。

          具體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 閱讀(356) | 評論 (0)編輯 收藏

          Spring Framework之最佳實踐一



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

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

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

          Context中,最重要的是Beanfactory,它是將接口與實現分開,非常重要。以前我們寫程序,如一個接口IDocument,一個實現類Document1。在寫程序時,需寫成IDocument doc = new Document1(),一旦我們的實現類需改變時,變為Document2,則程序需寫成IDocument doc = new Document2(),所有用到的地方全需改。Beanfactory幫我們解決了這個問題,用context后,寫法變為IDocument doc=(IDocument)beanFactory.getBean("doc")。如果實現類從Document1改為Document2,直接在配置文件改就可以了。Context是Bean factory的進一步抽象。很多人都喜歡用ApplicationConext,用Servlet把它Load。這樣就把Bean Factory與Web綁定在一起。如果是Fat Client或Remote調用,則這些Bean factory就很難調用,實際是將表現層與業務層綁定的太緊。推薦的方法是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>


          這樣,就可隨時動態擴展,實現組件式的開發。

          (未完,待續)

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

          網頁常用小技巧(JavaScript)

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

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

          3. onpaste="return false" 不準粘貼

          4. oncopy="return false;" oncut="return false;" 防止復制

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

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

          7. <input style="ime-mode:disabled"> 關閉輸入法

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

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

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

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

          12.刪除時確認
          <a href="javascript:if(confirm("確實要刪除嗎?"))location="boos.asp?&areyou=刪除&page=1"">刪除</a>?

          13. 取得控件的絕對位置
          //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. 光標是停在文本框文字的最后
          <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. 最小化、最大化、關閉窗口
          <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=關閉 onclick=hh3.Click()>
          本例適用于IE

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

          18. 網頁不會被緩存
          <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>的區別??
          <div>(division)用來定義大段的頁面元素,會產生轉行?
          <span>用來定義同一行內的元素,跟<div>的唯一區別是不產生轉行?
          <layer>是ns的標記,ie不支持,相當于<div>

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

          22.不要滾動條??
          讓豎條沒有:?
          <body style="overflow:scroll;overflow-y:hidden">?
          </body>?
          讓橫條沒有:?
          <body style="overflow:scroll;overflow-x:hidden">?
          </body>?
          兩個都去掉?更簡單了?
          <body scroll="no">?
          </body>?

          23.怎樣去掉圖片鏈接點擊后,圖片周圍的虛線?
          <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.如何設定打開頁面的大小
          <body onload="top.resizeTo(300,200);">
          打開頁面的位置<body onload="top.moveBy(300,200);">

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

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

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

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

          31.TEXTAREA自適應文字行數的多少
          <textarea rows=1 name=s1 cols=27 onpropertychange="this.style.posHeight=this.scrollHeight">
          </textarea>
          32. 日期減去天數等于第二個日期
          <script language=Javascript>
          function cc(dd,dadd)
          {
          //可以加上錯誤處理
          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. 選擇了哪一個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.腳本永不出錯
          <SCRIPT LANGUAGE="JavaScript">?
          <!-- Hide?
          function killErrors() {?
          return true;?
          }?
          window.onerror = killErrors;?
          // -->?
          </SCRIPT>

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

          36. 檢測某個網站的鏈接速度:
          把如下代碼加入<body>區域中:
          <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=測試中……> =》<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="鏈接超時"}
          else
          {document.forms[0]["txt"+b].value="時間"+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. 各種樣式的光標
          auto :標準光標
          default :標準箭頭
          hand :手形光標
          wait :等待光標
          text :I形光標
          vertical-text :水平I形光標
          no-drop :不可拖動光標
          not-allowed :無效光標
          help :?幫助光標
          all-scroll :三角方向標
          move :移動標
          crosshair :十字標
          e-resize
          n-resize
          nw-resize
          w-resize
          s-resize
          se-resize
          sw-resize

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

          39.在規定時間內跳轉
          <META http-equiv=V="REFRESH" content="5;URL=http://www.51js.com">?

          40.網頁是否被檢索
          <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(
          " 對不起,您的瀏覽器的Cookie功能被禁用,請開啟 " );
          ??????}
          </ script >

          ?

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

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

          應用:計算字符串的長度(一個雙字節字符長度計2,ASCII字符計1)

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

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

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

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

          應用:javascript中沒有像vbscript那樣的trim函數,我們就可以利用這個表達式來實現,如下:

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

          利用正則表達式分解和轉換IP地址:

          下面是利用正則表達式匹配IP地址,并將IP地址轉換成對應數值的Javascript程序:

          function IP2V(ip)
          {
          re=/(\d+)\.(\d+)\.(\d+)\.(\d+)/g //匹配IP地址的正則表達式
          if(re.test(ip))
          {
          return RegExp.$1*Math.pow(255,3))+RegExp.$2*Math.pow(255,2))+RegExp.$3*255+RegExp.$4*1
          }
          else
          {
          throw new Error("Not a valid IP address!")
          }
          }

          不過上面的程序如果不用正則表達式,而直接用split函數來分解可能更簡單,程序如下:

          var ip="10.100.20.168"
          ip=ip.split(".")
          alert("IP值是:"+(ip[0]*255*255*255+ip[1]*255*255+ip[2]*255+ip[3]*1))

          匹配Email地址的正則表達式:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*

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

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

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

          我原來在CSDN上發貼尋求一個表達式來實現去除重復字符的方法,最終沒有找到,
          這是我能想到的最簡單的實現方法。思路是使用后向引用取出包括重復的字符,
          再以重復的字符建立第二個表達式,取到不重復的字符,兩者串連。
          這個方法對于字符順序有要求的字符串可能不適用。

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

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

          利用正則表達式限制網頁表單里的文本框輸入內容:

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

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

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

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

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

          JSP 70問

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

          2. 問:java中用什么表示雙引號
          答:"""

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

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

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

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

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

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

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

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

          11. 問:&&和&的區別?
          答:
          &&是短路的與操作,也就是當地一個條件是false的時候,第二個條件不用執行
          &相反,兩個條件總是執行。

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

          13. 問:浮點數相乘后結果不精確如100.0 * 0.6 結果等于 60.0004
          答:
          這不叫錯誤,float和double是這樣實現的.如果要精確計算,java提供了一個strictfp,它的計算遵循IEEE 754標準.而普通的float和double是

          由地平臺浮點格式或硬件提供的額外精度或表示范圍。

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

          15. 問:表單成功提交了,點后退顯示網頁過期
          答:
          在<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. 問:接口的簡單理解
          答:接口為了規范,比如我在接口中定義了一個方法:
          getData()
          這是用來從不同的數據庫中取數據的,就是JDBC的實現對于用戶,我不要知道每種數據庫是如何做的,但我知道如何它們要實現這個接口就一定有

          這個方法可以供我調用.這樣SUN就把這個接口給各個數據庫開發商,讓他們自己實現. 但為什么不用繼承而用接口哩,因為繼承只能從一個你類

          繼承,而接口可以實現多個,就是說我實現的子類有多個規定好的接口中的功能. 這只是簡單的理解,等你深入理解抽象的時候就知道抽象到抽象

          類時為什么還要再抽象到接口.

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

          的那個LOCATION給你. 這就是JAVASCRIPT在實現history.go(-x)的原理.

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

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

          開新的線程了.

          19. 問:簡要介紹一下compareTo方法
          答:
          compareTo方法是Comparable 接口必需實現的方法,只要實現Comparable

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

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

          21. 問:applet中如何獲得鍵盤的輸入
          答:application的System.in是當前系統的標準輸入,applet因為安全的原因不可能讀取當前系統(客戶端)的標準輸入,只能從它的ROOT組件的

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

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

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

          24. 問:連接池的使用是建立很多連接池,還是一個連接池里用多個連接?
          答:
          只有在對象源不同的情況下才會發生多個池化,如果你只連一結一個數據源,永遠不要用多個連結池. 所以連結池的初始化一定要做成靜態的,而

          且應該在構造對象之前,也就是只有在類LOAD的時候,別的時候不應該有任何生成新的連結池的時候。

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

          26. 問:怎樣把地址欄里的地址鎖定?
          答:把你的服務器的可訪問目錄索引選項關閉就行了,任何服務器都有一個conf文件,里面都有這個選項。

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

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

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


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

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

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

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

          文的情況,RESIN自帶的MYSQL JDBC就不支持,MM的就支持,還有你的數據庫類型是否支持中文?CHAR的一般支持,但是否用binary存儲雙字節碼

          34. 問:對于JFrame,hide(),show()與setVisibel()有什么區別嗎?
          答:
          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. 區別在

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

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

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

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

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

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

          41. 問:我的applet code 中用到jbutton 時就出錯是否由于ie不支持swing package 請問應怎么辦?
          答:JBUTTON是SWING基本包啊,只要把jdk/jre/lib/rt.jar放在classpath就行了.不要加載任何別的庫。

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

          43. 問:在jsp里面防止用戶直接輸入url進去頁面,應該怎么做呢?
          答:
          一是從web服務器控制,對某一目錄的所有訪問要通過驗證.
          二是在要訪問的頁面中加入控制.這個一般用session,也可以用請求狀態碼實現

          44. 問:
          例如后臺有一計算應用程序(此程序運算起來很慢,可持續幾分鐘到幾小時,這不管,主要是能激活它),客戶機講任務提交后,服務器對任

          務進行檢測無誤后將向服務器后臺程序發送信息,并將其激活。要求如下:
          1)首先將后臺程序激活,讓它執行此任務(比如,前臺將計算的C代碼提交上后,后臺程序程序能馬上調用,并將其運行)
          2)要在前臺JSP頁面中顯示運行過程信息(由于運行時間長,希望讓客戶看到運行過程中產生的信息)如何完成?

          答:
          活是可以的,運行一個shell讓它去運行后臺就行,但不可能取出運行信息,因為HTTP的超時限制不可能永遠等你后臺運行的,而且信息如果要動態

          實時推出來就得用SERVER PUSH技術。

          45. 問:數據庫是datetime 型 ,插入當前時間到數據庫?
          答:
          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類型的數據保留兩位小數。
          答:Math.round(aaaaa*100)/100。

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

          50. 問:如何把txt或word文件按原格式顯示在jsp頁面或servlet上?
          答:
          其實一個非常簡單的解決方法就是在服務器的MIME中指點定TEXT和WORD的解釋方式,然后用JSP或SERVLET生成它就行了,客戶端就會自動調用相

          應程序打開你的文檔。
          如果是希望按原格式的顯示在頁面上,而不是調用其他程序打開那么你可以試試用WEBDEV協議,可以說這是MS的一個亮點.它是在WEB方式下打開

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

          51. 問:object的clone方法為什么不能直接調用?
          答:
          這個方法在object中是protected
          為什么要把這個方法定義為protected,這是一個折中,它的目的是想知道你這個方法在Object里只是一個標記,而不是一個實現,比如

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

          所以直接繼承的clone()方法并不能做任何時,你要使用這個方法就要重載這個方法并放寬訪問權限為public,或實現cloneable接口. 但它沒法

          這樣告訴你它沒有真的實現,只好用protected 方法加以警示

          52. 問:一個頁面中如何刷新另外一個頁面?
          答:
          要求是這些面頁必須有關聯,一是它們都有一個共同的頂層幀,也就是說是一個幀內的分級頁面,當然可以是任意級,幀內再分幀也可以,另一個可

          能是當前窗口彈出的窗口,如果沒有聯系,那就不可能用一個頁面刷新另一個頁面. 幀內只要一級一級引用就行了.

          比如在左幀中一個頁面中寫top.right.location.reload();那么名為right的右幀中的頁面就會刷新. 彈出的一樣,用open時的名稱刷新子窗口,

          子窗口用opener刷新主窗口

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

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

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

          符組成一個新字符串就行了。

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

          57. 問:有一個字符串:"EF0C114EA4",如何變為a[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. 問:怎樣將一個int轉換成一個四字節的byte數組?
          答:
          int x = 1234567;
          byte[] b = new byte[4];
          for(int i=0;i<b.length;i++)
          {
          b = (x >>( i*8)) & 0xFF;
          }

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

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

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

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

          e),按A時設為 true。

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

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

          寫是錯誤的。

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

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

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

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

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


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

          66. 問:怎樣在tomcat中實現一個定時執行的東東?
          答:
          在應用程序啟動時自動運行。servlet2.3中定義了ServletListener,監聽Servlet Con text的啟動或則關閉(可在配置文件中配置),啟動時

          觸發一個守護程序的運行(可以實現java.util.Timer或則 javax.swing.Timer).

          67. 問:程序可以輸出自己嗎?
          答:孔德悖論這個非常有名的法則.就是說任何程序都不可能輸出自己.

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

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

          70. 問:用戶注冊后的自動發信程序該怎么做?
          答:
          這種發信程序不考慮性能,因為不可能1秒就有一個人注冊,我們說的考慮性能的發信程序是指上百萬封信在隊列里要不停發送的那種,象你這個

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

          信就好象兩個鄰居之間送一樣東西,直接遞過去得了,用JAVAMAIL,消息機制就是你把這個東西從郵局寄給你的鄰居了.

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

          僅列出標題
          共9頁: 上一頁 1 2 3 4 5 6 7 8 9 下一頁 
          <2025年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          導航

          統計

          常用鏈接

          留言簿(3)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          相冊

          收藏夾

          Java技術網站

          友情鏈接

          國內一些開源網站

          最新隨筆

          搜索

          積分與排名

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 祁阳县| 荆门市| 舟曲县| 静海县| 海丰县| 大新县| 读书| 西华县| 白玉县| 江川县| 顺义区| 英超| 雷波县| 紫金县| 泰宁县| 全椒县| 张家口市| 崇阳县| 定陶县| 阜阳市| 定州市| 新和县| 香港 | 富顺县| 故城县| 温泉县| 应城市| 吉林省| 张掖市| 岳阳县| 房产| 桦南县| 桃源县| 吐鲁番市| 彭泽县| 新绛县| 浦东新区| 金阳县| 天柱县| 隆化县| 巨鹿县|