Java WEB開發(fā)中的中文亂碼問題解決
本文所有范例以UTF-8為例。大家可以根據(jù)自己的情況加以替換。
在開始本文之前,假設(shè)本文的讀者已經(jīng)熟悉或了解以下技術(shù):
- Java語法
- Java WEB開發(fā)的基本概念
- Jsp
- Servlet
- 至少一種支持JSP/SERVLET的Web服務(wù)器(包括安裝,運(yùn)行)
瀏覽器/WEB服務(wù)器之間的參數(shù)傳遞原理分析
瀏覽器/WEB服務(wù)器之間的中文參數(shù)傳遞
1,表單(form)中文參數(shù)的傳遞方法。我們使用一個(gè)簡(jiǎn)單的范例說明表單提交時(shí)瀏覽器的對(duì)中文參數(shù)的處理。
- SubmitAsia.html
- view plaincopy to clipboardprint?
- <html>
- <head>
- <meta http-equiv="content-type" content="text/html; charset=UTF-8">
- </head>
- <body>
- <form method="get">
- <input type="text" name="userName" id="userName"> <input type="submit" value="submit" />
- </form>
- </body>
- </html>
- <html>
- <head>
- <meta http-equiv="content-type" content="text/html; charset=UTF-8">
- </head>
- <body>
- <form method="get">
- <input type="text" name="userName" id="userName"> <input type="submit" value="submit" />
- </form>
- </body>
- </html>
使用任意瀏覽器打開該文件,在輸入框內(nèi)輸入 “你好” 中文2字,然后按submit按鈕,我們注意到瀏覽器的地址欄:
file:///C:/SubmitAsia.html?userName=%E4%BD%A0%E5%A5%BD
剛才輸入“你好”二字,被轉(zhuǎn)換為 %E4%BD%A0%E5%A5%BD 后被發(fā)往服務(wù)器。
這個(gè) %E4%BD%A0%E5%A5%BD 是什么呢?
我們先使用一個(gè)Java程序來測(cè)試一下。如下:
- EnDecoderUtil.java
- view plaincopy to clipboardprint?
- import java.io.IOException;
- import java.io.UnsupportedEncodingException;
- import java.net.URLDecoder;
- import java.net.URLEncoder;
- public class EnDecoderUtil {
- public static void main(String []args) {
- try {
- String str = URLEncoder.encode("你好", "UTF-8");
- System.out.println(str);
- str = URLDecoder.decode(str, "UTF-8");
- System.out.println(str);
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
- }
- }
- import java.io.IOException;
- import java.io.UnsupportedEncodingException;
- import java.net.URLDecoder;
- import java.net.URLEncoder;
- public class EnDecoderUtil {
- public static void main(String []args) {
- try {
- String str = URLEncoder.encode("你好", "UTF-8");
- System.out.println(str);
- str = URLDecoder.decode(str, "UTF-8");
- System.out.println(str);
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
- }
- }
編譯執(zhí)行:
c:\>javac EnDecoderUtil.java
c:\>java EnDecoderUtil
%E4%BD%A0%E5%A5%BD
你好
我們發(fā)現(xiàn),瀏覽器發(fā)送給服務(wù)器的“你好”中文參數(shù)跟使用java.net.URLEncoder.encode()方法編碼后的值完全一樣。
原來,瀏覽器在向服務(wù)器傳遞參數(shù)時(shí),對(duì)于非數(shù)字,非英文的字符(比如中日韓文)時(shí),會(huì)先將其加以變換(編碼),再發(fā)送給服務(wù)器,服務(wù)器接收到這種格式的字符時(shí),會(huì)將其反向編碼,還原成原來的字符。
瀏覽器/Java WEB服務(wù)器之間的中文參數(shù)傳遞 過程模擬
為了幫助大家能更好地理解,我們使用下面的例子,該例通過聯(lián)結(jié)的形式向Google服務(wù)器發(fā)送一個(gè)查詢命令參數(shù)。
比如,我們通過Google查詢“你好啊”,通過以下2種方法向Google服務(wù)器發(fā)送參數(shù):
- SubmitAsia2Google.html
- view plaincopy to clipboardprint?
- <html>
- <head>
- <meta http-equiv="content-type" content="text/html; charset=UTF-8">
- </head>
- <body>
- 方法1:<a href="http://www.google.com/search?q=你好啊">你好啊</a><br>
- 方法2:<a href="http://www.google.com/search?q=%E4%BD%A0%E5%A5%BD%E5%95%8A">你好啊</a>
- </body>
- </html>
- <html>
- <head>
- <meta http-equiv="content-type" content="text/html; charset=UTF-8">
- </head>
- <body>
- 方法1:<a href="http://www.google.com/search?q=你好啊">你好啊</a><br>
- 方法2:<a href="http://www.google.com/search?q=%E4%BD%A0%E5%A5%BD%E5%95%8A">你好啊</a>
- </body>
- </html>
使用任意瀏覽器打開該文件。
方法1:你好啊
方法2:你好啊
使用方法1時(shí),Google的查詢頁面通常會(huì)顯示亂碼,方法2時(shí)顯示完全正常。
通過這個(gè)例子,我們知道,為了讓服務(wù)器能夠正常接收中文參數(shù),對(duì)HTML頁面的中文參數(shù)一定要經(jīng)過編碼處理。
表單里的中文字符在提交時(shí),瀏覽器已經(jīng)替我們做了編碼處理,但聯(lián)結(jié)(<a href.../>)里的中文需要我們自己處理。
JSP頁面聯(lián)結(jié)的中文參數(shù)編碼方法
JSP頁面里的聯(lián)結(jié)很多情況下是動(dòng)態(tài)生成的,比如根據(jù)數(shù)據(jù)庫(kù)里的數(shù)據(jù)的不同動(dòng)態(tài)生成包含中文關(guān)鍵字的聯(lián)結(jié)等等。
方法1:JSP里直接使用java.net.URLEncoder.encode()。例:<a href="some.jsp?key=<%=java.net.URLEncoder.encode("可能包含中文的參數(shù)","UTF-8")%>">聯(lián)結(jié)</a>
方法2:Javabean使用java.net.URLEncoder.encode()
在Javabean里使用java.net.URLEncoder.encode()處理之后,JSP里加以引用。
- view plaincopy to clipboardprint?
- <jsp:useBean id="someBean" class="Beans.SomeBean"
- scope="request" />
- ...
- <%
- String chars = myBean.getSomeProp();
- out.println("<a href=\"some.jsp?key=" + chars + ">聯(lián)結(jié)</a>");
- %>
- ...
- <jsp:useBean id="someBean" class="Beans.SomeBean"
- scope="request" />
- ...
- <%
- String chars = myBean.getSomeProp();
- out.println("<a href=\"some.jsp?key=" + chars + ">聯(lián)結(jié)</a>");
- %>
- ...
方法3:使用自定義標(biāo)簽。
在自定義標(biāo)簽里使用java.net.URLEncoder.encode()方法處理。
關(guān)于自定義標(biāo)簽的具體方法,這里不做介紹。
JSP與SERVLET的連動(dòng)
JSP經(jīng)過上面的處理之后,***輸出的HTML頁面聯(lián)結(jié)已經(jīng)可以正常向服務(wù)器傳遞中文參數(shù)了。
下面我們闡述一下Servlet里怎么接收/解析中文參數(shù)。
對(duì)于<a href="/someServlet?key=%E4%BD%A0%E5%A5%BD">你好</a>之類的聯(lián)結(jié),我們可以用下面的servlet來解析傳遞過來的中文參數(shù)。
- GetAsiaCharServlet.java
- view plaincopy to clipboardprint?
- import java.io.IOException;
- import java.net.URLEncoder;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- public class GetAsiaCharServlet extends HttpServlet {
- @Override
- //redir?key=xxxx
- protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
- String key = req.getParameter("key");
- key = <SPAN style="COLOR: #ff0000">new String(key.getBytes("ISO-8859-1", "utf-8"))</SPAN>;
- System.out.println(keyword);
- //...
- //重定向處理
- //res.sendRedirect("http://www.google.com/search?q="+URLEncoder.encode(key, "utf-8"));
- }
- }
- import java.io.IOException;
- import java.net.URLEncoder;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- public class GetAsiaCharServlet extends HttpServlet {
- @Override
- //redir?key=xxxx
- protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
- String key = req.getParameter("key");
- key = new String(key.getBytes("ISO-8859-1", "utf-8"));
- System.out.println(keyword);
- //...
- //重定向處理
- //res.sendRedirect("http://www.google.com/search?q="+URLEncoder.encode(key, "utf-8"));
- }
- }
我們注意到使用req.getParameter("key")得到參數(shù)后,還使用了new String(key.getBytes("ISO-8859-1", "utf-8"))把ISO-8859-1字符集形式轉(zhuǎn)換成UTF-8形式。
為什么呢?因?yàn)閕so-8859-1是Java中網(wǎng)絡(luò)傳輸使用的標(biāo)準(zhǔn)字符集,req.getParameter("key")得到的還是ISO-8859-1字符集,所以要轉(zhuǎn)換一下才不會(huì)是亂碼。
***,順便提一下,采用servlet重定向時(shí),也需要對(duì)包含中文文字的參數(shù)做特殊處理。
例如,SERVLET從HTML頁面的聯(lián)結(jié)接受參數(shù),然后重新定向到Google搜索。則可以在上面的GetAsiaCharServlet里加上如下處理:res.sendRedirect("http://www.google.com/search?q="+URLEncoder.encode(key, "utf-8"));
也就是說,需要把參數(shù)取出來,轉(zhuǎn)換,再重新使用URLEncoder.encode編碼,這樣就不會(huì)出現(xiàn)亂碼現(xiàn)象。
【編輯推薦】