關於java字符編碼的理解

字符是各種文字和符號的總稱,包括各個國家文字、標點符號、圖形符號、數字等。字符集是多個字符的集合,字符集種類較多,每個字符集包含的字符個數不同,常見字符集有:ASCII字符集、ISO 8859字符集、GB2312字符集、BIG5字符集、GB18030字符集、Unicode字符集等。計算機要準確的處理各種字符集文字,需要進行字符編碼,以便計算機能夠識別和存儲各種文字。如Unicode字符集可依不同需要以UTF-8、UTF-16、UTF-32等方式編碼。

編碼和字符集不同。字符集只是字符的集合,不一定適合作網絡傳送、處理,有時須經編碼後才能應用。對於一個字符集來說要正確編碼轉碼一個字符需要三個關鍵元素:字庫表、編碼字符集、字符編碼。字庫表是一個相當於所有可讀或者可顯示字符的數據庫,字庫表決定了整個字符集能夠展現表示的所有字符的範圍。編碼字符集,即用一個編碼值來表示一個字符在字庫中的位置。字符編碼,將編碼字符集和實際存儲數值之間的轉換關係。

 

正確使用字符串的getBytes方法

         java提供了將String轉化爲byte[]的幾種方法,具體說明如下:

        

         不帶參數的方法使用平臺的默認字符集,另外兩個方法都是按照指定字符集獲取字節數組,window下默認的字符集是GBK,驗證方式如下:

         進入cmd --> 點擊標題欄右鍵 --> 屬性 --> 選項 --> 當前代碼頁

         

         Linux下,輸入:echo $LANG進行驗證(默認是UTF-8)

        

         當調用無參getBytes()方法時,實際上先獲取默認字符集Charset.defaultCharset(),然後根據該字符集進行獲取字節數組;爲了實現更加靈活的控制,java引入了file.encoding屬性,JVM啓動之前如果未指定file.encoding這個屬性,這個屬性就會默認爲操作系統編碼方式, JVM啓動如果指定了file.encoding這個屬性,整個項目都會用這個屬性(file.encoding在運行時設置無效)。

 

         下面使用一個簡單的測試例子來說明

                  

        

        

         通過上面的瞭解,無參的getBytes方法會存在很多不確定性,會與預期的不一致,所以不要使用缺省的方法,應當根據約定的編碼方式進行轉換處理。

        

java的URL編碼和解碼

        

javascript的URL編碼和解碼

         encodeURI()

         ecodeURI()

Javascript中真正用來對URL編碼的函數。對整個URL進行編碼,因此除了常見的符號以外,對其他一些在網址中有特殊含義的符號「; / ? : @ & = + $ , #」,也不進行編碼。編碼後,它輸出符號的UTF-8形式,並且在每個字節前加上%

         encodeURIComponent()

         decodeURIComponent()

它用於對URL的組成部分進行個別編碼,而不用於對整個URL進行編碼。在encodeURI()中不被編碼的符號,在encodeURIComponent()中統統會被編碼。至於具體的編碼方法,兩者是一樣

         在web應用中,經常會出現亂碼問題,本質上是由於編碼不一致導致,下面對Form表單的POST提交方式進行分析

         

         爲了避免出現亂碼,需要保存編碼一致

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

         String nameA = new String(nameB.getBytes("編碼B"),"編碼A");//還原爲發送請求真實的編碼

         1、文檔編碼(網頁右鍵 --> 編碼)

           

         決定文檔編碼主要來自文件的描述

         JSP:<%@ page language="java" contentType="text/html; charset=GBK" pageEncoding="GBK"%>

    HTML:<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

   

    JSP示例(GBK編碼):

                   name對應的值「立思辰」進行了雙字節轉碼(GBK)%C1%A2%CB%BC%B3%BD

                  

    HTML示例(UTF-8編碼):

                   name對應的值「立思辰」進行了三字節轉碼(UTF-8)%E7%AB%8B%E6%80%9D%E8%BE%B0

                 

         2、服務器解碼

            tomcat中,如果未指定character encoding ,則默認使用ISO-8859-1 

            上述JSP 表單提交時,通過從ISO-8859-1GBK轉換即可

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

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

                  

                   上述HTML 表單提交時,通過從ISO-8859-1UTF-8轉換即可

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

        String nameUTF8 = new String(nameISO.getBytes("ISO-8859-1"),"UTF-8");

       

                   在實際應用中,爲了避免每次獲取參數都進行轉碼,有以下幾種方式

                   A、在每個servlet/JSP中設置request.setCharacterEncoding(String charEncoding)

            JSP示例(GBK編碼):

                                     request.setCharacterEncoding("GBK");

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

            HTML示例(UTF-8編碼):

                                     request.setCharacterEncoding("UTF-8");

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

           

        B、設置統一的過濾器設置request.setCharacterEncoding(String charEncoding)

                      通過過濾器統一設置字符編碼(不需要在每個文件中進行設置)

                           

                            Servlet中只要直接獲取參數值String nameGBK = request.getParameter("name");

這種方式,也是目前比較流行的處理方式,項目使用約定好的字符編碼,前後保持一致,對於特殊的servlet/jsp 可以在開始位置進行重置request.setCharacterEncoding

                  

         form表單的提交get方式

        

        

         地址欄效果,等價與在瀏覽器地址欄輸入地址訪問,對應的值按照GBK進行編碼

        

         第一個語句打印亂碼,第二個能正常顯示

 

 

         ajax提交

        

         相應的servlet自動按照UTF-8進行解析

         

         當第一次執行request.getParameter() 進行參數解析,優先解析Url參數,再解析body部分

         決定body解析編碼的依次是:

         1、是否設置request.setCharacterEncoding()

         2、是否設置header 中Content-type 對應的charset

         3、以上都沒設置,默認ISO-8859-1

         決定url解析編碼:

         1、server.xml 設置URIEncoding

                  

                   這樣對於上面模擬的form get提交方式就能正常獲取參數值

         2、server.xml 設置useBodyEncodingForURI="true"

                  

                   這種方式需要在調用前進行設置request.setCharacterEncoding()

         3、server.xml 設置URIEncoding和useBodyEncodingForURI

                  

設置useBodyEncodingForURI爲true時,如果未進行setCharacterEncoding則使用URIEncoding對應的編碼進行解析,若設置了CharacterEncoding,這按照設定的字符編碼值進行解析

         4、上述都未設置,則使用默認編碼(ISO-8859-1)進行解析

 

         在前後交互時需要避免UTF8和GBK之間的相互轉碼

         前臺:

                 

         後臺:

                 

         輸出:

                  

         引起這種現象的本質原因在於兩個字符集特點所引發的,一個漢字UTF-8是3個字節,GBK則是2個字節。