1. 程式人生 > >【Java】中文亂碼不再亂

【Java】中文亂碼不再亂

     小編總結了一下一些中文亂碼的心得,總結一下積累。(最近更新2017年5月9日)

【為什麼】

      在頁面上輸入資訊,通過表單等打包提交成request請求發給伺服器,jsp在執行時總是被編譯成servlet,這期間也會有字元的編譯,最終將資料插入資料庫中,資料庫的字符集等等,這期間的各種字元編碼的轉換傳輸等等都會造成亂碼。一個J2EE系統的各個組成部分都有各自的字符集編碼,如果不做字符集統一,必然會出現亂碼。

【解決方案】

       UTF-8無疑是最好的統一選擇,UTF-8編碼相容所有語言(具體的編碼比較見文尾),唯一比較麻煩的就是需要在資料從輸入到進資料庫這一系列操作的所有出入管你口都用UTF-8來統一。如下:

1.需要在專案開發和編譯時指定字符集UTF-8。Eclipse就直接設定整個專案的屬性即可。如下圖:


2.在JSP的頭部進行宣告:

<%@ pagelanguage="java"contentType="text/html;charset=UTF-8"pageEncoding="UTF-8"%>

3.也可以使用過濾器,所有請求都要經過servlet控制分配器,在servlet的filter設定統一。

       詳見部落格:http://blog.csdn.net/u013036274/article/details/52592818

4.設定資料庫連線方式為UTF-8。以mysql連線為例,在連線mysql配置url時:

<?xmlversion="1.0" encoding="UTF-8"?>
<config>
<db-info>
<driver-name>com.mysql.jdbc.Driver</driver-name>       
<url>jdbc:mysql://localhost:3306/drp?characterEncoding=UTF-8</url>
<user-name>root</user-name>
<password>123456</password>
</db-info>
</config>

5.資料庫設定為UTF-8,如下圖:


6.JSP與頁面引數之間的亂碼轉換

Request.setCharacterEncoding("UTF-8");//從請求中獲取引數出現亂碼
response.setContentType("text/html;charset=GBK");//將變數輸出到頁面時出現亂碼

    這種情況綜合起來還是直接使用過濾器比較合適。

7.Filter設定字符集對get提交方式並不起作用,所以還有一種方式,是配置伺服器。一Tomcat為例:Tomcat的配置檔案中:.me_tcat/conf/server.xml,如下圖:


開啟進行如下修改:


8.對中文采用Java.net.URLEncoder.encode()進行編碼

 URLEncoder.encode("某中文", "GB18030")

9.其他 

       上面提到的方法應該能解決大部分亂碼問題,如果在其他地方還出現亂碼,可能需要手動修改程式碼。

String test=newString(name.getBytes("gbk"),"utf-8");

10.瀏覽器中文亂碼

      最近小編做專案遇到了這樣一個問題:通過上文的方法,可以保證谷歌、火狐等瀏覽器都沒問題,但是IE卻依然亂碼,這是因為IE和火狐對URL的處理不同,瀏覽器在傳輸URI時得對URL進行編碼,IE預設是以UTF_8來傳輸的,Firefox是GBK來編碼,如果不對中文引數進行處理,中文字元經過各個瀏覽器以各自的方式傳輸到伺服器後就出現了各種編碼方式,而伺服器卻只能以一種編碼方式來對接收到得URL進行解碼,這樣的話和伺服器使用的編碼方式一致的瀏覽器在傳中文引數時沒問題,不一致的就會有問題。解決方法也很簡單,上文介紹中少了一個地方,就是在引數傳遞之前。我們可以再引數傳遞之前就進行編碼,後臺獲取引數時再解碼即可,並且這種方式可以很好的處理瀏覽器相容性問題,這樣的話下面的那一段補充液沒用了,因為我們根本就不需要知道原來是什麼編碼。如下:

js程式碼:

	var url =encodeURI("transport/viewTransitList.do?searchOption="
			+ searchOption + "&searchCondition="
			+ searchCondition);

Controller程式碼:

		String searchCondition=request.getParameter("searchCondition");
		try {			
			 searchCondition = java.net.URLDecoder.decode(searchCondition, "UTF-8");// 解碼
			searchCondition = new String(searchCondition.getBytes("iso-8859-1"), "utf-8");
		
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}	

補充:解決Java亂碼問題的關鍵在於在位元組與字元的轉換過程中,你必須知道原來位元組或轉換後的位元組的編碼方式,轉換時採用的編碼必須與這個編碼方式保持一致。但是如何獲取字串的編碼格式,實驗了幾個網上的方案,無果。待續。。。。

【幾種編碼格式的介紹】----(摘自部落格見文尾連結)

       當中國人們得到計算機時,已經沒有可以利用的位元組狀態來表示漢字,況且有6000多個常用漢字需要儲存,於是想到把那些ASCII碼中127號之後的奇異符號們直接取消掉,規定:一個小於127的字元的意義與原來相同,但兩個大於127的字元連在一起時,就表示一個漢字,前面的一個位元組(稱之為高位元組)從0xA1用到0xF7,後面一個位元組(低位元組)從0xA1到0xFE,這樣我們就可以組合出大約7000多個簡體漢字了。在這些編碼裡,我們還把數學符號、羅馬希臘的字母、日文的假名們都編進去了,連在ASCII 裡本來就有的數字、標點、字母都統統重新編了兩個位元組長的編碼,這就是常說的"全形"字元,而原來在127號以下的那些就叫"半形"字元了。這種漢字方案叫做"GB2312"。GB2312 是對 ASCII 的中文擴充套件。相容ASCII。

       但是中國的漢字太多了,我們很快就就發現有許多人的人名沒有辦法在這裡打出來,不得不繼續把GB2312沒有用到的碼位找出來用上。後來還是不夠用,於是乾脆不再要求低位元組一定是127號之後的內碼,只要第一個位元組是大於127就固定表示這是一個漢字的開始,不管後面跟的是不是擴充套件字符集裡的內容。結果擴充套件之後的編碼方案被稱為“GBK” 標準,GBK 包括了 GB2312 的所有內容,同時又增加了近20000個新的漢字(包括繁體字)和符號。

       後來少數民族也要用電腦了,於是我們再擴充套件,又加了幾千個新的少數民族的字,GBK擴成了 GB18030。從此之後,中華民族的文化就可以在計算機時代中傳承了。

       中國的程式設計師們看到這一系列漢字編碼的標準是好的,於是通稱他們叫做"DBCS"(Double ByteCharecter Set雙位元組字符集)。在DBCS系列標準裡,最大的特點是兩位元組長的漢字字元和一位元組長的英文字元並存於同一套編碼方案裡,因此他們寫的程式為了支援中文處理,必須要注意字串裡的每一個位元組的值,如果這個值是大於127的,那麼就認為一個雙位元組字符集裡的字元出現了。在這種情況下,"一個漢字算兩個英文字元!"。然而,在Unicode環境下卻並非總是如此。

       在Unicode裡,所有的字元被一視同仁。漢字不再使用“兩個擴充套件ASCII”,而是使用“1個Unicode”,注意,現在的漢字是“一個字元”了,於是,拆字、統計字數這些問題也就自然而然的解決了。

       但是,這個世界不是理想的,不可能在一夜之間所有的系統都使用Unicode來處理字元,所以Unicode在誕生之日,就必須考慮一個嚴峻的問題:和ASCII字符集之間的不相容問題。

       我們知道,ASCII字元是單個位元組的,比如“A”的ASCII是65。而Unicode是雙位元組的,比如“A”的Unicode是0065,這就造成了一個非常大的問題:以前處理ASCII的那套機制不能被用來處理Unicode了。

       另一個更加嚴重的問題是,C語言使用'\0'作為字串結尾,而Unicode裡恰恰有很多字元都有一個位元組為0,這樣一來,C語言的字串函式將無法正常處理Unicode,除非把世界上所有用C寫的程式以及他們所用的函式庫全部換掉。

       於是,比Unicode更偉大的東東誕生了,之所以說它更偉大是因為它讓Unicode不再存在於紙上,而是真實的存在於我們大家的電腦中。那就是:UTF。

       UTF= UCS TransformationFormat,即UCS轉換(傳輸)格式。它是將Unicode編碼規則和計算機的實際編碼對應起來的一個規則。現在流行的UTF有2種:UTF-8和UTF-16。這兩種都是Unicode的編碼實現。

下面兩篇部落格對這方面介紹的生動風趣,有興趣可以看一下。

http://blog.csdn.net/guanfengliang1988/article/details/50440197

http://blog.csdn.net/ldanduo/article/details/8203532/