注意:

從Tomcat8開始,默認編碼已經改為UTF-8,所以已經不會出現Get請求亂碼問題了。只需處理Post亂碼。

我們往常對亂碼的處理都放在Servlet的doGet和doPost方法中:

這個案例採用的Tomcat7

但是這樣太麻煩了,每寫一個Servlet都要處理亂碼。於是就想到用Filter處理。我能想到的有兩種處理方式:裝飾者模式、動態代理。

裝飾者模式處理亂碼的方案大家可以直接看崔老師的視頻:

案例3:全站編碼問題

這裡主要講動態代理方式。


Filter+動態代理解決全站編碼問題

對動態代理不熟悉的朋友,可以參考:Java 動態代理作用是什麼?

web.xml

<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--編碼過濾器-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.summerframework.web.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<!--測試Servlet-->
<servlet>
<servlet-name>TestServlet</servlet-name>
<servlet-class>org.summerframework.web.servlet.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>TestServlet</servlet-name>
<url-pattern>/TestServlet</url-pattern>
</servlet-mapping>
</web-app>

TestServlet

public class TestServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
System.out.println(username);
response.getWriter().write(username);
}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
System.out.println(username);
response.getWriter().write(username);
}
}

CharacterEncodingFilter

public class CharacterEncodingFilter implements Filter {
public void destroy() {
}

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {

// 【響應編碼設置】後面Servlet拿到的Response對象都是已經設置過編碼的
res.setContentType("text/html;charset=utf-8");

/*
* 【請求編碼設置】思路:
*
* 1.特別注意,這裡的request/response類型是ServletRequest/ServletResponse,我們要強轉成Http相關的
*
*
* 2.Filter傳給後面Servlet的Request對象肯定不能是原先的,不然request.getParameter()還是會亂碼
* 這裡使用動態代理生成代理對象,所以後面Servlet拿到的其實是代理Request
*
* 3.對於Get、Post請求,解決亂碼的方式是不同的,所以代理對象內部必須有針對兩者的判斷
* */

// 1.強轉req/res 【思考一下為什麼要加final】
final HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;

// 2.使用Proxy.newProxyInstance()創建Request代理對象
Object proxyRequest = Proxy.newProxyInstance(
this.getClass().getClassLoader(), /*類載入器*/
req.getClass().getInterfaces(), /*代理對象要和目標對象實現相同介面*/
new InvocationHandler() { /*InvocationHandler,採用匿名內部類的方式*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 由於亂碼的根源在於getParameter(),所以我們只盯著這個方法
if (!"getParameter".equalsIgnoreCase(method.getName())) {
return method.invoke(request, args);
}

// 3.判斷是Get還是Post
if ("GET".equalsIgnoreCase(request.getMethod())) {
// 按默認編碼ISO-8859-1取出
String value = (String) method.invoke(request, args);
// 按IOS-8859-1得到位元組,再按UTF-8轉成中文
value = new String(value.getBytes("ISO-8859-1"), "UTF-8");
// 返回正確的中文
return value;
} else {
// 目標方法前設置編碼
request.setCharacterEncoding("UTF-8");
Object value = method.invoke(request, args);
return value;
}

}
});
//把代理request對象傳給Servlet
chain.doFilter((HttpServletRequest) proxyRequest, res);
}

public void init(FilterConfig config) throws ServletException {

}

}

index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>

<a href="/TestServlet?username=張三">點擊發送Get請求</a><br/>

<form action="/TestServlet" method="post">
用戶名:<input type="text" name="username" value="李四"/>
<input type="submit" value="提交Post請求">
</form>

</body>
</html>

示意圖:

推薦閱讀:

相關文章