小閣飛空 一池碧映垂楊路 絳云深處 聽盡瀟瀟雨
          At times , people will simply not come through for you in the way you need.Forgive them and move on.
          posts - 212,comments - 87,trackbacks - 0

          盡管關(guān)于Java中文問題的討論已經(jīng)相當(dāng)多了,但由于Java的相關(guān)技術(shù)標(biāo)準(zhǔn)繁多,面向Java的Web服務(wù)器、應(yīng)用服務(wù)器以及JDBC數(shù)據(jù)庫(kù)驅(qū)動(dòng)等都沒有官方的標(biāo)準(zhǔn),所以Java應(yīng)用在處理中文時(shí)所存在的問題不僅沒有消失而且隨著所選用的服務(wù)器、驅(qū)動(dòng)程序以及運(yùn)行環(huán)境等因素的不同而變化。那么我們?nèi)绾螐谋姸喱F(xiàn)象中找出問題所在,并進(jìn)行分析和解決呢?與大部分的討論不同,本文將主要從如何預(yù)測(cè)、發(fā)現(xiàn)和檢查問題的角度給出建議,幫助開發(fā)人員找出可能引起問題的各種源頭,從而更好地解決Java的中文問題。

            引言

            盡管對(duì)于Java中文處理問題的討論已不乏其數(shù),但由于Java技術(shù)涉及內(nèi)容廣(J2EE包含了十幾種相關(guān)技術(shù)),技術(shù)供應(yīng)商繁多,面向Java的Web服務(wù)器、應(yīng)用服務(wù)器以及JDBC數(shù)據(jù)庫(kù)驅(qū)動(dòng)等都沒有官方的標(biāo)準(zhǔn),所以Java應(yīng)用在處理中文過程中出了存在固有的問題外也存在隨著選用的服務(wù)器,驅(qū)動(dòng)程序的不同而帶來(lái)的Java中文問題的多變性,增加了問題的復(fù)雜度。那么,我們?nèi)绾卧谶@么紛繁的現(xiàn)象中找到問題的癥結(jié)呢?

            Java中文問題的一般解決辦法

            事實(shí)上,Java的中文問題都是由于Java應(yīng)用所采用的缺省編碼格式與目標(biāo)或者應(yīng)用所要讀入字符的編碼格式不同而造成的(具體參見文獻(xiàn)1)。對(duì)于如何解決Java的中文問題,通常有四種方法:

            1)選擇JDK的中文本地化版本。盡管Java2 JDK的中文本地化版本(http://java.sun.com/products/jdk/1.2/chinesejdk.html)并不是一個(gè)官方的版本,Sun公司也沒有承諾會(huì)對(duì)該本地化版本進(jìn)行升級(jí),但其仍不失為一個(gè)Java中文問題的解決方案。

            2)選擇合適的編譯參數(shù)。對(duì)于Java的國(guó)際版本來(lái)講,我們也可以在編譯Java應(yīng)用的時(shí)候通過指定確定的編碼機(jī)制來(lái)實(shí)現(xiàn)其編譯結(jié)果對(duì)中文的支持。例如,對(duì)于需要支持繁體中文和簡(jiǎn)體中文應(yīng)用可以通過javac -encoding big5 sourcefile.java 和javac -encoding gb2312 sourcefile.java來(lái)編譯源程序。

            3)通過編程的方式實(shí)現(xiàn)字符編碼的轉(zhuǎn)換代碼。通過編程的方式來(lái)解決Java的中文問題,已經(jīng)成為了一種較為普遍的做法。下面就是一種最常見的字符編碼轉(zhuǎn)換函數(shù),其將字符的編碼格式轉(zhuǎn)換為中文Windows系統(tǒng)的GBK編碼形式。

          public static String toChinese(String strvalue)
             {
                   try{
                       if(strvalue==null)
                          return null;
                       else
                       {
                          strvalue = new String(strvalue.getBytes("ISO8859_1"), "GBK");
                          return strvalue;
                   }
                   }catch(Exception e){
                         return null;
                   }
             }

            4)定義字符輸出集。對(duì)于JSP應(yīng)用,我們可以通過<%@ page contentType="text/html; charset=GBK" %>或<%@ page contentType="text/html; charset=GB2312" %>來(lái)定義JSP頁(yè)面的字符輸出集。當(dāng)然,我們也可以通過HTML的標(biāo)記<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=gb2312">來(lái)定義字符的輸出集。

            存在的問題

            根據(jù)方法實(shí)現(xiàn)的方式,我們可以將以上四種方法分為兩類,一類是通過利用某些標(biāo)準(zhǔn)或者規(guī)則來(lái)實(shí)現(xiàn)的方法,上面的1)、2)、4)都屬于此類;一類是通過針對(duì)性的編程來(lái)實(shí)現(xiàn)的方法,上面所提的方法3)就屬于此類。

            由于方法1),2),4)是具有規(guī)范性的一類方法,所以方法比較簡(jiǎn)單,解決方案也不具備較大的針對(duì)性,較為通用,例如我們可以采用方法2)的編譯方式通過編譯Java源文件來(lái)實(shí)現(xiàn)內(nèi)碼的預(yù)置,而無(wú)需考慮源碼到底有哪些部分出現(xiàn)了Java的中文處理問題,諸如輸出亂碼等等。

            但是,正由于這些方法不具備針對(duì)性,解決問題的方法過于統(tǒng)一,所以在某些情況下,它們并不能徹底地解決Java的中文問題。舉一個(gè)非常常見的例子。在通常情況下,用戶的Java應(yīng)用往往需要與其它Java應(yīng)用接口進(jìn)行交互,例如通過某種版本的JDBC訪問數(shù)據(jù)庫(kù)。由于JDBC的驅(qū)動(dòng)所支持的編碼隨著提供商乃至版本的不同而不同,所以如果在數(shù)據(jù)庫(kù)的輸入輸出過程中出現(xiàn)中文不能正確處理問題時(shí),我們需要在數(shù)據(jù)的輸入和輸出過程做兩次正好相反的編碼轉(zhuǎn)換,這對(duì)于方法1),2),4)來(lái)說,往往是無(wú)法解決的。當(dāng)然,對(duì)于方法2,我們也可以通過采用一些技巧使來(lái)滿足上面的情況,一個(gè)最有效的辦法就是盡量將Java應(yīng)用的各個(gè)部分組件化。例如我們可以通過將數(shù)據(jù)庫(kù)的讀入和輸出代碼分解在不同的源文件上來(lái)實(shí)現(xiàn)分別編譯,從而滿足不同的字符編碼要求。但是通常的程序設(shè)計(jì)都不太可能滿足這種要求,因?yàn)檫@種程序的劃分結(jié)果很可能是不合理的。例如,我們將數(shù)據(jù)庫(kù)的讀出和寫入方法封裝到一個(gè)類中是比較合適的一種設(shè)計(jì),但如果將該類的這兩個(gè)方法分別實(shí)現(xiàn)在兩個(gè)文件里則變得非常不合理。因此對(duì)于1),2),4)方法來(lái)說,雖然實(shí)現(xiàn)比較簡(jiǎn)單,但卻具有一些無(wú)法克服的缺點(diǎn)。這也是那些實(shí)現(xiàn)起來(lái)相對(duì)復(fù)雜的編程方法得以流行的原因。

            相對(duì)于方法1),2),4)來(lái)說,方法3)具有更好的針對(duì)性和靈活性。程序可以根據(jù)不同的情況做出靈活的處理,在任何需要的地方進(jìn)行字符的編碼轉(zhuǎn)換,但是該方法的特點(diǎn)也對(duì)軟件的開發(fā)人員提出了更高要求--必須能夠準(zhǔn)確的捕捉到有可能發(fā)生中文處理問題的地方,并做出正確的判斷和處理。

            分析的原則

            總的說來(lái),所有解決Java中文處理的方法都不是很復(fù)雜。相反的是,由于Java技術(shù)特別是J2EE技術(shù)涉及的內(nèi)容繁多,各種Web服務(wù)器、應(yīng)用服務(wù)器以及JDBC數(shù)據(jù)庫(kù)驅(qū)動(dòng)等參差不齊,所以如何正確而及時(shí)的發(fā)現(xiàn)應(yīng)用的中文處理問題則變得相對(duì)復(fù)雜的多。那么我們?nèi)绾蝸?lái)發(fā)現(xiàn)這些問題呢?

            通常,Java處理中文時(shí)所產(chǎn)生的問題都是由于用戶的Java應(yīng)用所采用的缺省編碼格式與目標(biāo)或者應(yīng)用所要讀入字符的編碼格式不同而造成的,而引起這些不同的一個(gè)主要原因就是用戶的Java應(yīng)用與其它應(yīng)用進(jìn)行了編碼格式不匹配的數(shù)據(jù)交換(包括直接或間接的數(shù)據(jù)輸入、輸出)。所以,為了及時(shí)發(fā)現(xiàn)問題,我們可以由這一點(diǎn)入手,根據(jù)以下的原則對(duì)應(yīng)用進(jìn)行分析:

            1. 注意字符變量情況。由于變量的字符編碼形式較為隱蔽,多次變量間數(shù)值的改變和運(yùn)算可能會(huì)引起字符集的改變;在變量與頁(yè)面所提交數(shù)據(jù)的各種操作中,較容易發(fā)生不同編碼格式字符進(jìn)行運(yùn)算的情況。

            2. 注意任何形式的字符讀入與輸出。之所以要提到任何形式,是因?yàn)镴ava應(yīng)用大多數(shù)都是作為網(wǎng)絡(luò)應(yīng)用開發(fā)的,所以與其它語(yǔ)言的應(yīng)用相比,Java應(yīng)用需要面對(duì)網(wǎng)絡(luò)世界各種各樣的字符數(shù)據(jù)交換形式。例如各種表單的數(shù)據(jù)提交,URL形式的數(shù)據(jù)讀入,經(jīng)過加密運(yùn)算的字符數(shù)據(jù)交換,網(wǎng)頁(yè)控件選擇結(jié)果的輸入,控件內(nèi)容的的顯示(如List控件)等等。

            3. 小心使用第三方的組件和應(yīng)用。由于第三方組件和應(yīng)用的實(shí)現(xiàn)是非透明的,所以一般情況下,我們很難判斷這些組件或驅(qū)動(dòng)的缺省編碼格式是什么,也無(wú)法對(duì)其進(jìn)行控制。因此,在使用它們所提供的接口函數(shù)進(jìn)行數(shù)據(jù)交換的時(shí)候要特別注意,如果確實(shí)出現(xiàn)中文無(wú)法正確處理情況,應(yīng)首先檢查我們自己的代碼并調(diào)整相關(guān)代碼以適應(yīng)這些接口,因?yàn)檫@些組件或者應(yīng)用基本上不會(huì)提供調(diào)整編碼機(jī)制的接口。必要時(shí),我們可能需要采用其它可替換的組件或者應(yīng)用。

            4. 注意被請(qǐng)求對(duì)象所含有的數(shù)據(jù)輸入與輸出。這是非常隱蔽的一類情況,當(dāng)我們的應(yīng)用以對(duì)象的方式(例如序列化的對(duì)象)進(jìn)行交互時(shí),如果這個(gè)對(duì)象內(nèi)部含有字符數(shù)據(jù)的處理過程,或者含有某些數(shù)據(jù)的輸入、輸出,甚至是拋出一段用中文注解的異常,都可能出現(xiàn)中文無(wú)法正確顯示等問題。由于這些行為往往被封裝在對(duì)象中,所以我們?cè)诰帉懗绦驎r(shí),很容易忽略這種可能情況。并且這種情況帶有一定的不可預(yù)見性,例如我們可能不清楚這個(gè)對(duì)象會(huì)在什么時(shí)候拋出什么樣的異常,所以這時(shí)我們就需要做一定的測(cè)試工作。

            5. 注意數(shù)據(jù)庫(kù)的數(shù)據(jù)訪問過程。Java通過JDBC與數(shù)據(jù)庫(kù)建立連接。對(duì)于JDBC驅(qū)動(dòng)程序來(lái)說,由于目前大部分的JDBC驅(qū)動(dòng)程序并不是針對(duì)中文系統(tǒng)而設(shè)計(jì)的(中文數(shù)據(jù)大都采用ISO-8859-1編碼方式),所以一般情況下在數(shù)據(jù)讀寫過程中往往都需要字符編碼的轉(zhuǎn)化。但是我們?nèi)越ㄗh用戶在使用這些JDBC驅(qū)動(dòng)時(shí),仔細(xì)閱讀它的說明。如果確實(shí)無(wú)法弄清JDBC字符數(shù)據(jù)的編碼到底是什么,我們的建議是做一些必要的測(cè)試。例如下面是一組在簡(jiǎn)體中文Win2000平臺(tái)下,采用Weblogic 6.0所提供的JDBC驅(qū)動(dòng)從MS SQL Server2000中正確讀入中文字符的代碼(例子中進(jìn)行了字符運(yùn)算):

           ...
          Class.forName("weblogic.jdbc.mssqlserver4.Driver").newInstance();
             conn = myDriver.connect("jdbc:weblogic:mssqlserver4", props);
                conn.setCatalog("labmanager");
               Statement st = conn.createStatement();
            //execute a query
           String  testStr;
          String testTempStr = new String() ;
               testStr = new String(testTempStr.getBytes("ISO-8859-1"));//編碼轉(zhuǎn)化
           DatabaseMetaData DBMetaData =conn.getMetaData();
            ResultSet rs = DBMetaData.getTables(null, null,null,new String[]{"TABLE"} );
            while (rs.next()){
             for(int j=1; j<=rs.getMetaData().getColumnCount(); j++){
          testStr = testStr +String(rs.getObject(j).toString().getBytes("ISO-8859-1"));
             }
            }

            然而,需要注意的是,不同的JDBC驅(qū)動(dòng)對(duì)相同的數(shù)據(jù)庫(kù)的支持并不同,而同一類JDBC驅(qū)動(dòng)對(duì)不同的數(shù)據(jù)庫(kù)的支持也不相同,也就是說我們的字符轉(zhuǎn)化代碼在JDBC驅(qū)動(dòng)改變甚至是版本變化情況下都有可能無(wú)法正確工作。例如對(duì)于上面的例子,在同樣的環(huán)境下改用i-net 的Una 2000 Driver Version 2.03 for MS SQL Server時(shí),是無(wú)法正確處理中文的。原因很簡(jiǎn)單,這個(gè)JDBC驅(qū)動(dòng)本身支持的就是GBK的編碼機(jī)制,所以根本就不需要做任何的編碼轉(zhuǎn)化。

            6. 必要的測(cè)試。由于Java中文問題的產(chǎn)生隨著Web服務(wù)器,瀏覽器,運(yùn)行環(huán)境和開發(fā)工具的不同都可能發(fā)生變化,所以為了更好的避免問題的發(fā)生,我們必須作一些針對(duì)性的測(cè)試。另外,在我們確實(shí)無(wú)法通過分析來(lái)確定Java的中文處理問題是否可能發(fā)生的情況下或者無(wú)法知道問題的發(fā)生是由于哪個(gè)環(huán)節(jié)(是Web服務(wù)器,瀏覽器還是JDBC數(shù)據(jù)驅(qū)動(dòng)等等)引起的時(shí)候,測(cè)試工作則變得非常重要。并且我們可能需要較為全面的測(cè)試,例如對(duì)Web服務(wù)器,瀏覽器和JDBC數(shù)據(jù)驅(qū)動(dòng)等都要做測(cè)試,這樣有利于我們找出那些隱藏在多個(gè)環(huán)節(jié)協(xié)調(diào)過程中所產(chǎn)生的問題。

            結(jié)論

            事實(shí)上,Java中文處理之所以存在問題,其根本原因是由于被操作的中文字符(變量)的編碼格式與目標(biāo)的編碼格式不同造成的,所有這些問題其實(shí)都是發(fā)生在字符的讀入、輸出過程中的,只要我們把握住這一環(huán)節(jié),就可以更好的發(fā)現(xiàn)、分析、處理和預(yù)防Java的中文問題了。

          posted on 2005-11-15 15:26 瀟瀟雨 閱讀(201) 評(píng)論(0)  編輯  收藏 所屬分類: JAVA 、JSP
          主站蜘蛛池模板: 余庆县| 乌兰浩特市| 来宾市| 临桂县| 浦东新区| 莱州市| 咸阳市| 楚雄市| 崇义县| 肥乡县| 瑞昌市| 黄平县| 开鲁县| 上高县| 许昌县| 怀化市| 乐业县| 聂拉木县| 平邑县| 湾仔区| 灵石县| 石台县| 四子王旗| 黄陵县| 普宁市| 公主岭市| 英超| 金华市| 秀山| 汝城县| 南开区| 汉中市| 辽阳市| 丹巴县| 睢宁县| 高密市| 唐河县| 留坝县| 绥德县| 紫阳县| 尼玛县|