想必大家在網站開發時經常遇到亂碼問題,最近自己在寫了一個部落格的小例子時,又遇到了亂碼問題,一般都是些常見的,往往搜搜,都有解決方案,但網上大部分都是直接貼解決方案的,沒有指出具體原因,所以這兩天自己看了一些關於亂碼的文章,慢慢有點頭緒,所以抓緊寫下來,我會把自己遇到的亂碼問題一一呈現給大家,並分析原因及寫出解決辦法。
如有不對,還請大家多多包含,積極指正!一個人的理解往往是有限,甚至有錯誤,集思廣益才會使分析更趨於正確、完美!
先看一段代碼,解釋幾處代碼:
<%@ page language="java" pageEncoding="gb2312"%><%@ page contentType="text/html;charset=iso8859-1"%><html><head><title>JSP的中文處理</title><meta http-equiv="Content-Type" content="text/html charset=gb2312"></head><body><%out.print("JSP的中文處理");%></body></html>
第一處<%@ page language="java" pageEncoding="gb2312"%>,指定了頁面的編碼格式,jsp檔案的儲存格式就是這個編碼格式,Eclipse會根據這個編碼格式儲存檔案。並編譯jsp檔案,包括裡面的漢字。
第二處編碼為解碼格式。因為存為gb2312的檔案被解碼為iso8859-1,這樣如有中文肯定出亂碼。也就是必須一致。如果第二處所在的這一行沒有的話,系統預設也是使用iso8859-1的編碼格式。所以如果沒有這一行的話,也會出現亂碼。必須一致才可以。
這行負責jsp頁面中字元按什麼編碼格式顯示,也就是最終見到的網頁內容的編碼格式。
注意:<%@ page language="java" pageEncoding=""%>指定了,<%@ page contentType="text/html;charset="%>沒有指定的話,一般預設是iso8859-1編碼格式;反之,它們編碼格式相同。
第三處編碼為控制瀏覽器的解碼方式。如果前面的解碼都一致並且無誤的話,這個編碼格式用不用設定都可以。有的網頁出現亂碼,就是因為瀏覽器不能確定使用哪種編碼格式。因為頁面有時候會嵌入頁面,導致瀏覽器混淆了編碼格式出現了亂碼。
注意:<%@ page contentType="text/html;charset="%>指定了瀏覽器的編碼格式,如果jsp頁面中指定了這個,那麼meta http-equiv="Content-Type" content="text/html charset=">是不起作用的;只有jsp中沒有<%@ page contentType="text/html;charset="%>,它才會起作用;如果它們都存在,<%@ page contentType="text/html;charset="%>優先。
下面開始進入本文:
情形1:
jsp頁面利用form表單提交(method=“post”),在servlet檔案中利用request.getParameter("參數名")得到傳過來的值。這裡往往會出現亂碼。
接下來的例子的處理方式是正確的,大家注意看紅色字。
關鍵點:jsp中的charset=“utf-8”且value = new String(value.getBytes("ISO8859_1"),
"utf-8");這兩個地方字元要保持一致才行。
index.jsp
<%@ page contentType="text/html; charset=utf-8" language="java" import="java.sql.*" errorPage="" %><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title></title><link href="CSS/style.css" type="text/css" rel="stylesheet"><style type="text/css"></style></head><body onselectstart="return false"><table class="indexmain"> <tr> <td valign="top"><table width="658" border="0"> <tr> <td colspan="2"> </td> </tr> <tr> <td width="92" height="358"> </td> <td width="550" valign="bottom"><form name="form1" method="post" action="ConsumerServlet?method=0&sign=0" onSubmit="return userCheck()"><table width="291" border="0" align="center" cellpadding="0" cellspacing="0"> <tr> <td width="66" height="30">使用者名稱:</td> <td width="225"> <input name="account" type="text" class="inputinput" id="account" size="30"> </td> </tr> <tr> <td height="30">密 碼:</td> <td><input name="password" type="password" class="inputinput" id="password" size="30"></td> </tr> <tr> <td height="30" colspan="2" align="center"> <input type="image" class="inputinputinput" src="images/land.gif"> <a href="#" onClick="javascript:form1.reset()"><img src="images/reset.gif"></a> <a href="accountAdd.jsp"><img src="images/register.gif"></a> </td> </tr></table></form></td> </tr></table></td></tr></table><script src="JS/validate.js" language="javascript" type="text/javascript"></script></body></html>
ConsumerServlet.java
// 使用者登入操作public void checkConsumer(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {String account = Chinese.toChinese(request.getParameter("account"));consumerDao = new ConsumerDao();ConsumerForm consumerForm = consumerDao.getConsumerForm(account);if (consumerForm == null) {request.setAttribute("information", "您輸入的使用者名稱不存在,請重新輸入!");} else if (!consumerForm.getPassword().equals(request.getParameter("password"))) {request.setAttribute("information", "您輸入的登入密碼有誤,請重新輸入!");} else {request.setAttribute("form", consumerForm);}//驗證通過之後RequestDispatcher requestDispatcher = request.getRequestDispatcher("dealwith.jsp");requestDispatcher.forward(request, response);}
Chinese.java(關鍵)
public class Chinese { public static String toChinese(String value) { try { if (value == null) { return ""; } else { value = new String(value.getBytes("ISO8859_1"), "utf-8"); return value; } //用ISO8859_1的編碼格式去讀取value,並轉換成utf-8 } catch (Exception e) { return ""; } }}
這段代碼負責轉碼,可能大家對紅色代碼不太理解,我這裡貼上JAVA API的解釋:
public byte[] getBytes(String charsetName)
throws
UnsupportedEncodingException
使用指定的字元集將此String 解碼為位元組序列,並將結果儲存到一個新的位元組數組中。
當此字串不能在給定的字元集中解碼時,該方法無指定的行為。當需要進一步控制解碼過程時,應使用CharsetEncoder 類。
參數:
charsetName - 受支援的
charset 名稱
返回:
結果位元組數組
拋出:
UnsupportedEncodingException - 如果指定的字元集不受支援
public String(byte[] bytes,
String charsetName)
throws UnsupportedEncodingException
構造一個新的 String,方法是使用指定的字元集解碼指定的位元組數組。新的 String 的長度是一個字元集函數,因此不能等於位元組數組的長度。
當給定位元組在給定字元集中無效的情況下,該構造方法無指定的行為。當需要進一步控制解碼過程時,應使用
CharsetDecoder 類。
參數:
bytes - 要解碼為字元的位元組
charsetName - 受支援的 charset 的名稱
拋出:
UnsupportedEncodingException - 如果指定字元集不受支援
情形2:
form表單的另外一種形式(利用Submit)。
下面是一個提交頁面(submit.jsp),代碼如下:
<%@ page contentType="text/html; charset=gb2312"%> <html><head><title>JSP的中文處理</title><meta http-equiv="Content-Type" content="text/html; charset=gb2312"></head><body><form name="form1" method="post/get" action="process.jsp"><div align="center"><input type="text" name="name"><input type="submit" name="Submit" value="Submit"></div></form></body></html>
下面是處理頁面(process.jsp)代碼:
<%@ page contentType="text/html; charset=gb2312"%><html><head><title>JSP的中文處理</title><meta http-equiv="Content-Type" content="text/html; charset=gb2312"></head><body><%=request.getParameter("name")%></body></html>
如果輸入中文,就會看到亂碼,解決方案同上:
<%@ page contentType="text/html; charset=gb2312"%><html><head><title>JSP的中文處理</title><meta http-equiv="Content-Type" content="text/html; charset=gb2312"></head><body><%String s=new String(request.getParameter("name").getBytes("ISO-8859-1"),"gb2312") ;out.print(s);%></body></html>
這樣就OK了。
分析:
tomcat預設使用ISO-8859-1的方式去讀取數值的,但實際裡面的字元編碼應該是jsp頁面的pageEncoding指定的(一般不會是iso-8859-1),這樣的話讀取之後顯示的編碼格式和儲存的格式不一致,所以出現了亂碼。
而我們的轉碼恰恰解決了這個問題,我們先使用ISO-8859-1格式解碼字串,再利用與pageEncoding一致的編碼格式解碼位元組數組,這樣就使讀取之後顯示的編碼格式和儲存的格式一致,亂碼問題解決。
網上搜尋的來另外一種解決方案:
通過request.seCharacterEncoding ("gb2312")對請求進行統一編碼。
修改後的process.jsp代碼如下:
<%@ page contentType="text/html; charset=gb2312"%><%request.setCharacterEncoding("gb2312");%><html><head><title>JSP的中文處理</title><meta http-equiv="Content-Type" content="text/html; charset=gb2312"></head><body><%=request.getParameter("name")%></body></html>
經測試,這個方法不行,還是亂碼,哪位給解釋解釋????
未完待續~~~