在開發(fā) Web 項(xiàng)目時,解決中文亂碼問題是不可避免的。在前面所學(xué)的知識中,解決亂碼的通常做法是在 Servlet 程序中設(shè)置編碼方式,但是,當(dāng)多個 Servlet 程序都需要設(shè)置編碼方式時,就會書寫大量重復(fù)的代碼。
為了解決這一問題,我們可以在 Filter 中對獲取到的請求和響應(yīng)消息進(jìn)行編碼處理,這樣就可以實(shí)現(xiàn)全站編碼方式的統(tǒng)一。本節(jié)將分步驟演示如何使用 Filter 實(shí)現(xiàn)全站編碼的統(tǒng)一。
在 filterDemo01 項(xiàng)目的 WebContent 目錄中編寫一個 form.jsp 頁面,該頁面用于提交用戶登錄的表單信息,如下所示。
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>用戶登錄</title>
</head>
<center>
<h3>用戶登錄</h3>
</center>
<body style="text-align:center;">
<a href="<%=request.getContextPath()%>/CharacterServlet?name=張三&password=1234">
單擊超鏈接登錄
</a>
<form action="<%=request.getContextPath()%>/CharacterServlet" method="post">
<table border="1" width="600px" cellpadding="0" cellspacing="0" align="center">
<tr>
<td height="30" align="center">用戶名:</td>
<td> <input type="text" name="name" /></td>
</tr>
<tr>
<td height="30" align="center">密 碼</td>
<td> <input type="password" name="password" /></td>
</tr>
<tr>
<td height="30" colspan="2" align="center">
<input type="submit" value="登錄"/>
<input type="reset" value="重置" />
</td>
</tr>
</table>
</form>
</body>
</html>
在 form.jsp 中,第 14~16 行代碼是一個請求方式為 GET 的超鏈接;第 17~35 行代碼是一個 POST 提交方式 form 表單。
在 filterDemo01 項(xiàng)目的 com.mengma.filter 包中創(chuàng)建一個名稱為 CharacterServlet 的 Servlet 類,該類用于獲取用戶輸入的請求參數(shù),并將參數(shù)輸出到控制臺,其代碼如下所示。
package com.mengma.filter;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CharacterServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println(request.getParameter("name"));
System.out.println(request.getParameter("password"));
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
3、創(chuàng)建過濾器
在 filterDemo01 項(xiàng)目的 com.mengma.filter 包中創(chuàng)建一個名稱為 CharacterFilter 的 Filter 類,該類用于攔截用戶的請求訪問,并實(shí)現(xiàn)全站編碼的統(tǒng)一,其具體實(shí)現(xiàn)代碼如下所示。
package com.mengma.filter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
public class CharacterFilter implements Filter {
public void init(FilterConfig fConfig) throws ServletException {
}
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
// 攔截所有的請求,解決全站中文亂碼,指定request和response的編碼
request.setCharacterEncoding("utf-8"); // 只對消息體有效
response.setContentType("text/html;charset=utf-8");
// 對 request 進(jìn)行包裝
CharacterRequest characterRequest = new CharacterRequest(request);
chain.doFilter(characterRequest,response);
}
public void destroy() {
}
}
// 繼承默認(rèn)包裝類 HttpServletRequestWrapper
class CharacterRequest extends HttpServletRequestWrapper {
private HttpServletRequest request;
public CharacterRequest(HttpServletRequest request) {
super(request);
this.request = request;
}
// 子類繼承父類一定會覆寫一些方法,此處用于重寫getParameter()方法
public String getParameter(String name) {
// 調(diào)用被包裝對象getParameter()方法,獲得請求參數(shù)
String value = super.getParameter(name);
if (value == null) {
return null;
}
String method = super.getMethod(); // 判斷請求方式
if ("get".equalsIgnoreCase(method)) {
try {
value = new String(value.getBytes("iso-8859-1"), "utf-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
return value; // 解決亂碼后返回結(jié)果
}
}
在 CharacterFilter 中,針對請求的方式不同,采用了不同的亂碼解決方式。其中,由于 POST 方式的請求參數(shù)存放在消息體中,所以通過 setCharacterEncoding() 方法進(jìn)行設(shè)置,而 GET 方式的請求參數(shù)存放在消息頭中,通過 HttpServletRequestWrapper 類對 HttpServletRequest 類進(jìn)行包裝,并通過重寫 getParameter() 的方式設(shè)置 GET 方式提交參數(shù)的編碼。
需要注意的是,由于要攔截用戶訪問資源的所有請求,因此需要將 CharacterFilter 映射信息中 元素攔截的路徑設(shè)置為“/*”,如下所示:
<filter>
<filter-name>CharacterFilter</filter-name>
<filter-class>com.mengma.filter.CharacterFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
4、運(yùn)行項(xiàng)目并查看結(jié)果
啟動 Tomcat 服務(wù)器,在瀏覽器的地址欄中輸入地址 http://localhost:8080/filterDemo01/form.jsp,此時,瀏覽器窗口中會顯示一個用戶登錄的表單,在這個表單中輸入用戶名“張三”和密碼“1234”,如圖 1 所示。
圖 1 運(yùn)行結(jié)果
單擊圖 1 中的【登錄】按鈕提交表單,此時,MyEclipse 控制臺顯示的結(jié)果如圖 2 所示。
圖 2 控制臺窗口
從圖 2 中可以看出,form.jsp 表單中輸入的信息已經(jīng)顯示在了控制臺窗口中,而且中文的用戶名也沒有出現(xiàn)亂碼。需要注意的是,由于 form.jsp 表單的提交方式是 POST,因此可以說明使用 CharacterFilter 類可以解決 POST 提交方式的中文亂碼問題。
接下來驗(yàn)證 GET 方式提交表單的亂碼問題是否可以解決。單擊圖 1 中的“單擊超鏈接登錄”鏈接后(這種提交方式相當(dāng)于 GET 方式提交信息),MyEclipse 控制臺窗口顯示的結(jié)果同樣如圖 2 所示。因此可以說明,使用 CharacterFilter 類可以解決 GET 提交方式的中文亂碼問題。