優(yōu)秀是一種習慣

           

          Java基礎——孫鑫談Java中文亂碼問題產(chǎn)生原因分析(二)

          聲明:本文轉(zhuǎn)載自:http://www.mybole.com.cn/article/815.html

          在輸出字符和字符串的時候,會從Unicode編碼向中文系統(tǒng)默認的編碼GBK轉(zhuǎn)換,由于Unicode編碼0xfffdGBK字符集中沒有對應的編碼,于是得到0x3f,輸出字符“?”。最后輸出的結果如下:

          fffd--?

          40--@

          554a--

          從上述所知,由于存在著多種不同的字符集,在各種字符集之間進行轉(zhuǎn)換,就有可能出現(xiàn)亂碼,同樣是中文字符集GB2312GBK,由于編碼范圍的不同,某些字符在轉(zhuǎn)換時也會出現(xiàn)亂碼。

          在一個使用了數(shù)據(jù)庫的Web應用程序中,亂碼可能會在多個環(huán)節(jié)產(chǎn)生。由于瀏覽器會根據(jù)本地系統(tǒng)默認的字符集來提交數(shù)據(jù),而Web容器默認采用的是ISO-8859-1的編碼方式解析POST數(shù)據(jù),在瀏覽器提交中文數(shù)據(jù)后,Web容器會按照ISO-8859-1字符集來解碼數(shù)據(jù),在這一環(huán)節(jié)可能會導致亂碼的產(chǎn)生。由于大多數(shù)數(shù)據(jù)庫的JDBC驅(qū)動程序默認采用ISO-8859-1的編碼方式在Java程序和數(shù)據(jù)庫之間傳遞數(shù)據(jù),我們的程序在向數(shù)據(jù)庫中存儲包含中文的數(shù)據(jù)時,JDBC驅(qū)動首先將程序內(nèi)部的Unicode編碼格式的數(shù)據(jù)轉(zhuǎn)化為ISO-8859-1的格式,然后傳遞到數(shù)據(jù)庫中,在這一環(huán)節(jié)可能會導致亂碼的產(chǎn)生。目前流行的關系型數(shù)據(jù)庫系統(tǒng)都支持數(shù)據(jù)庫編碼,也就是說在創(chuàng)建數(shù)據(jù)庫時可以指定它自己的字符集設置,數(shù)據(jù)庫的數(shù)據(jù)以指定的編碼形式存儲。當JDBC驅(qū)動向數(shù)據(jù)庫中保存數(shù)據(jù)時,有可能還會發(fā)生字符集的轉(zhuǎn)換。正是由于在Web應用程序運行過程中,輸入的中文字符需要在不同的字符集之間來回轉(zhuǎn)換,也就導致了中文亂碼問題的頻繁出現(xiàn)。

          17-1  描述了在Web應用的請求響應過程中,發(fā)生的字符編碼轉(zhuǎn)換過程,其中瀏覽器是IE 6.0Web容器的是Tomcat 6.0.16

          從圖17-1 描述的過程中可以看到,如果在Web應用程序中不指定任何的字符集,從瀏覽器端傳來的中文字符,輸出回瀏覽器時,可以正常顯示(以簡體中文的方式查看網(wǎng)頁)。然而,事情并沒有這么簡單,在Servlet/JSP中,可能存在著直接寫入的或從其他來源讀取的中文字符,如果這些字符對應的Unicode碼是從GB2312編碼轉(zhuǎn)換而來,那么以ISO-8859-1編碼方式輸出,這些字符將不能正常顯示。所以對于中文的處理,應該在圖17-1②和⑤的位置明確指定使用GB2312GBK字符集。

           17-1 Web請求響應過程中,中文字符編碼的轉(zhuǎn)換過程

          java中文亂碼問題的解決方案

          只要掌握了中文亂碼問題產(chǎn)生的原因,然后對癥下藥,就可以順利地解決這些問題。下面我們對容易產(chǎn)生亂碼問題的場景進行分析,并提出解決方案。

          1.以POST方法提交的表單數(shù)據(jù)中有中文字符

          由于Web容器默認的編碼方式是ISO-8859-1,在Servlet/JSP程序中,通過請求對象的getParameter()方法得到的字符串是以ISO-8859-1轉(zhuǎn)換而來,這是導致亂碼產(chǎn)生的原因之一。為了避免容器以ISO-8859-1的編碼方式返回字符串,對于以POST方法提交的表單數(shù)據(jù),可以在獲取請求參數(shù)值之前,調(diào)用request.setCharacterEncoding"GBK"),明確指定請求正文使用的字符編碼方式是GBK。在向瀏覽器發(fā)送中文數(shù)據(jù)之前,調(diào)用response.setContentType"text/html;charset=GBK"),指定輸出內(nèi)容的編碼方式是GBK

          對于JSP頁面,在獲取請求參數(shù)值之前,寫上下面的代碼:

          <%request.setCharacterEncoding("GB2312");%>

          為了指定輸出內(nèi)容的編碼格式,設置page指令contentType屬性,如下:

          <%@ page contentType="text/html; charset=GBK" %>

          Web容器轉(zhuǎn)換JSP頁面后的Servlet類中,會自動添加下面的代碼:

          response.setContentType("text/html; charset=GBK");

          2.以GET方法提交的表單數(shù)據(jù)中有中文字符

          當提交表單采用GET方法時,提交的數(shù)據(jù)作為查詢字符串被附加到URL的末端,發(fā)送到服務器,此時在服務器端調(diào)用setCharacterEncoding()方法也就沒有作用了。我們需要在得到請求參數(shù)的值后,自己做正確的編碼轉(zhuǎn)換。

          String name = request.getParameter("name");

          name=new String(name.getBytes("ISO-8859-1"),"GBK");

          在第一行,調(diào)用getParameter()方法得到的字符串nameUnicode值是以ISO-8859-1編碼轉(zhuǎn)換而來,調(diào)用name.getBytes"ISO-8859-1"),將得到原始的GBK編碼值,接著,對new String()的調(diào)用將以GBK字符集重新構造字符串的Unicode編碼。

          為了方便從ISO-8859-1編碼到GBK的轉(zhuǎn)換,我們可以編寫一個工具方法,如下:

          public String toGBK(String str)

                           throws java.io.UnsupportedEncodingException

          {

              return new String(str.getBytes("ISO-8859-1"),"GBK");

          }

          3.在數(shù)據(jù)庫中存儲和讀取中文數(shù)據(jù)

          對于大多數(shù)數(shù)據(jù)庫的JDBC驅(qū)動程序,在Java程序和數(shù)據(jù)庫之間傳遞數(shù)據(jù)都是以ISO-8859-1為默認編碼格式,所以,我們在程序中向數(shù)據(jù)庫存儲包含中文的數(shù)據(jù)時,JDBC驅(qū)動程序首先把程序內(nèi)部的Unicode編碼格式的數(shù)據(jù)轉(zhuǎn)化為ISO-8859-1編碼,然后傳遞到數(shù)據(jù)庫中,加上數(shù)據(jù)庫本身也有字符集,這就是為什么我們常常在數(shù)據(jù)庫中讀取中文數(shù)據(jù)時,讀到的是亂碼。

          要解決上述問題,只需要將數(shù)據(jù)庫默認的編碼格式改為GBKGB2312即可,不同的數(shù)據(jù)庫還提供了另外的方式來處理字符編碼轉(zhuǎn)換的問題,讀者在實際應用過程中,可針對具體情況再做具體處理,只要理解了編碼轉(zhuǎn)換的過程,就能找到問題的所在,進而解決問題。4Servlet/JSP在不同語言系統(tǒng)的平臺下運行

          有時候,我們在中文系統(tǒng)平臺下開發(fā)的Web應用程序移植到英文系統(tǒng)平臺下,在ServletJSP中直接書寫的中文字符串在輸出時,將顯示為亂碼。這是因為在編譯Servlet類或者JSP文件時,如果沒有使用-encoding參數(shù)指定Java源程序的編碼格式,javac會獲取本地操作系統(tǒng)默認采用的字符集,以該字符集將Java源程序轉(zhuǎn)換為Unicode編碼保存到內(nèi)存中,然后將源程序編譯為字節(jié)碼文件(字節(jié)碼文件采用的是UTF-8編碼),保存到硬盤上。

          在英文平臺下,采用的默認編碼格式是ISO-8859-1,所以在編譯轉(zhuǎn)換后,執(zhí)行輸出時,原先在源文件中書寫的中文字符串就變成了亂碼。

          要解決這個問題,在編譯Servlet的源程序時,可以用-encoding參數(shù)指定編碼為GBKGB2312,例如:

          javac –encoding GBK HelloServlet.java

          對于JSP頁面,只要在page指令中用contentType屬性或pageEncoding屬性指定編碼格式為GBKGB2312Web容器就可以正確轉(zhuǎn)換和編譯JSP文件了。例如:

          <%@ page contentType="text/html; charset=GBK" %>

          <%@ page pageEncoding="GBK" %>

          在實際的Web應用中,亂碼問題產(chǎn)生的原因多種多樣,然而只要我們理解了字符編碼的轉(zhuǎn)換過程,仔細地分析亂碼產(chǎn)生的原因,找到問題的關鍵,就能對癥下藥,解決問題。

          posted on 2009-08-12 09:55 黃土高坡 閱讀(370) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導航:
           

          導航

          統(tǒng)計

          常用鏈接

          留言簿

          隨筆分類

          隨筆檔案

          收藏夾

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 梁山县| 交口县| 阿克| 潮州市| 常山县| 奎屯市| 丰都县| 若尔盖县| 如东县| 龙州县| 巫山县| 兴海县| 称多县| 通海县| 淳化县| 玉林市| 东方市| 内乡县| 乡宁县| 前郭尔| 巴彦淖尔市| 南岸区| 黄山市| 乌审旗| 琼中| 普兰县| 宣恩县| 罗山县| 根河市| 泸西县| 吴江市| 百色市| 肃宁县| 通城县| 榆林市| 锡林浩特市| 黔西县| 唐河县| 弥渡县| 娱乐| 洞头县|