1. 程式人生 > >解決get方法傳遞URL引數中文亂碼問題

解決get方法傳遞URL引數中文亂碼問題

應用一:解決tomcat下中文亂碼問題(先來個簡單的) 

在tomcat下,我們通常這樣來解決中文亂碼問題:

過濾器程式碼:

  1. package filter;  
  2. import java.io.*;  
  3. import javax.servlet.*;  
  4. import javax.servlet.http.*;  
  5. import wrapper.GetHttpServletRequestWrapper;  
  6. public class ContentTypeFilter implements Filter {  
  7.     private String charset = "UTF-8";  
  8.     private FilterConfig config;  
  9.     public void destroy() {  
  10.         System.out.println(config.getFilterName()+"被銷燬");  
  11.         charset = null;  
  12.         config = null;  
  13.     }  
  14.     public void doFilter(ServletRequest request, ServletResponse response,  
  15.             FilterChain chain) throws IOException, ServletException {  
  16.         //設定請求響應字元編碼  
  17.         request.setCharacterEncoding(charset);  
  18.         response.setCharacterEncoding(charset);  
  19.         HttpServletRequest req = (HttpServletRequest)request;  
  20.         System.out.println("----請求被"+config.getFilterName()+"過濾");  
  21.         //執行下一個過濾器(如果有的話,否則執行目標servlet)  
  22.         chain.doFilter(req, response);  
  23.         System.out.println("----響應被"+config.getFilterName()+"過濾");  
  24.     }  
  25.     public void init(FilterConfig config) throws ServletException {  
  26.             this.config = config;  
  27.             String charset = config.getServletContext().getInitParameter("charset");    
  28.             if( charset != null && charset.trim().length() != 0)  
  29.             {  
  30.                 this.charset = charset;  
  31.             }  
  32.     }  
  33. }  

web.xml中過濾器配置:

  1. <!--將採用的字元編碼配置成應用初始化引數而不是過濾器私有的初始化引數是因為在JSP和其他地方也可能需要使用-->  
  2.     <context-param>  
  3.             <param-name>charset</param-name>  
  4.             <param-value>UTF-8</param-value>  
  5.     </context-param>  
  6.     <filter>  
  7.         <filter-name>ContentTypeFilter</filter-name>  
  8.         <filter-class>filter.ContentTypeFilter</filter-class>  
  9.     </filter>  
  10.     <filter-mapping>  
  11.         <filter-name>ContentTypeFilter</filter-name>  
  12.         <url-pattern>/*</url-pattern>  
  13.     </filter-mapping>  

request.setCharacterEncoding(charset); 必須寫在第一次使用request.getParameter()之前,這樣才能保證引數是按照已經設定的字元編碼來獲取。
response.setCharacterEncoding(charset);必須寫在PrintWriter out = request.getWriter()之前,這樣才能保證out按照已經設定的字元編碼來進行字元輸出。

通過過濾器,我們可以保證在Servlet或JSP執行之前就設定好了請求和響應的字元編碼。

但是這樣並不能完全解決中文亂碼問題:

對於post請求,無論是“獲取引數環節”還是“輸出環節"都是沒問題的;

對於get請求,"輸出環節"沒有問題,但是"獲取引數環節"依然出現中文亂碼,所以在輸出時直接將亂碼輸出了。

原因是post請求和get請求存放參數位置是不同的:

post方式引數存放在請求資料包的訊息體中。get方式引數存放在請求資料包的請求行的URI欄位中,以?開始以param=value&parame2=value2的形式附加在URI欄位之後。而request.setCharacterEncoding(charset); 只對訊息體中的資料起作用,對於URI欄位中的引數不起作用,我們通常通過下面的程式碼來完成編碼轉換:

  1. String paramValue = request.getParameter("paramName");  
  2. paramValue = new String(paramValue.trim().getBytes("ISO-8859-1"), charset);  

但是每次進行這樣的轉換實在是很麻煩,有沒有統一的解決方案呢?

解決方案1: 在tomcat_home\conf\server.xml 中的Connector元素中設定URIEncoding屬性為合適的字元編碼

  1. <Connector port="8080" protocol="HTTP/1.1"   
  2.            connectionTimeout="20000"   
  3.            redirectPort="8443"   
  4.            URIEncoding="UTF-8"  
  5.  />  

這樣做的缺點是,同一個tomcat下的其他應用也將受到影響。而其每次部署時都需要類修改配置也很麻煩。

解決方案2:自定義請求包裝器包裝請求,將字元編碼轉換的工作新增到getParameter()方法中

  1. package wrapper;  
  2. import java.io.UnsupportedEncodingException;  
  3. import java.net.URLDecoder;  
  4. import javax.servlet.http.HttpServletRequest;  
  5. import javax.servlet.http.HttpServletRequestWrapper;  
  6. public class GetHttpServletRequestWrapper extends HttpServletRequestWrapper {  
  7.     private String charset = "UTF-8";  
  8.     public GetHttpServletRequestWrapper(HttpServletRequest request) {  
  9.         super(request);  
  10.     }  
  11.     /** 
  12.      * 獲得被裝飾物件的引用和採用的字元編碼 
  13.      * @param request 
  14.      * @param charset 
  15.      */  
  16.     public GetHttpServletRequestWrapper(HttpServletRequest request,  
  17.             String charset) {  
  18.         super(request);  
  19.         this.charset = charset;  
  20.     }  
  21.     /** 
  22.      * 實際上就是呼叫被包裝的請求物件的getParameter方法獲得引數,然後再進行編碼轉換 
  23.      */  
  24.     public String getParameter(String name) {  
  25.         String value = super.getParameter(name);  
  26.         value = value == null ? null : convert(value);  
  27.         return value;  
  28.     }  
  29.     public String convert(String target) {  
  30.         System.out.println("編碼轉換之前:" + target);  
  31.         try {  
  32.             return new String(target.trim().getBytes("ISO-8859-1"), charset);  
  33.         } catch (UnsupportedEncodingException e) {  
  34.             return target;  
  35.         }  
  36.     }  
  37. }  

修改過濾器的doFilter方法 程式碼如下:

  1. public void doFilter(ServletRequest request, ServletResponse response,  
  2.             FilterChain chain) throws IOException, ServletException {  
  3.         //設定請求響應字元編碼  
  4.         request.setCharacterEncoding(charset);  
  5.         response.setCharacterEncoding(charset);  
  6.         //新增加的程式碼          
  7.         HttpServletRequest req = (HttpServletRequest)request;  
  8.         if(req.getMethod().equalsIgnoreCase("get"))  
  9.         {  
  10.             req = new GetHttpServletRequestWrapper(req,charset);  
  11.         }  
  12.         System.out.println("----請求被"+config.getFilterName()+"過濾");  
  13.         //傳遞給目標servlet或jsp的實際上時包裝器物件的引用,而不是原始的HttpServletRequest物件  
  14.         chain.doFilter(req, response);  
  15.         System.out.println("----響應被"+config.getFilterName()+"過濾");  
  16.     }  

這樣一來,在servlet中呼叫包裝器的getParameters方法來獲取引數,就已經完成了字元編碼的轉換過程,我們就不需要在每次獲取引數時來進行字元編碼轉換了。

spring轉碼過濾器,在web.xml檔案中配置,

注意:filter是根據filter-mapping節點的順序來執行的,為了避免其他filter在這個filter之前執行,所以請將這個filter-mapping放到最前面