在JSP/Servlet中,主要有以下四種方式可以設(shè)置編碼,其中前兩個(gè)只能應(yīng)用于JSP中,而后兩個(gè)可以用于 JSP 和 Servlet 中。
pageEncoding=”UTF-8”;
contentType=”text/html;charset=UTF-8”;
request.setCharacterEncoding(“UTF-8”) ;
response.setCharacterEncoding(“UTF-8”)。
事實(shí)上,一個(gè)JSP的源文件需要經(jīng)過(guò)三個(gè)階段,兩次編碼,才能完成一次完整的輸出,這三個(gè)階段是:
第一階段:轉(zhuǎn)譯(.jsp -> .java;pageEncoding -> UTF-8)。將jsp編譯成Servlet(.java)文件,用到的指令是pageEncoding。在編譯過(guò)程中,根據(jù)pageEncoding=“XXX”的指示,找到編碼的規(guī)則為“XXX”,然后服務(wù)器將JSP文件編譯成.java文件時(shí)會(huì)根據(jù)pageEncoding的設(shè)定讀取jsp,結(jié)果是由指定的編碼方案翻譯成統(tǒng)一的UTF-8編碼的JAVA源碼(即.java)。
第二階段:編譯(.java -> .class;UTF-8 -> UTF-8)。從Servlet文件(.java)到Java字節(jié)碼文件(.class),從UTF-8到UTF-8。在這一階段中,不論JSP編寫(xiě)時(shí)候用的是什么編碼方案,經(jīng)過(guò)這個(gè)階段的結(jié)果全部是UTF-8的encoding的java源碼。JAVAC用UTF-8的encoding讀取java源碼,編譯成UTF-8編碼的二進(jìn)制碼(即.class),這是JVM對(duì)常數(shù)字串在二進(jìn)制碼(Java encoding)內(nèi)表達(dá)的規(guī)范。這一過(guò)程是由JVM的內(nèi)在規(guī)范決定的,不受外界控制。
第三階段:編譯(UTF-8 -> contentType)。從服務(wù)器到瀏覽器,這在一過(guò)程中用到的指令是contentType。服務(wù)器載入和執(zhí)行由第二階段生成出來(lái)JAVA二進(jìn)制碼,輸出的結(jié)果,也就是在客戶端可見(jiàn)到的結(jié)果,在這次輸出過(guò)程中,由contentType屬性中的charset來(lái)指定,將UTF8形式的二進(jìn)制碼以charset的編碼形式來(lái)輸出。如果沒(méi)有人為設(shè)定,則默認(rèn)的是ISO-8859-1的形式。
特別需要注意的是,pageEncoding 的默認(rèn)值是 “ISO-8859-1”, contentType 的默認(rèn)值是 “text/html;ISO-8859-1”。
Ps: 第一、三兩個(gè)階段的轉(zhuǎn)碼個(gè)人感覺(jué)聯(lián)想到Sting轉(zhuǎn)碼更容易理解些,例如 :new String(name.getBytes(“ISO-8859-1”), “utf-8”)。
pageEncoding=”UTF-8” 的作用是設(shè)置JSP編譯成Servlet時(shí)使用的編碼。通常,在JSP內(nèi)部定義的字符串(直接在JSP中定義,而不是從瀏覽器提交的數(shù)據(jù))出現(xiàn)亂碼時(shí),很多都是由于該參數(shù)設(shè)置錯(cuò)誤引起的。例如,你的 JSP文件中含有中文字符,而在JSP中卻指定pageEncoding=”iso-8859-1”,就會(huì)導(dǎo)致中文字符顯示異常??聪旅娴睦樱?/span>
在其編譯為Servlet后,其源碼(片段)如下所示:
訪問(wèn)該頁(yè)面,頁(yè)面顯示如下:
我們可以看到,由于pageEncoding被指定為”iso-8859-1”,導(dǎo)致其在由服務(wù)器將JSP文件編譯成.java文件過(guò)程中,在使用 “iso-8859-1” 讀取jsp并翻譯成統(tǒng)一的UTF-8編碼的JAVA源碼時(shí),所有的中文字符被轉(zhuǎn)成亂碼,并使得其呈現(xiàn)給用戶的響應(yīng)也包含亂碼。特別地,該屬性還有一個(gè)功能,就是在JSP中不指定contentType參數(shù),也不使用response.setCharacterEncoding方法時(shí),指定對(duì)服務(wù)器響應(yīng)的內(nèi)容進(jìn)行編碼。
contentType=”text/html;charset=UTF-8” 的作用是將上述第二階段所生成的UTF8形式的二進(jìn)制碼以charset的編碼形式來(lái)輸出到客戶端,如果設(shè)置不當(dāng)?shù)脑?,?huì)出現(xiàn)亂碼??聪旅娴睦樱?/span>
在其編譯為Servlet后,其源碼(片段)如下所示:
訪問(wèn)該頁(yè)面,頁(yè)面顯示如下:
request.setCharacterEncoding(“UTF-8”)用來(lái)指定對(duì)瀏覽器發(fā)送來(lái)的數(shù)據(jù)以特定的字符集進(jìn)行重新編碼,常用于對(duì) POST 請(qǐng)求參數(shù)進(jìn)行解碼。
response.setCharacterEncoding(“UTF-8”)的作用是:在服務(wù)器將響應(yīng)返回到瀏覽器前,對(duì)響應(yīng)使用指定字符集進(jìn)行重新編碼。一旦使用了該種方式,即使該響應(yīng)頁(yè)面指定了具體的 contentType,也將失效。看下面的例子:
在其編譯為Servlet后,其源碼(片段)如下所示:
訪問(wèn)該頁(yè)面,頁(yè)面顯示如下:
根據(jù)上文內(nèi)容,我們得出以下三點(diǎn):
在指定JSP編譯成Servlet時(shí)使用的編碼時(shí),優(yōu)先級(jí)為: pageEncoding=”UTF-8” > contentType=”text/html;charset=UTF-8”
在指定服務(wù)器對(duì)響應(yīng)內(nèi)容的編碼時(shí),優(yōu)先級(jí)為:response.setCharacterEncoding(“UTF-8”) > contentType=”text/html;charset=UTF-8” > pageEncoding=”UTF-8”
request.setCharacterEncoding(“UTF-8”) 只用來(lái)指定對(duì)瀏覽器發(fā)送來(lái)的請(qǐng)求數(shù)據(jù)的解碼方式。
在介紹JSP頁(yè)面與JSP源文件的亂碼問(wèn)題前,首先我們必須對(duì)JSP頁(yè)面中文亂碼問(wèn)題與JSP源文件中文亂碼問(wèn)題有一個(gè)清晰的概念,即:
JSP頁(yè)面中文亂碼問(wèn)題是指用戶在瀏覽器看到的服務(wù)器所返回的jsp頁(yè)面中,中文字符不能正常顯示;
JSP源文件中文亂碼問(wèn)題是指在編輯器保存JSP源文件后,中文字符不能正常顯示。
因此,這是兩個(gè)不同層面的問(wèn)題。接下來(lái),我們分別解決這兩個(gè)問(wèn)題。
1、JSP頁(yè)面亂碼
我們先在記事本中編寫(xiě)一個(gè)JSP程序,如下:
上面這個(gè)JSP程序是在頁(yè)面顯示幾句中文而且標(biāo)題也是中文,運(yùn)行后在瀏覽器中顯示如圖所示:
原因在于沒(méi)有在JSP中指定 頁(yè)面顯示的編碼,消除亂碼的解決方案就是將上面代碼中的page命令修改成如下所示即可:
再次運(yùn)行中文正常顯示,原理就是 向頁(yè)面指定編碼為utf-8,那么頁(yè)面就會(huì)按照此編碼來(lái)顯示,于是亂碼消失。
2、JSP源文件亂碼
1). JSP源文件亂碼 與 Eclipse/MyEclipse 對(duì)JSP的默認(rèn)編碼設(shè)置
如果我們?cè)贓clipse/MyEclipse中打開(kāi)上面示例1的jsp源文件,由于Eclipse/MyEclipse中默認(rèn)的JSP編碼格式為ISO-8859-1,所以當(dāng)打開(kāi)由其他編輯器編輯的JSP文件時(shí)會(huì)出現(xiàn)亂碼,如圖所示:
對(duì)于這個(gè)問(wèn)題,我們只需要更改一下 Eclipse/MyEclipse 中對(duì)JSP的默認(rèn)編碼并update就可以了,修改的地方(我的MyEclipse版本為 10)如圖所示:
修改后,對(duì)于在Eclipse/MyEclipse所創(chuàng)建的任何一個(gè)JSP源文件,其默認(rèn)編碼方式均為 UTF-8,例如:
如果不做上述修改,如果我們?cè)贓clipse/MyEclipse中編輯的JSP中存在中文字符,那么當(dāng)我們保存該頁(yè)面時(shí),會(huì)彈出以下對(duì)話框:
但是,我們?nèi)绻覀兲崆鞍慈缟喜襟E設(shè)置后,JSP源文件就能正常保存、編譯。
2). Eclipse/MyEclipse 創(chuàng)建 JSP時(shí) pageEncoding 的默認(rèn)值設(shè)置
我們?cè)诰庉嫷腏SP文件時(shí),尤其在包含中文字符時(shí),一定要在page編譯指令中恰當(dāng)?shù)刂该?pageEncoding 的值,否則在瀏覽器訪問(wèn)該JSP頁(yè)面時(shí),其中的中文就會(huì)顯示為亂碼。因?yàn)橐坏┤笔?pageEncoding 時(shí),其值就會(huì)被默認(rèn)指定為 “iso-8859-1”,該字符集不支持中文。此外,使用 Eclipse/MyEclipse 進(jìn)行開(kāi)發(fā)的伙伴們都知道,這兩個(gè)IDE生成的JSP模板的pageEncoding的默認(rèn)值是“iso-8859-1”。為方便開(kāi)發(fā),我們可以更改Eclipse/MyEclipse生成JSP模板時(shí)pageEncoding的默認(rèn)值,修改的地方(我的MyEclipse版本為10)如圖所示:
這樣,通過(guò)以上兩步的設(shè)置,當(dāng)我們?cè)?Eclipse/MyEclipse 中創(chuàng)建一個(gè)新的JSP文件時(shí),該源文件在Eclipse/MyEclipse中的默認(rèn)編碼方式為utf-8,因此就不會(huì)導(dǎo)致 JSP源文件亂碼;并且其 pageEncoding 的值會(huì)被自動(dòng)設(shè)為“utf-8”,這就不會(huì)導(dǎo)致JSP頁(yè)面亂碼。
1、URL傳遞參數(shù)中文亂碼
運(yùn)行結(jié)果如下圖所示:
2、表單提交中文亂碼
該示例由 “收集參數(shù)的表單頁(yè)” 和 “表單提交參數(shù)顯示頁(yè)”兩部分構(gòu)成。
收集參數(shù)的表單頁(yè):
表單提交參數(shù)顯示頁(yè):
運(yùn)行結(jié)果如下圖所示:
3、GET 請(qǐng)求的請(qǐng)求參數(shù)為中文情形小結(jié)
只要我們以GET形式提交請(qǐng)求,無(wú)論是以表單形式提交還是以URL形式提交,如果參數(shù)中存在中文字符,那么我們必須進(jìn)行相應(yīng)的轉(zhuǎn)碼(借助String類)或者解碼(借助URLDecoder類),特別地,有五點(diǎn)需要注意:
request.getQueryString() 所返回的原生查詢字符串只適用于 GET請(qǐng)求 ,若對(duì) POST請(qǐng)求 使用,則返回 null;
利用 URLDecoder 進(jìn)行解碼時(shí),必須先對(duì)原生查詢字符串解碼,而后獲取各請(qǐng)求參數(shù)。如果先獲取各個(gè)請(qǐng)求參數(shù),再依次解碼,則仍是亂碼;
使用String進(jìn)行 轉(zhuǎn)碼時(shí),往往都是先從 ISO-8859-1 格式的字符串中取出字節(jié)內(nèi)容,然后再用頁(yè)面相應(yīng)的編碼格式重新構(gòu)造一個(gè)新的字符串,像本示例(new String(country.getBytes(“ISO-8859-1”), “utf-8”))中的 一樣。這樣就可以支持中文字符的正常取值和顯示;
利用 URLDecoder 進(jìn)行解碼時(shí),所采用的解碼字符集取決于瀏覽器(本文所有實(shí)驗(yàn)都是基于 Google Chrome 的)。對(duì)于中文環(huán)境而言,一般要么是 UTF-8,要么是 GBK ;
對(duì)于 GET請(qǐng)求,語(yǔ)句 request.setCharacterEncoding(“utf-8”); 對(duì)避免中文參數(shù)亂碼起不到任何作用。
經(jīng)過(guò)上面的處理,GET請(qǐng)求的中文參數(shù)亂碼問(wèn)題已經(jīng)得到解決。但是如果上面的表單中的輸入項(xiàng)不止幾項(xiàng),那么每個(gè)輸入項(xiàng)都需要進(jìn)行編碼轉(zhuǎn)換,那樣就很麻煩了。這時(shí),我們就用到了大名鼎鼎的過(guò)濾器 filter 了。
一般地,我們以POST形式提交請(qǐng)求,都是以表單形式進(jìn)行并且 form 的 method 屬性為 post。下面的示例對(duì)上面的示例做了一些修改,也由 “收集參數(shù)的表單頁(yè)” 和 “表單提交參數(shù)顯示頁(yè)” 兩部分構(gòu)成:
收集參數(shù)的表單頁(yè):
表單提交參數(shù)顯示頁(yè):
運(yùn)行結(jié)果如下圖所示:
根據(jù)上面運(yùn)行結(jié)果,我們知道: 對(duì)于POST請(qǐng)求,若其請(qǐng)求參數(shù)包含中文字符,那么我們只需在解析請(qǐng)求參數(shù)前加一句如下的代碼即可。需要注意的是,這種方式對(duì) Get請(qǐng)求起不到任何作用。此外,由于我們對(duì)請(qǐng)求已經(jīng)重新編碼,所以已經(jīng)不需要使用 String類 再進(jìn)行轉(zhuǎn)碼,否則畫(huà)蛇添足。最后,對(duì)于 POST請(qǐng)求,request.getQueryString(); 返回的查詢字符串為 null。
聯(lián)系客服