通過HttpServletRequestWrapper(裝飾模式的應用)增強HttpServletRequest,實現解決get方式的中文亂碼...

轉自http://whistler.iteye.com/blog/483158

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

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

 

過濾器代碼:

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

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import wrapper.GetHttpServletRequestWrapper;

public class ContentTypeFilter implements Filter {

	private String charset = "UTF-8";
	private FilterConfig config;
	
	public void destroy() {
        System.out.println(config.getFilterName()+"被銷燬");
		charset = null;
		config = null;
	}

	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
        //設置請求響應字符編碼
		request.setCharacterEncoding(charset);
		response.setCharacterEncoding(charset);
		
        HttpServletRequest req = (HttpServletRequest)request;
		
		
		System.out.println("----請求被"+config.getFilterName()+"過濾");
		//執行下一個過濾器(如果有的話,否則執行目標servlet)
		chain.doFilter(req, response);
		
		System.out.println("----響應被"+config.getFilterName()+"過濾");

	}

	public void init(FilterConfig config) throws ServletException {
		    this.config = config;
            String charset = config.getServletContext().getInitParameter("charset");  
            if( charset != null && charset.trim().length() != 0)
            {
            	this.charset = charset;
            }
	}

}

 

 

web.xml中過濾器配置:

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

	<filter>
		<filter-name>ContentTypeFilter</filter-name>
		<filter-class>filter.ContentTypeFilter</filter-class>
	</filter>

	<filter-mapping>
		<filter-name>ContentTypeFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</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字段中的參數不起作用,我們通常通過下面的代碼來完成編碼轉換:

 

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

 

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

 

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

 

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

 

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

 

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

 

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

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class GetHttpServletRequestWrapper extends HttpServletRequestWrapper {

	private String charset = "UTF-8";

	public GetHttpServletRequestWrapper(HttpServletRequest request) {
		super(request);
	}

	/**
	 * 獲得被裝飾對象的引用和採用的字符編碼
	 * @param request
	 * @param charset
	 */
	public GetHttpServletRequestWrapper(HttpServletRequest request,
			String charset) {
		super(request);
		this.charset = charset;
	}

	/**
	 * 實際上就是調用被包裝的請求對象的getParameter方法獲得參數,然後再進行編碼轉換
	 */
	public String getParameter(String name) {
		String value = super.getParameter(name);
		value = value == null ? null : convert(value);
		return value;
	}

	public String convert(String target) {
		System.out.println("編碼轉換之前:" + target);
		try {
			return new String(target.trim().getBytes("ISO-8859-1"), charset);
		} catch (UnsupportedEncodingException e) {
			return target;
		}
	}

}

 

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

Java代碼 複製代碼
  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.            
  9.         if(req.getMethod().equalsIgnoreCase("get"))   
  10.         {   
  11.             req = new GetHttpServletRequestWrapper(req,charset);   
  12.         }   
  13.            
  14.         System.out.println("----請求被"+config.getFilterName()+"過濾");   
  15.         //傳遞給目標servlet或jsp的實際上時包裝器對象的引用,而不是原始的HttpServletRequest對象   
  16.         chain.doFilter(req, response);   
  17.            
  18.         System.out.println("----響應被"+config.getFilterName()+"過濾");   
  19.   
  20.     }  
public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
        //設置請求響應字符編碼
		request.setCharacterEncoding(charset);
		response.setCharacterEncoding(charset);
        //新增加的代碼		
        HttpServletRequest req = (HttpServletRequest)request;
		
        if(req.getMethod().equalsIgnoreCase("get"))
        {
        	req = new GetHttpServletRequestWrapper(req,charset);
        }
		
		System.out.println("----請求被"+config.getFilterName()+"過濾");
		//傳遞給目標servlet或jsp的實際上時包裝器對象的引用,而不是原始的HttpServletRequest對象
		chain.doFilter(req, response);
		
		System.out.println("----響應被"+config.getFilterName()+"過濾");

	}

 

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

 

這是我講課時的一個例子,不對之處,敬請指教,以免誤人子弟啊。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章