programmer's home, welcome here!

          technical issues and my life

          常用鏈接

          統計

          最新評論

          #

          Spring內核研究-set方法注入和構造函數注入

          Spring種提供了2種常用的注入方式,set方法注入和構造函數注入。由于這2種注入方式很相似,都可以滿足我們的需求,所以在大多數情況下我們忽視了這2種注入方式的區別。下面讓我們看看這2種注入方式的特點。

                   我們先看看Spring在使用set方法注入時,是怎樣實例化一個Bean和Bean的合作者的:

                  在A中有一個setB方法用來接收B對象的實例。那么Spring實例化A對象的過程如下:

                  在不考慮Bean的初始化方法和一些Spring回調的情況下,Spring首先去調用A對象的構造函數實例化A,然后查找A依賴的對象本例子中是B(合作者)。一但找到合作者,Spring就會調用合作者(B)的構造函數實例化B。如果B還有依賴的對象Spring會把B上依賴的所有對象都按照相同的機制實例化然后調用A對象的setB(B b)b對象注入給A
                  因為Spring調用一個對象的set方法注入前,這個對象必須先被實例化。所以在"使用set方法注入"的情況下Spring會首先調用對象的構造函數。
                  我們在來看通過構造函數注入的過程:

                  如果發現配置了對象的構造注入,那么Spring會在調用構造函數前把構造函數需要的依賴對象都實例化好,然后再把這些實例化后的對象作為參數去調用構造函數。
                  在使用構造函數和set方法依賴注入時,Spring處理對象和對象依賴的對象的順序時不一樣的。一般把一個Bean設計為構造函數接收依賴對象時,其實是表達了這樣一種關系:他們(依賴對象)不存在時我也不存在,即“沒有他們就沒有我”。
                  通過構造函數的注入方式其實表達了2個對象間的一種強的聚合關系:組合關系。就比如一輛車如果沒有輪子、引擎等部件那么車也就不存在了。而且車是由若干重要部件組成的,在這些部件沒有的情況下車也不可能存在。這里車和他的重要部件就時組合的關系。如果你的應用中有這樣類似的場景那么你應該使用“構造函數注入”的方式管理他們的關系。“構造函數注入”可以保證合作者先創建,在后在創建自己。
                  通過set方法注入的方式表達了2個對象間較弱的依賴關系:聚合關系。就像一輛車,如果沒有車內音像車也時可以工作的。當你不要求合作者于自己被創建時,“set方法注入”注入比較合適。
                  雖然在理論上“構造函數注入”和“set方法注入”代表2種不同的依賴強度,但是在spring中,spring并不會把無效的合作者傳遞給一個bean。如果合作者無效或不存在spring會拋出異常,這樣spring保證一個對象的合作者都是可用的。所以在spring中,“構造函數注入”和“set方法注入”唯一的區別在于2種方式創建合作者的順序不同。
                  使用構造函數依賴注入時,Spring保證所有一個對象所有依賴的對象先實例化后,才實例化這個對象。(沒有他們就沒有我原則)
                  使用set方法依賴注入時,Spring首先實例化對象,然后才實例化所有依賴的對象。

          posted @ 2007-04-09 02:56 crazy zerlot 閱讀(1458) | 評論 (0)編輯 收藏

          SWT/JFace開發入門指南-轉載

          寫在前面的話

          終于決定提起筆來寫一篇關于swt和JFace編程的文章。在開始之前,我想先介紹一下你能夠從將要出現的這一系列文章里得到什么,以及更重要的,你不能得到什么。我們的時間是如此之重要,以至于我們很難容忍把它浪費在自己不關心的事情上。

          因為我剛開始寫,所以到底這些文章會分成幾次發布出來,也很難講。但是我心里大體有這樣一個提綱。也就是說,我打算介紹以下方面的內容:

                   設定swt以及JFace的開發環境

                   swt的一些簡單部件(widget)介紹

                   JFace的一些入門性介紹

                   swt和JFace的事件模式

                 通過一些簡單的例子說明如何利用swt和JFace編寫圖形化應用程序

           

          我還要說明一下你不能從本文中得到的信息,這些信息包括:

                   swt和JFace相關內容非常深入的介紹:正如你從題目中了解到的,本文的定位是“入門”,也就是說假定的讀者是那些對swt和JFace開發沒有什么了解的人。所以我并不打算進行一個深入的介紹。因為我相信在入門之后,他們能夠找到更好的資料(此外,我可能會寫另外一個系列文章來介紹)。

                   eclipse的使用:我假定你在讀這篇文章的時候已經對eclipse有所了解,所以不會解釋到具體eclipse如何使用。

                   eclipse插件開發:雖然eclipse插件開發和本文內容有著千絲萬縷的聯系,我決定還是不把它列為介紹的內容。這方面,你仍然可以找到相當多的資料供參考。

                 
          第一個SWT 程序
                  1。加入項目要包含的LIB
                  2。如果是在Windwos下面做開發,則還需要要一個org.eclipse.swt.win32_3.x.x.jar文件,這個文件要解壓縮,其中的幾個DLL文件要被JAVA 用JNI 調用,所以把DLL 文件的目錄加入到PATH 中。

                  代碼:     
          1package swtjfacesample;
           
          2
           3
          import org.eclipse.swt.SWT;
           4
          import org.eclipse.swt.widgets.Display;
           5
          import org.eclipse.swt.widgets.Shell;
           6
          import org.eclipse.swt.widgets.Text;
           
          7
           8
          public class HelloSwt {
           
          9    /**//**
          10     * Hello,world!
          11     * 
          12     * 
          @param args
          13     
          */

          14       public static void main(String[] args) {
          15        Display display = new Display();
          16        Shell shell = new Shell(display);
          17        
          18        Text helloText = new Text(shell, SWT.CENTER);
          19        helloText.setText("Hello,World!");
          20        helloText.pack();
          21        
          22        shell.pack();
          23        shell.open();
          24
          25        while (!shell.isDisposed()) {
          26            if (!display.readAndDispatch()) {
          27                display.sleep();
          28            }

          29        }

          30        display.dispose();
          31
          32    }

          33}

          34


          運行為SWT 應用程序,彈出一個小窗口,上面寫著Hello World!







          posted @ 2007-04-07 23:16 crazy zerlot 閱讀(234) | 評論 (0)編輯 收藏

          J2EE 架構師的SCEA認證(轉載)

            網絡上搜到的SCEA 的考試經驗,希望對大家有所幫助!

          正文:

          今天,2005年4月9號中午,我通過了Sun的系統架構師考試(SCEA)的310-051部分。總成績72%(很勉強,及格線68%)。面向對象概念、EJB、設計模式、消息、國際化等部分都對了80-100%;通用架構、遺留系統連接、EJB容器、協議、J2EE應用、安全等部分只有50-66%左右的正確率。
          但好歹整體是pass,否則又浪費銀子了——1250RMB實在太貴。就在昨晚,老公明白我今天就要考試,馬上表達了他的不滿:
          第一、 他認為我準備不夠,肯定pass不了,簡直是浪費銀子。
          第二、 他認為我那么早考過,就不會接著深入學習,很快會忘掉這些知識滴。

          但我今天早上還是在他極不看好的抱怨聲中去考試。第一道題就是又臭又長的遺留系統連接題,這些電腦屏幕上的英文馬上讓我的腦袋轟地暈了。所以接下來我一直是在極度緊張暈乎乎的情況下考試的。
          臭長的情景題目奇多,我以為時間不一定夠,心情緊張地完全影響了我做題效果。但我依然30分鐘左右把48個題目全部做了一遍。然后再用25分鐘左右仔細檢查了一遍,特別仔細研究那些臭長的題目,所有題目全部用排錯法選一次答案,但被重新選擇答案的題目不超過5個。剩下20分鐘左右時,又開始重新過一遍,但做到第34時,整個考試就over了,打印機就刷刷刷打印成績。我沒看到屏幕上的成績提示,很著急,馬上直接去看打印機吐出來的紙,直到看到成績是pass,才知道這1250塊是沒有浪費掉。
          從考場出來,恰好老公打電話來匯報他酒店的房間可看海景。我告訴他我過了,并埋怨自己備考方向不十分正確導致成績不算良好。他很意外我通過了沒有浪費錢;然后打斷我詳細的成績匯報,叫我不要太得意。

          其實,我覺得如果備考得當,是很可能拿到80%的。但現在根本沒有什么書能完全覆蓋了Sun的考試范圍,也沒有很update的guideline。通過這次實戰,我覺得我知道了Sun的真實考試范圍,因此覺得有必要整理出來,讓后來者少走彎路。
          我認為有三個資料是大家主要應該關注的。
          1.《J2EE學習指南-Sun   certified   enterprise   architect   for   J2EE   (Exam   310-051)(英文版)》,一定要讀英文版,因為考試是英文。Paul   R.Allen,Joseph   J.Bambara   人民郵電出版社。
          這本書粗看是覆蓋了SCEA全部大綱,但其實很多真正考試內容沒涉及,比如遺留系統連接、安全、集群、負載平衡。而遺留系統連接部分,最新的JCA并沒有考,考的還是Screen   Scraper及Corba等綜合技術連接各種復雜的遺留系統。其他內容,該書也寫的很羅索,不精煉。
          2.   《Sun   Certified   Enterprise   Architect   for   J2EE   Technology   Study   Guide》Prentice   Hall   著,作者是Sun的,該書接近于Sun的官方資料了。
          這本書很好,簡潔、扼要,非常適合最后沖刺階段使用。但缺點是完全沒有消息、遺留系統連接等內容。但是設計模式、協議、安全等部分相當好,至少比《J2EE學習指南》好。集群、負載平衡等部分,這本書一樣沒涉及。
          我自己翻譯了這本書的中文簡版,如果想對J2EE入個門,可以參考。但最好讀原文。連英文技術資料都看不懂的人,我想絕對通不過這個考試的,考試中的情景題都是很長的英文。《中文Sun的系統架構師認證教材》http://community.csdn.net/Expert/topic/3892/3892784.xml?temp=.1181452
          3.yahoo討論組上的資源,有最接近Sun考試范圍的資料和題目,是考80%的最好保證。
          scea_j2ee     http://groups.yahoo.com/group/scea_j2ee
          scea_prep     http://groups.yahoo.com/group/scea_prep
          特別推薦的是《Java   Architect   Notes   -   Balaji.doc》和《SCEA   Practice   Questions1.zip》及其他類似電子文檔。
          Balaji等人的筆記,更符合Sun實際考試的內容,比以上兩本書更貼近考試范圍。比如其中提到的集群、負載平衡、遺留系統連接等技術,今天我都被考到,而且我都沒考好。因為之前我一直以為出版的書更可能貼近考試,而我對上面兩本書的知識點都掌握到90%。但我接觸yahoo的資料很遲,對這些資料跟那兩本書的不同很懷疑,懷疑yahoo的資料不正確。但實際考試告訴我,yahoo的資料更正確。
          《SCEA   Practice   Questions1.zip》這些題目,多數跟Sun考試接近,特別是安全、遺留系統連接、集群、負載平衡等情景分析題,J2EE應用分析題等。但那些很detail的,接近編程的題目,可能不會考。而且這些題目的結果分析部分特別詳盡,非常有利于讓你處理J2EE選型等情景題目。
          尤其是其中部分題就基本重現在我今天的考試中,那些關于集群、負載平衡、J2EE應用分析的情景題。如果再考一次,我發誓我會把yahoo   group中的題目用心重做一遍。那樣我絕對可以拿到80%了。


          我覺得SCEA考試是一個覆蓋面很廣的東東。備考的過程中,絕對可以優化、充實自己的技術知識。比如通過這段時間的學習,我覺得我更了解J2EE及實際系統選型,也學會了設計模式。之前我基本是設計模式盲,現在我卻可以歷歷數出各模式的特點,甚至有更深入研究的興趣。我覺得備考SCEA是學習更多知識的方式,而考試結果只是附加的回報。

          備考時間和步驟建議:
          先介紹本人的背景和準備時間。
          本人具有多年J2EE工作經驗,很早學習OOA、J2EE,很早就深入學習、模擬過pet   store的framework。工作中的項目有很多practices及EJB   pattern,但這個很好的framework我沒參與設計。
          大概是去年(04年)11月初左右有了考SCEA的想法。然后買了上面提到的《J2EE學習指南》。在年前看完了這本書,同時就著《設計模式(中文版)》、《設計模式和Java》等書,對設計模式入了門。原來想年前考,但工作突然趨緊,加上要過年、寫網絡小說、看小說,就把考試計劃推遲到年后。
          過了年,又因為分心去“研究”宏微觀的經濟、管理及把手頭長編網絡小說over掉,也就不敢貿然考試。但工作輕松,所以還是花了很多時間學習SCEA。
          進入三月下旬(20號之后),我的SCEA沖刺階段開始了。反反復復看前面提到的兩本書和設計模式,終于把設計模式給吃下了。一直到三月底,才接觸到Balaji的《Java   Architect   Notes》,做yahoo上共享的題目。做題結果很慘,正確率只有50%左右。所以很快發現自己在情景題、安全等方面的不足,并力補之,同時花了2天半,把《Sun   Certified   Enterprise   Architect   for   J2EE   Technology   Study   Guide》翻譯了一下。
          到了4月2號,我決定報名9號考試。然后又把那2本書看一編,把《SCEA   Practice   Questions1.zip》等數百套題過一遍。6號交錢報名。7號下午通過作題,就發現自己不是很行。8號打印Sun的考試大綱,發現有些地方要加強。但最后認為安全、遺留系統連接、集群、負載平衡等比率不多,幻想Sun不會考那些DNS集群機制等題目,所以還是決定去考試(已經報名了,也不可能推遲)。可是9號考試的時候,心理很明白準備不充分,因此考試特別緊張。但謝天謝地,我面向對象概念、EJB、設計模式、消息、國際化等扎實的底子和yahoo資料給我的遺留系統連接、集群、負載平衡的粗淺印象,到底還是讓我pass了。

          要說明的是,我全部是工作時學習,根據工作強度,每天有0-7個小時學習。周末和晚上是不學習的。周末用來辦事、逛街、去公園;晚上用來上網。

          我覺得準備SCEA的時間因人而異。對于普通水平,如我,若集中學習,2-3個月夠了;對于更高水平,1個月甚至更短也行;對于水平更差,我想4-6個月都可能。

          最后要強調的是英語。這個考試有接近50%是臭長的情景題,還是多項選擇,如果基本英語要求都達不到的人,可能連正確理解題目都困難。而另外那些簡短的題目,偶爾也有一兩個不認識的關鍵的單詞,這絕對影響作題,因為那會讓你不知道整個句子的概念。我考試就遇到1-2個這樣的題目其中各有1個不認識的關鍵的單詞。我很懷疑通用架構、J2EE應用部分我得分過底就是因為這個原因。
          搞定英語,我覺得只能是基本只看英文資料和做英文題目。我的英語底子一般,也就四級水平,工作是純英文,近兩年除了小說、新聞看中文的,其他只看英文。但我的英語還是稍微影響了我的考試,至少我是這樣認為的。

          以上是我考后的感想。我覺得yahoo上的資料最符合sun考試范圍的;但那兩本書應該是主要的學習基礎。如果EJB不熟的人,其他一些EJB書籍都很必要。

          如果大家希望有個學習計劃的參考,我建議是:
          1.先學《J2EE學習指南》和其他的有名的EJB書籍(一本網上最著名、最流行的就行了)。這個時間應該1個月左右。
          2.再學習《Sun   Certified   Enterprise   Architect   for   J2EE   Technology   Study   Guide》。
          3.然后學習Balaji的筆記。
          4.打印Sun的考試大綱,逐條檢驗知識點。
          考試大綱   http://www.sun.com/training/catalog/courses/CX-310-051.xml
          5.做yahoo上的《SCEA   Practice   Questions1.zip》等題目。
          6.考試前2天,根據做題經驗,結合考試大綱,再逐一根據各知識點復習。
          7.考試時,也許第一個題目就是很長的英文題。不用被嚇著,穩定心態做下去。你會發現后面那些簡短的題目幾秒鐘就可以搞定一個。你肯定有時間回頭檢查的。

          310-051只是系統架構師的第一步,后面還有Assignment   (CX-310-300A)   、Essay   Exam   (CX-310-061)兩步。我不知道我什么時候會考,考試費太貴了(全程5000),最好能找個地方報銷。我更看中學習過程及實際掌握的知識,考試的結果,尤其是證書,天曉得有沒有用。但第一步應該是最難的一步,選擇題考過了,剩下兩步應該更容易。也許我會去考,如果考過了,如果有經驗,我一樣會來分享的。考慮到第一個1250花出去,我老公可能會催我考下去,他會覺得既然花錢了,那么搞個證書才合算。哈哈!

          posted @ 2007-04-07 04:29 crazy zerlot 閱讀(3955) | 評論 (13)編輯 收藏

          java字符集(轉自鍵者天行)

          1. 概述 

          本文主要包括以下幾個方面:編碼基本知識,java,系統軟件,url,工具軟件等。 

          在下面的描述中,將以"中文"兩個字為例,經查表可以知道其GB2312編碼是"d6d0 cec4",Unicode編碼為"4e2d 6587",UTF編碼就是"e4b8ad e69687"。注意,這兩個字沒有iso8859-1編碼,但可以用iso8859-1編碼來"表示"。 

          2. 編碼基本知識 

          最早的編碼是iso8859-1,和ascii編碼相似。但為了方便表示各種各樣的語言,逐漸出現了很多標準編碼,重要的有如下幾個。 

          2.1. iso8859-1 

          屬于單字節編碼,最多能表示的字符范圍是0-255,應用于英文系列。比如,字母'a'的編碼為0x61=97。 

          很明顯,iso8859-1編碼表示的字符范圍很窄,無法表示中文字符。但是,由于是單字節編碼,和計算機最基礎的表示單位一致,所以很多時候,仍舊使用iso8859-1編碼來表示。而且在很多協議上,默認使用該編碼。比如,雖然"中文"兩個字不存在iso8859-1編碼,以gb2312編碼為例,應該是"d6d0 cec4"兩個字符,使用iso8859-1編碼的時候則將它拆開為4個字節來表示:"d6 d0 ce c4"(事實上,在進行存儲的時候,也是以字節為單位處理的)。而如果是UTF編碼,則是6個字節"e4 b8 ad e6 96 87"。很明顯,這種表示方法還需要以另一種編碼為基礎。 

          2.2. GB2312/GBK 

          這就是漢子的國標碼,專門用來表示漢字,是雙字節編碼,而英文字母和iso8859-1一致(兼容iso8859-1編碼)。其中gbk編碼能夠用來同時表示繁體字和簡體字,而gb2312只能表示簡體字,gbk是兼容gb2312編碼的。 

          2.3. unicode 

          這是最統一的編碼,可以用來表示所有語言的字符,而且是定長雙字節(也有四字節的)編碼,包括英文字母在內。所以可以說它是不兼容iso8859-1編碼的,也不兼容任何編碼。不過,相對于iso8859-1編碼來說,uniocode編碼只是在前面增加了一個0字節,比如字母'a'為"00 61"。 

          需要說明的是,定長編碼便于計算機處理(注意GB2312/GBK不是定長編碼),而unicode又可以用來表示所有字符,所以在很多軟件內部是使用unicode編碼來處理的,比如java。 

          2.4. UTF 

          考慮到unicode編碼不兼容iso8859-1編碼,而且容易占用更多的空間:因為對于英文字母,unicode也需要兩個字節來表示。所以unicode不便于傳輸和存儲。因此而產生了utf編碼,utf編碼兼容iso8859-1編碼,同時也可以用來表示所有語言的字符,不過,utf編碼是不定長編碼,每一個字符的長度從1-6個字節不等。另外,utf編碼自帶簡單的校驗功能。一般來講,英文字母都是用一個字節表示,而漢字使用三個字節。 

          注意,雖然說utf是為了使用更少的空間而使用的,但那只是相對于unicode編碼來說,如果已經知道是漢字,則使用GB2312/GBK無疑是最節省的。不過另一方面,值得說明的是,雖然utf編碼對漢字使用3個字節,但即使對于漢字網頁,utf編碼也會比unicode編碼節省,因為網頁中包含了很多的英文字符。 

          3. java對字符的處理 

          在java應用軟件中,會有多處涉及到字符集編碼,有些地方需要進行正確的設置,有些地方需要進行一定程度的處理。 

          3.1. getBytes(charset) 

          這是java字符串處理的一個標準函數,其作用是將字符串所表示的字符按照charset編碼,并以字節方式表示。注意字符串在java內存中總是按unicode編碼存儲的。比如"中文",正常情況下(即沒有錯誤的時候)存儲為"4e2d 6587",如果charset為"gbk",則被編碼為"d6d0 cec4",然后返回字節"d6 d0 ce c4"。如果charset為"utf8"則最后是"e4 b8 ad e6 96 87"。如果是"iso8859-1",則由于無法編碼,最后返回 "3f 3f"(兩個問號)。 

          3.2. new String(charset) 

          這是java字符串處理的另一個標準函數,和上一個函數的作用相反,將字節數組按照charset編碼進行組合識別,最后轉換為unicode存儲。參考上述getBytes的例子,"gbk" 和"utf8"都可以得出正確的結果"4e2d 6587",但iso8859-1最后變成了"003f 003f"(兩個問號)。 

          因為utf8可以用來表示/編碼所有字符,所以new String( str.getBytes( "utf8" ), "utf8" ) === str,即完全可逆。 

          3.3. setCharacterEncoding() 

          該函數用來設置http請求或者相應的編碼。 

          對于request,是指提交內容的編碼,指定后可以通過getParameter()則直接獲得正確的字符串,如果不指定,則默認使用iso8859-1編碼,需要進一步處理。參見下述"表單輸入"。值得注意的是在執行setCharacterEncoding()之前,不能執行任何getParameter()。java doc上說明:This method must be called prior to reading request parameters or reading input using getReader()。而且,該指定只對POST方法有效,對GET方法無效。分析原因,應該是在執行第一個getParameter()的時候,java將會按照編碼分析所有的提交內容,而后續的getParameter()不再進行分析,所以setCharacterEncoding()無效。而對于GET方法提交表單是,提交的內容在URL中,一開始就已經按照編碼分析所有的提交內容,setCharacterEncoding()自然就無效。 

          對于response,則是指定輸出內容的編碼,同時,該設置會傳遞給瀏覽器,告訴瀏覽器輸出內容所采用的編碼。 

          3.4. 處理過程 

          下面分析兩個有代表性的例子,說明java對編碼有關問題的處理方法。 

          3.4.1. 表單輸入 

          User input  *(gbk:d6d0 cec4)  browser  *(gbk:d6d0 cec4)  web server  iso8859-1(00d6 00d 000ce 00c4)  class,需要在class中進行處理:getbytes("iso8859-1")為d6 d0 ce c4,new String("gbk")為d6d0 cec4,內存中以unicode編碼則為4e2d 6587。 

          l 用戶輸入的編碼方式和頁面指定的編碼有關,也和用戶的操作系統有關,所以是不確定的,上例以gbk為例。 

          l 從browser到web server,可以在表單中指定提交內容時使用的字符集,否則會使用頁面指定的編碼。而如果在url中直接用?的方式輸入參數,則其編碼往往是操作系統本身的編碼,因為這時和頁面無關。上述仍舊以gbk編碼為例。 

          l Web server接收到的是字節流,默認時(getParameter)會以iso8859-1編碼處理之,結果是不正確的,所以需要進行處理。但如果預先設置了編碼(通過request. setCharacterEncoding ()),則能夠直接獲取到正確的結果。 

          l 在頁面中指定編碼是個好習慣,否則可能失去控制,無法指定正確的編碼。 

          3.4.2. 文件編譯 

          假設文件是gbk編碼保存的,而編譯有兩種編碼選擇:gbk或者iso8859-1,前者是中文windows的默認編碼,后者是linux的默認編碼,當然也可以在編譯時指定編碼。 

          Jsp  *(gbk:d6d0 cec4)  java file  *(gbk:d6d0 cec4)  compiler read  uincode(gbk: 4e2d 6587; iso8859-1: 00d6 00d 000ce 00c4)  compiler write  utf(gbk: e4b8ad e69687; iso8859-1: *)  compiled file  unicode(gbk: 4e2d 6587; iso8859-1: 00d6 00d 000ce 00c4)  class。所以用gbk編碼保存,而用iso8859-1編譯的結果是不正確的。 

          class  unicode(4e2d 6587)  system.out / jsp.out  gbk(d6d0 cec4)  os console / browser。 

          l 文件可以以多種編碼方式保存,中文windows下,默認為ansi/gbk。 

          l 編譯器讀取文件時,需要得到文件的編碼,如果未指定,則使用系統默認編碼。一般class文件,是以系統默認編碼保存的,所以編譯不會出問題,但對于jsp文件,如果在中文windows下編輯保存,而部署在英文linux下運行/編譯,則會出現問題。所以需要在jsp文件中用pageEncoding指定編碼。 

          l Java編譯的時候會轉換成統一的unicode編碼處理,最后保存的時候再轉換為utf編碼。 

          l 當系統輸出字符的時候,會按指定編碼輸出,對于中文windows下,System.out將使用gbk編碼,而對于response(瀏覽器),則使用jsp文件頭指定的contentType,或者可以直接為response指定編碼。同時,會告訴browser網頁的編碼。如果未指定,則會使用iso8859-1編碼。對于中文,應該為browser指定輸出字符串的編碼。 

          l browser顯示網頁的時候,首先使用response中指定的編碼(jsp文件頭指定的contentType最終也反映在response上),如果未指定,則會使用網頁中meta項指定中的contentType。 

          3.5. 幾處設置 

          對于web應用程序,和編碼有關的設置或者函數如下。 

          3.5.1. jsp編譯 

          指定文件的存儲編碼,很明顯,該設置應該置于文件的開頭。例如:<%@page pageEncoding="GBK"%>。另外,對于一般class文件,可以在編譯的時候指定編碼。 

          3.5.2. jsp輸出 

          指定文件輸出到browser是使用的編碼,該設置也應該置于文件的開頭。例如:<%@ page contentType="text/html; charset= GBK" %>。該設置和response.setCharacterEncoding("GBK")等效。 

          3.5.3. meta設置 

          指定網頁使用的編碼,該設置對靜態網頁尤其有作用。因為靜態網頁無法采用jsp的設置,而且也無法執行response.setCharacterEncoding()。例如:<META http-equiv="Content-Type" content="text/html; charset=GBK" /> 

          如果同時采用了jsp輸出和meta設置兩種編碼指定方式,則jsp指定的優先。因為jsp指定的直接體現在response中。 

          需要注意的是,apache有一個設置可以給無編碼指定的網頁指定編碼,該指定等同于jsp的編碼指定方式,所以會覆蓋靜態網頁中的meta指定。所以有人建議關閉該設置。 

          3.5.4. form設置 

          當瀏覽器提交表單的時候,可以指定相應的編碼。例如:<form accept-charset= "gb2312">。一般不必不使用該設置,瀏覽器會直接使用網頁的編碼。 

          4. 系統軟件 

          下面討論幾個相關的系統軟件。 

          4.1. mysql數據庫 

          很明顯,要支持多語言,應該將數據庫的編碼設置成utf或者unicode,而utf更適合與存儲。但是,如果中文數據中包含的英文字母很少,其實unicode更為適合。 

          數據庫的編碼可以通過mysql的配置文件設置,例如default-character-set=utf8。還可以在數據庫鏈接URL中設置,例如: useUnicode=true&characterEncoding=UTF-8。注意這兩者應該保持一致,在新的sql版本里,在數據庫鏈接URL里可以不進行設置,但也不能是錯誤的設置。 

          4.2. apache 

          appache和編碼有關的配置在httpd.conf中,例如AddDefaultCharset UTF-8。如前所述,該功能會將所有靜態頁面的編碼設置為UTF-8,最好關閉該功能。 

          另外,apache還有單獨的模塊來處理網頁響應頭,其中也可能對編碼進行設置。 

          4.3. linux默認編碼 

          這里所說的linux默認編碼,是指運行時的環境變量。兩個重要的環境變量是LC_ALL和LANG,默認編碼會影響到java URLEncode的行為,下面有描述。 

          建議都設置為"zh_CN.UTF-8"。 

          4.4. 其它 

          為了支持中文文件名,linux在加載磁盤時應該指定字符集,例如:mount /dev/hda5 /mnt/hda5/ -t ntfs -o iocharset=gb2312。 

          另外,如前所述,使用GET方法提交的信息不支持request.setCharacterEncoding(),但可以通過tomcat的配置文件指定字符集,在tomcat的server.xml文件中,形如:<Connector ... URIEncoding="GBK"/>。這種方法將統一設置所有請求,而不能針對具體頁面進行設置,也不一定和browser使用的編碼相同,所以有時候并不是所期望的。 

          5. URL地址 

          URL地址中含有中文字符是很麻煩的,前面描述過使用GET方法提交表單的情況,使用GET方法時,參數就是包含在URL中。 

          5.1. URL編碼 

          對于URL中的一些特殊字符,瀏覽器會自動進行編碼。這些字符除了"/?&"等外,還包括unicode字符,比如漢子。這時的編碼比較特殊。 

          IE有一個選項"總是使用UTF-8發送URL",當該選項有效時,IE將會對特殊字符進行UTF-8編碼,同時進行URL編碼。如果改選項無效,則使用默認編碼"GBK",并且不進行URL編碼。但是,對于URL后面的參數,則總是不進行編碼,相當于UTF-8選項無效。比如"中文.html?a=中文",當UTF-8選項有效時,將發送鏈接"%e4%b8%ad%e6%96%87.html?a=\x4e\x2d\x65\x87";而UTF-8選項無效時,將發送鏈接"\x4e\x2d\x65\x87.html?a=\x4e\x2d\x65\x87"。注意后者前面的"中文"兩個字只有4個字節,而前者卻有18個字節,這主要時URL編碼的原因。 

          當web server(tomcat)接收到該鏈接時,將會進行URL解碼,即去掉"%",同時按照ISO8859-1編碼(上面已經描述,可以使用URLEncoding來設置成其它編碼)識別。上述例子的結果分別是"\ue4\ub8\uad\ue6\u96\u87.html?a=\u4e\u2d\u65\u87"和"\u4e\u2d\u65\u87.html?a=\u4e\u2d\u65\u87",注意前者前面的"中文"兩個字恢復成了6個字符。這里用"\u",表示是unicode。 

          所以,由于客戶端設置的不同,相同的鏈接,在服務器上得到了不同結果。這個問題不少人都遇到,卻沒有很好的解決辦法。所以有的網站會建議用戶嘗試關閉UTF-8選項。不過,下面會描述一個更好的處理辦法。 

          5.2. rewrite 

          熟悉的人都知道,apache有一個功能強大的rewrite模塊,這里不描述其功能。需要說明的是該模塊會自動將URL解碼(去除%),即完成上述web server(tomcat)的部分功能。有相關文檔介紹說可以使用[NE]參數來關閉該功能,但我試驗并未成功,可能是因為版本(我使用的是apache 2.0.54)問題。另外,當參數中含有"?& "等符號的時候,該功能將導致系統得不到正常結果。 

          rewrite本身似乎完全是采用字節處理的方式,而不考慮字符串的編碼,所以不會帶來編碼問題。 

          5.3. URLEncode.encode() 

          這是Java本身提供對的URL編碼函數,完成的工作和上述UTF-8選項有效時瀏覽器所做的工作相似。值得說明的是,java已經不贊成不指定編碼來使用該方法(deprecated)。應該在使用的時候增加編碼指定。 

          當不指定編碼的時候,該方法使用系統默認編碼,這會導致軟件運行結果得不確定。比如對于"中文",當系統默認編碼為"gb2312"時,結果是"%4e%2d%65%87",而默認編碼為"UTF-8",結果卻是"%e4%b8%ad%e6%96%87",后續程序將難以處理。另外,這兒說的系統默認編碼是由運行tomcat時的環境變量LC_ALL和LANG等決定的,曾經出現過tomcat重啟后就出現亂碼的問題,最后才郁悶的發現是因為修改修改了這兩個環境變量。 

          建議統一指定為"UTF-8"編碼,可能需要修改相應的程序。 

          5.4. 一個解決方案 

          上面說起過,因為瀏覽器設置的不同,對于同一個鏈接,web server收到的是不同內容,而軟件系統有無法知道這中間的區別,所以這一協議目前還存在缺陷。 

          針對具體問題,不應該僥幸認為所有客戶的IE設置都是UTF-8有效的,也不應該粗暴的建議用戶修改IE設置,要知道,用戶不可能去記住每一個web server的設置。所以,接下來的解決辦法就只能是讓自己的程序多一點智能:根據內容來分析編碼是否UTF-8。 

          比較幸運的是UTF-8編碼相當有規律,所以可以通過分析傳輸過來的鏈接內容,來判斷是否是正確的UTF-8字符,如果是,則以UTF-8處理之,如果不是,則使用客戶默認編碼(比如"GBK"),下面是一個判斷是否UTF-8的例子,如果你了解相應規律,就容易理解。 

          public static boolean isValidUtf8(byte[] b,int aMaxCount){ 

                 int lLen=b.length,lCharCount=0; 

                 for(int i=0;i<lLen && lCharCount<aMaxCount;++lCharCount){ 

                        byte lByte=b[i++];//to fast operation, ++ now, ready for the following for(;;) 

                        if(lByte>=0) continue;//>=0 is normal ascii 

                        if(lByte<(byte)0xc0 || lByte>(byte)0xfd) return false; 

                        int lCount=lByte>(byte)0xfc?5:lByte>(byte)0xf8?4 

                               :lByte>(byte)0xf0?3:lByte>(byte)0xe0?2:1; 

                        if(i+lCount>lLen) return false; 

                        for(int j=0;j<lCount;++j,++i) if(b[i]>=(byte)0xc0) return false; 

                 } 

                 return true; 



          相應地,一個使用上述方法的例子如下: 

          public static String getUrlParam(String aStr,String aDefaultCharset) 

          throws UnsupportedEncodingException{ 

                 if(aStr==null) return null; 

                 byte[] lBytes=aStr.getBytes("ISO-8859-1"); 

                 return new String(lBytes,StringUtil.isValidUtf8(lBytes)?"utf8":aDefaultCharset); 



          不過,該方法也存在缺陷,如下兩方面: 

          l 沒有包括對用戶默認編碼的識別,這可以根據請求信息的語言來判斷,但不一定正確,因為我們有時候也會輸入一些韓文,或者其他文字。 

          l 可能會錯誤判斷UTF-8字符,一個例子是"學習"兩個字,其GBK編碼是" \xd1\xa7\xcf\xb0",如果使用上述isValidUtf8方法判斷,將返回true。可以考慮使用更嚴格的判斷方法,不過估計效果不大。 

          有一個例子可以證明google也遇到了上述問題,而且也采用了和上述相似的處理方法,比如,如果在地址欄中輸入"http://www.google.com/search?hl=zh-CN&newwindow=1&q=學習",google將無法正確識別,而其他漢字一般能夠正常識別。 

          最后,應該補充說明一下,如果不使用rewrite規則,或者通過表單提交數據,其實并不一定會遇到上述問題,因為這時可以在提交數據時指定希望的編碼。另外,中文文件名確實會帶來問題,應該謹慎使用。 

          6. 其它 

          下面描述一些和編碼有關的其他問題。 

          6.1. SecureCRT 

          除了瀏覽器和控制臺與編碼有關外,一些客戶端也很有關系。比如在使用SecureCRT連接linux時,應該讓SecureCRT的顯示編碼(不同的session,可以有不同的編碼設置)和linux的編碼環境變量保持一致。否則看到的一些幫助信息,就可能是亂碼。 

          另外,mysql有自己的編碼設置,也應該保持和SecureCRT的顯示編碼一致。否則通過SecureCRT執行sql語句的時候,可能無法處理中文字符,查詢結果也會出現亂碼。 

          對于Utf-8文件,很多編輯器(比如記事本)會在文件開頭增加三個不可見的標志字節,如果作為mysql的輸入文件,則必須要去掉這三個字符。(用linux的vi保存可以去掉這三個字符)。一個有趣的現象是,在中文windows下,創建一個新txt文件,用記事本打開,輸入"連通"兩個字,保存,再打開,你會發現兩個字沒了,只留下一個小黑點。 

          6.2. 過濾器 

          如果需要統一設置編碼,則通過filter進行設置是個不錯的選擇。在filter class中,可以統一為需要的請求或者回應設置編碼。參加上述setCharacterEncoding()。這個類apache已經給出了可以直接使用的例子SetCharacterEncodingFilter。 

          6.3. POST和GET 

          很明顯,以POST提交信息時,URL有更好的可讀性,而且可以方便的使用setCharacterEncoding()來處理字符集問題。但GET方法形成的URL能夠更容易表達網頁的實際內容,也能夠用于收藏。 

          從統一的角度考慮問題,建議采用GET方法,這要求在程序中獲得參數是進行特殊處理,而無法使用setCharacterEncoding()的便利,如果不考慮rewrite,就不存在IE的UTF-8問題,可以考慮通過設置URIEncoding來方便獲取URL中的參數。 

          6.4. 簡繁體編碼轉換 

          GBK同時包含簡體和繁體編碼,也就是說同一個字,由于編碼不同,在GBK編碼下屬于兩個字。有時候,為了正確取得完整的結果,應該將繁體和簡體進行統一。可以考慮將UTF、GBK中的所有繁體字,轉換為相應的簡體字,BIG5編碼的數據,也應該轉化成相應的簡體字。當然,仍舊以UTF編碼存儲。 

          例如,對于"語言 ?言",用UTF表示為"\xE8\xAF\xAD\xE8\xA8\x80 \xE8\xAA\x9E\xE8\xA8\x80",進行簡繁體編碼轉換后應該是兩個相同的 "\xE8\xAF\xAD\xE8\xA8\x80>"。 

           

          Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1145171

          posted @ 2007-04-03 23:33 crazy zerlot 閱讀(465) | 評論 (2)編輯 收藏

          僅列出標題
          共3頁: 上一頁 1 2 3 
          主站蜘蛛池模板: 金寨县| 德庆县| 阳新县| 平凉市| 大余县| 寿阳县| 台中县| 抚顺市| 罗平县| 贵州省| 诸城市| 蓬溪县| 都安| 临城县| 甘南县| 邵武市| 松江区| 宁波市| 桐庐县| 吕梁市| 高邑县| 乌拉特后旗| 四平市| 中超| 台中县| 许昌市| 兰西县| 肃南| 新乡县| 东港市| 射洪县| 手机| 定南县| 年辖:市辖区| 监利县| 武鸣县| 环江| 元氏县| 广平县| 平和县| 丰都县|