注意:從Tomcat8開始,默認編碼已經改為UTF-8,所以已經不會出現Get請求亂碼問題了。只需處理Post亂碼。
注意:
我們往常對亂碼的處理都放在Servlet的doGet和doPost方法中:
但是這樣太麻煩了,每寫一個Servlet都要處理亂碼。於是就想到用Filter處理。我能想到的有兩種處理方式:裝飾者模式、動態代理。
裝飾者模式處理亂碼的方案大家可以直接看崔老師的視頻:
案例3:全站編碼問題
這裡主要講動態代理方式。
對動態代理不熟悉的朋友,可以參考: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>
示意圖:
推薦閱讀: