String odsStr = "測(cè)試"; String newStr = new String(odsStr.getBytes("GBK"), "ISO8859_1"); 首先需要說(shuō)明一下我們經(jīng)常用到的字符集,,有ISO8859-1,,GB2312,GBK,,GB18030,,UNICODE。這里ISO8859-1字符集只 包含英文字符,,使用一個(gè)字節(jié)存儲(chǔ),。GB2312、GBK和GB18030字符集包含中文字符,,他們都兼容ISO8859-1字符集,,他們的字符存儲(chǔ)格式是變長(zhǎng)的,其中GB18030包含GBK,,GBK包含GB2312,。UNICODE包含世界上所有國(guó)家的字符,UNICODE又分為UTF-8,,UTF-16和UTF-32三種,,UTF-8是變長(zhǎng)字符集,,它兼容ISO8859-1,即英文字符使用一個(gè)字節(jié)編碼,,而其他的字符使用2到4個(gè)字節(jié)編碼,,其中中文字符大部分都是使用3個(gè)字節(jié)進(jìn)行編碼,少量偏僻字使用4個(gè)字節(jié)編碼,,UTF-16統(tǒng)一都使用2個(gè)字節(jié)編碼,,它不兼容ISO8859-1,英文字符也使用兩個(gè)字節(jié),,UTF-32統(tǒng)一使用4個(gè)字節(jié)編碼,,也不兼容ISO8859-1,可見(jiàn)UTF-16和UTF-32都比較浪費(fèi)空間,。 亂碼問(wèn)題的產(chǎn)生最根本的原因就是使用錯(cuò)誤的字符集解碼字節(jié)流或者將給定的字符串用錯(cuò)誤的字符集編碼成錯(cuò)誤字節(jié)流造成的,,例如”中文”兩個(gè)漢字,如果用ISO8859-1字符集將其編碼為字節(jié)流,,因?yàn)檫@個(gè)字符集不支持中文,,所以就會(huì)出錯(cuò),輸出結(jié)果為3f3f,,其意義就是??,。再例如”中文”二字的GBK的字節(jié)流為d6 d0 ce c4,可是我們要是用不兼容的字符集去解碼,,例如用ISO8859-1或者UTF-8,,這隨后產(chǎn)生的字符串就是亂碼,或者是其他的某個(gè)字符,。 從開(kāi)發(fā)Java程序到運(yùn)行Java程序的過(guò)程中都存在著編碼問(wèn)題,,所以要想避免亂碼產(chǎn)生,就必須了解在其中任何時(shí)候的編碼處理的情況,。 源代碼:在編寫java源代碼的時(shí)候,,我們必須把編寫的文本保存在文件中,這個(gè)時(shí)候不管用什么編輯器,,都存在一個(gè)問(wèn)題,,就是以什么樣的字符集將這些源代碼(包含漢字)保存到文件中,大部分編輯器都會(huì)通過(guò)系統(tǒng)的環(huán)境變量得到系統(tǒng)的當(dāng)前默認(rèn)字符集,,編輯器就會(huì)使用這個(gè)字符集將我們編寫的源代碼保存到文件中,。一般我們的中文Windows系統(tǒng)的默認(rèn)字符集是GB18030,,AIX英文環(huán)境的默認(rèn)字符集是ISO8859-1,,AIX中文環(huán)境的默認(rèn)字符集是IBM-eucCN,。 編譯:在編譯.java文件的時(shí)候如果使用默認(rèn)處理,,則javac會(huì)使用系統(tǒng)當(dāng)前的默認(rèn)字符集去讀取源文件,將源文件的內(nèi)容轉(zhuǎn)換為UTF-8編碼,,然后在進(jìn)行編譯,,這時(shí)我們也可以通過(guò)-encoding參數(shù)指定一個(gè)字符集,,讓javac使用我們指定的字符集去讀取源代碼然后在轉(zhuǎn)換為UTF-8,然后編譯,。編譯以后產(chǎn)生的class文件內(nèi)部所有的中文字符都是用UTF-8的字符集進(jìn)行編碼的,,這就是Java程序能處理任何國(guó)家文字的原因。 運(yùn)行時(shí):Java程序在運(yùn)行時(shí),,需要使用程序內(nèi)部定義的中文字符串,,也可能會(huì)使用從外部讀取的中文字符串,這些經(jīng)過(guò)處理,,可能都會(huì)輸出到程序外部,,在這些 過(guò)程中都涉及到編碼的轉(zhuǎn)換,程序內(nèi)部定義的字符串都是用UTF-8存儲(chǔ)的,。而從外部讀取和輸出到程序外部的輸出又使用什么字符集進(jìn)行處理呢?在我們沒(méi)有在 程序中特別指定的情況下,,JVM會(huì)根據(jù)系統(tǒng)屬性確定使用哪個(gè)字符集,,這個(gè)系統(tǒng)屬性的名稱為file.encoding,我們可以在啟動(dòng)java程序的時(shí)候通過(guò)-D參數(shù)設(shè)定這個(gè)值,,如果沒(méi)有設(shè)定,,JVM會(huì)根據(jù)系統(tǒng)環(huán)境變量確定這個(gè)系統(tǒng)屬性,一般我們的中文Windows系統(tǒng)的默認(rèn)字符集是GB18030,,AIX英文環(huán)境的默認(rèn)字符集是ISO8859-1,,AIX中文環(huán)境的默認(rèn)字符集是IBM-eucCN。這樣JVM在處理輸入數(shù)據(jù)的時(shí)候就會(huì)把字節(jié)流根據(jù)這個(gè)參數(shù)進(jìn)行解碼,,然后轉(zhuǎn)成UTF-8格式,,在Java程序內(nèi)部處理,然后再根據(jù)這個(gè)參數(shù)把處理后的數(shù)據(jù)編碼,,輸出到程序外部,。這就是Java程序運(yùn)行時(shí)字符集的使用情況。 現(xiàn)在有一個(gè)問(wèn)題,,我們平時(shí)都是Windows的中文環(huán)境下做開(kāi)發(fā),,然后拿到AIX系統(tǒng)上去運(yùn)行,AIX系統(tǒng)的默認(rèn)語(yǔ)言環(huán)境是英文環(huán)境,,這樣就會(huì)出現(xiàn)亂碼,,分析過(guò)程如下:源文件編碼格式為GB18030,默認(rèn)編譯,,也采用GB18030讀取源文件,,正常轉(zhuǎn)換為UTF-8,生成class文件,,運(yùn)行時(shí)沒(méi)有進(jìn)行特殊設(shè)置,,語(yǔ)言環(huán)境為英文環(huán)境,,默認(rèn)編碼為ISO8859-1,這樣在輸出中文的時(shí)候會(huì)把正常的UTF-8表示的漢字用ISO8859-1的字符集去編碼生成字節(jié)流,,因?yàn)镮SO8859-1不支持漢字,,結(jié)果輸出的都是’?’,??墒沁@個(gè)時(shí)候卻發(fā)現(xiàn),由外界輸入給java程序的中文字符,,卻能正常輸出,,這又是為什么,其實(shí)這個(gè)也是運(yùn)行時(shí)的默認(rèn)字符集ISO8859-1造成的,,Java程序運(yùn)行時(shí),,在讀取外部進(jìn)入的字節(jié)流的時(shí)候,如果使用默認(rèn)的讀取方式,,也是使用ISO8859-1的字符集進(jìn)行解碼處理,,這樣中間的處理過(guò)程中,中文都已經(jīng)不是原來(lái)的中文了,,也就是說(shuō)我們這個(gè)時(shí)候處理根本不是我們認(rèn)為的中文,,而是一對(duì)亂碼,雖然是亂碼,,但是其中的信息卻沒(méi)有丟失,,在處理完后,在經(jīng)過(guò)一次ISO8859-1的編碼,,又還原為正常的GB18030的編碼輸出,,所有沒(méi)有出現(xiàn)亂碼。我們以前的解決方法是,,在編譯原文件的時(shí)候指定參數(shù)-encoding ISO8859-1,,讓編譯器用ISO8859-1的字符集去解碼源文件編譯,然后運(yùn)行程序,,這時(shí)再輸出程序的內(nèi)部中文字符串也不是亂碼了,。看起來(lái)一切都解決了,,可是卻沒(méi)有從根本上解決問(wèn)題,,class文件變得比平常大很多,程序中用到中文越多,,class文件變大的越快,。而且其中的中文信息也變味了。 另一個(gè)問(wèn)題,,如果我們正常編譯程序,,在AIX系統(tǒng)上線設(shè)定為中文環(huán)境,,然后再運(yùn)行Java程序,這樣既不會(huì)使程序變大,,也不會(huì)使中文變味,,可是用了一段時(shí)間又發(fā)現(xiàn)問(wèn)題了,處理過(guò)程中如果遇到偏僻的中文字,,還是亂碼,,原因是AIX的中文環(huán)境使用的字符集是IBM-eucCN,我認(rèn)為可能是這個(gè)字符集缺少偏僻漢字,,無(wú)法解釋其內(nèi)容,,所以偏僻字變成了亂碼了。 最后的解決辦法是,,在Windows中文環(huán)境下正常編寫原程序,,用默認(rèn)的方式編譯生成class文件,或者編譯時(shí)指定參數(shù)-encoding GB18030,,這樣漢字都能正常解釋并轉(zhuǎn)換為UTF-8存儲(chǔ)在class文件中,,在運(yùn)行的時(shí)候,我們需要制定參數(shù),,java –Dfile.encoding=GB18030 。,。,。。,。,,系統(tǒng)環(huán)境使用默認(rèn)英文即可,這樣JVM就不會(huì)根據(jù)系統(tǒng)的環(huán)境設(shè)定默認(rèn)字符集,,而是所有輸入輸出都使用我們指定的字符集,,這樣不但解決了英文環(huán)境下的中文輸出問(wèn)題,而且還解決了偏僻字的顯示問(wèn)題,。 最后附上漢字的轉(zhuǎn)碼過(guò)程: 1.‘中文’的GB18030編碼為d6 d0 ce c4 對(duì)應(yīng)java源碼文件 經(jīng)過(guò)ISO8859-1解碼為UTF-8為81 30 89 30 81 30 88 34 81 30 88 32 81 30 87 32 對(duì)應(yīng)編譯過(guò)程 經(jīng)過(guò)ISO8859-1編碼為d6 d0 ce c4 對(duì)應(yīng)Java程序輸出漢字的過(guò)程 d6 d0 ce c4經(jīng)GB18030解釋為‘中文’二字 對(duì)應(yīng)系統(tǒng)顯示漢字的過(guò)程,。 在這個(gè)過(guò)程中,雖然中間出現(xiàn)了亂碼,,但是信息沒(méi)有丟,,最后還是能還原為中文的,是比較蹩腳的處理過(guò)程,。 2. ‘中文’二字的UTF-8編碼為e4 b8 ad e6 96 87,,對(duì)應(yīng)正常編譯后的class文件存儲(chǔ)內(nèi)容 經(jīng)過(guò)ISO8859-1編碼為3f 3f,已經(jīng)出錯(cuò),,丟失信息,,對(duì)應(yīng)java程序漢字輸出過(guò)程 3f 3f經(jīng)GB18030解釋為漢字為,??,,亂碼,,無(wú)法還原, 對(duì)應(yīng)系統(tǒng)顯示漢字的過(guò)程 這個(gè)過(guò)程中,信息丟失,,是個(gè)完全錯(cuò)誤的處理過(guò)程,。 3. ‘中文’的GB18030編碼為d6 d0 ce c4 對(duì)應(yīng)java源碼文件 經(jīng)過(guò)GB18030解碼為UTF-8為e4 b8 ad e6 96 87 對(duì)應(yīng)編譯過(guò)程 經(jīng)過(guò)GB18030編碼為d6 d0 ce c4 對(duì)應(yīng)Java程序輸出漢字的過(guò)長(zhǎng) d6 d0 ce c4經(jīng)GB18030解釋為‘中文’二字 對(duì)應(yīng)系統(tǒng)顯示漢字的過(guò)程。 這個(gè)過(guò)程是最為理想的處理過(guò)程,,沒(méi)有丟失信息,,也沒(méi)有出現(xiàn)任何蹩腳的信息。 java亂碼的根本原因就是:java可以設(shè)置字符編碼的地方太多,,只要有不統(tǒng)一的地方就有出現(xiàn)亂碼,。 ---------------------------------------------------------------------------------------------------------------------------------- *************************************java、jsp中設(shè)置編碼******************************************/ 首先說(shuō)在java里那些地方能夠設(shè)置編碼 開(kāi)發(fā)工具會(huì)有好多地方設(shè)置編碼這個(gè)不解少了,,這里不介紹了,。 下面兩種設(shè)置編碼格式方法適用于jsp頁(yè)面(*.jsp) <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ page contentType="text/html; charset=UTF-8" %> 下面方式適合于jsp、servlet,、action中(*.java) request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); 下面適合html頁(yè)面(*.htm;*.html) Tomcate設(shè)置編碼(server.xml) mysql設(shè)置編碼命令 SET character_set_client = utf8; SET character_set_connection = utf8; SET character_set_database = utf8; SET character_set_results = utf8;/*這里要注意很有用*/ SET character_set_server = utf8; SET collation_connection = utf8_bin; SET collation_database = utf8_bin; SET collation_server = utf8_bin; my.ini中配置默認(rèn)編碼 default-character-set=utf8 連接數(shù)據(jù)庫(kù)設(shè)置編碼 jdbc:mysql://192.168.0.5:3306/test?characterEncoding=utf8 /*****************************************java與mysq編碼對(duì)應(yīng)****************************************/ java中的常用編碼UTF-8;GBK;GB2312;ISO-8859-1; 對(duì)應(yīng)mysql數(shù)據(jù)庫(kù)中的編碼utf8;gbk;gb2312;latin1 /********************************************過(guò)濾器使用*********************************************/ //過(guò)濾器設(shè)置編碼過(guò)濾(SetCharacterEncodingFilter.java) package com.sorc; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class SetCharacterEncodingFilter extends HttpServlet implements Filter{ private FilterConfig filterConfig; private String encoding=null; //Handle the passed-in FilterConfig public void init(FilterConfig filterConfig){ this.filterConfig=filterConfig; encoding=filterConfig.getInitParameter("encoding"); } //Process the request/response pair public void doFilter(ServletRequest request,ServletResponse response,FilterChain filterChain){ try{ request.setCharacterEncoding(encoding); filterChain.doFilter(request,response); } catch(ServletException sx){ filterConfig.getServletContext().log(sx.getMessage()); } catch(IOException iox){ filterConfig.getServletContext().log(iox.getMessage()); } } //Clean up resources public void destroy(){ } } //web.xml配置過(guò)濾器方法(web.xmd) setcharacterencodingfilter com.sorc.SetCharacterEncodingFilter encoding utf8 setcharacterencodingfilter /* /************************有了上面的基礎(chǔ)下面試完滿解決方案*****************************************/ 1.使用GBK編碼的解決方案 這個(gè)最簡(jiǎn)單 遇到設(shè)置編碼的地方就是用GBK數(shù)據(jù)庫(kù)gbk 然后在使用個(gè)過(guò)濾器過(guò)濾編碼為gbk一切搞定,。 效果為添加數(shù)據(jù)無(wú)亂碼 讀出無(wú)亂碼 數(shù)據(jù)庫(kù)管理工具無(wú)亂碼 到處sql結(jié)構(gòu)和數(shù)據(jù)無(wú)亂碼 2.使用UTF-8編碼解決方案 所有編碼都設(shè)置為UTF-8 數(shù)據(jù)庫(kù)編碼utf8 設(shè)置過(guò)濾器編碼utf8 數(shù)據(jù)庫(kù)連接?characterEncoding=utf8 然后在數(shù)據(jù)庫(kù)管理工具或mysql命令行 運(yùn)行 SET character_set_results = gbk; 效果為添加數(shù)據(jù)無(wú)亂碼 讀出無(wú)亂碼 數(shù)據(jù)庫(kù)管理工具無(wú)亂碼 到處sql結(jié)構(gòu)和數(shù)據(jù)時(shí)存在亂碼 3.頁(yè)面使用UTF8 數(shù)據(jù)庫(kù)使用latin1的解決方案 jap java tomcat 設(shè)置為UTF-8 過(guò)濾器 utf8 數(shù)據(jù)庫(kù)連接?characterEncoding=latin1 數(shù)據(jù)庫(kù)其他latin1 然后在數(shù)據(jù)庫(kù)管理工具或mysql命令行 運(yùn)行 SET character_set_results = gbk; 效果為添加數(shù)據(jù)無(wú)亂碼 讀出無(wú)亂碼 數(shù)據(jù)庫(kù)管理工具無(wú)亂碼 到處sql結(jié)構(gòu)和數(shù)據(jù)時(shí)存在亂碼 以上都不需要頁(yè)面或java代碼中手動(dòng)轉(zhuǎn)碼 ---------------------------------------------------------------------------------------------------------------------------------- 一、JSP頁(yè)面顯示亂碼二,、表單提交中文時(shí)出現(xiàn)亂碼三,、數(shù)據(jù)庫(kù)連接 大家在JSP的開(kāi)發(fā)過(guò)程中,經(jīng)常出現(xiàn)中文亂碼的問(wèn)題,,可能一至困擾著您,,我現(xiàn)在把我在JSP開(kāi)發(fā)中遇到的中文亂碼的問(wèn)題及解決辦法寫出來(lái)供大家參考。 一,、JSP頁(yè)面顯示亂碼 下面的顯示頁(yè)面(display.jsp)就出現(xiàn)亂碼: JSP的中文處理 <% out.print("JSP的中文處理"); %> 對(duì)不同的WEB服務(wù)器和不同的JDK版本,,處理結(jié)果就不一樣。原因:服務(wù)器使用的編碼方式不同和瀏覽器對(duì)不同的字符顯示結(jié)果不同而導(dǎo)致的,。解決辦法:在 JSP頁(yè)面中指定編碼方式(gb2312),即在頁(yè)面的第一行加上:<%@ page contentType="text/html; charset=gb2312"%>,,就可以消除亂碼了。完整頁(yè)面如下: <%@ page contentType="text/html; charset=gb2312"%> JSP的中文處理 <% out.print("JSP的中文處理"); %> 二,、表單提交中文時(shí)出現(xiàn)亂碼 下面是一個(gè)提交頁(yè)面(submit.jsp),,代碼如下: JSP的中文處理 下面是處理頁(yè)面(process.jsp)代碼: <%@ page contentType="text/html; charset=gb2312"%> JSP的中文處理 <%=request.getParameter("name")%> 如果submit.jsp提交英文字符能正確顯示,如果提交中文時(shí)就會(huì)出現(xiàn)亂碼,。原因:瀏覽器默認(rèn)使用UTF-8編碼方式來(lái)發(fā)送請(qǐng)求,,而UTF- 8和 GB2312編碼方式表示字符時(shí)不一樣,這樣就出現(xiàn)了不能識(shí)別字符。解決辦法:通過(guò)request.seCharacterEncoding ("gb2312")對(duì)請(qǐng)求進(jìn)行統(tǒng)一編碼,,就實(shí)現(xiàn)了中文的正常顯示,。修改后的process.jsp代碼如下: <%@ page contentType="text/html; charset=gb2312"%> <% request.seCharacterEncoding("gb2312"); %> JSP的中文處理 <%=request.getParameter("name")%> 三、數(shù)據(jù)庫(kù)連接出現(xiàn)亂碼 只要涉及中文的地方全部是亂碼,,解決辦法:在數(shù)據(jù)庫(kù)的數(shù)據(jù)庫(kù)URL中加上 useUnicode=true&characterEncoding=GBK 就OK了,。 四、數(shù)據(jù)庫(kù)的顯示亂碼 在mysql4.1.0中,varchar類型,,text類型就會(huì)出現(xiàn)中文亂碼,,對(duì)于varchar類型把它設(shè)為binary屬性就可以解決中文問(wèn)題,對(duì)于text類型就要用一個(gè)編碼轉(zhuǎn)換類來(lái)處理,,實(shí)現(xiàn)如下: public class Convert { /** 把ISO-8859-1碼轉(zhuǎn)換成GB2312 */ public static String ISOtoGB(String iso){ String gb; try{ if(iso.equals("") || iso == null){ return ""; } else{ iso = iso.trim(); gb = new String(iso.getBytes("ISO-8859-1"),"GB2312"); return gb; } } catch(Exception e){ System.err.print("編碼轉(zhuǎn)換錯(cuò)誤:"+e.getMessage()); return ""; } } } 把它編譯成class,,就可以調(diào)用Convert類的靜態(tài)方法ISOtoGB()來(lái)轉(zhuǎn)換編碼。 如果你還有什么不懂之處:我給大家推薦一個(gè)好的JSP-JAVA網(wǎng)站: http://www.phy./dsp/ 總結(jié): 1. 在jsp中<%@ page contentType="text/html; charset=A" %>如果指定了,,那么在改jsp中所有構(gòu)造的String(不是引用),,如果沒(méi)有指定編碼,那么這些String的編碼是A的,。 從request的得到的String如果沒(méi)有指定request的編碼的話,,他是iso-8859-1的 從別的地方得到的String是使用原來(lái)初始的編碼的,比如從數(shù)據(jù)庫(kù)得到String,如果數(shù)據(jù)庫(kù)的編碼是B,那么該String的編碼是B而不是A的,,也不是系統(tǒng)默認(rèn)的,。 此時(shí),如果要輸出的String的編碼不是A,那么,,很可能顯示亂碼的,,所以首先要將String正確轉(zhuǎn)化為編碼A的String,然后輸出。 2. 在jsp中<%@ page contentType="text/html; charset=A" %>沒(méi)有指定,,那么相當(dāng)于指定了<%@ page contentType="text/html; charset=ISO-8859-1" %> 3. Servelte中如果執(zhí)行了像 response.setContentType("text/html;charset=A");説明將response的字符輸出流編碼設(shè)置為A,所有要輸出的String的編碼要轉(zhuǎn)化為A的,否則會(huì)得到亂碼的,。 Servelet中從request得到的String的編碼和jsp中一樣的,,但是在servlet java文件中構(gòu)造的String是使用的系統(tǒng)默認(rèn)的編 -------------------------------------------------------------------------- 根本解決辦法 所有地方都設(shè)置成GBK |
|