Java web----POST和GET中文編碼問題

1 說明

亂碼問題:

獲取請求參數中的亂碼問題;

  • POST請求:request.setCharacterEncoding(“utf-8”);
  • GET請求:newString(request.getParameter(“xxx”).getBytes(“iso-8859-1”), “utf-8”);

響應的亂碼問題:response.setContextType(“text/html;charset=utf-8”)。

基本上在每個Servlet中都要處理亂碼問題,所以應該把這個工作放到過濾器中來完成。

2 分析

其實全站亂碼問題的難點就是處理GET請求參數的問題。

如果只是處理POST請求的編碼問題,以及響應編碼問題,那麼這個過濾器就太!太!太簡單的

public class EncodingFilter extends HttpFilter {
	public void doFilter(HttpServletRequest request,
			HttpServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		String charset = this.getInitParameter("charset");
		if(charset == null || charset.isEmpty()) {
			charset = "UTF-8";
		}
		request.setCharacterEncoding(charset);
		response.setContentType("text/html;charset=" + charset);
		chain.doFilter(request, response);
	}
}

如果是POST請求,當執行目標Servlet時,Servlet中調用request.getParameter()方法時,就會根據request.setCharacterEncoding()設置的編碼來轉碼!這說明在過濾器中調用request.setCharacterEncoding()方法會影響在目標Servlet中的request.getParameter()方法的行爲!

但是如果是GET請求,我們又如何能影響request.getParameter()方法的行爲呢?這是不好做到的!我們不可能先調用request.getParameter()方法獲取參數,然後手動轉碼後,再施加在到request中!因爲request只有getParameter(),而沒有setParameter()方法。 

處理GET請求參數編碼問題,需要在Filter中放行時,把request對象給“調包”了,也就是讓目標Servlet使用我們“調包”之後的request對象。這說明我們需要保證“調包”之後的request對象中所有方法都要與“調包”之前一樣可以使用,並且getParameter()方法還要有能力返回轉碼之後的參數。

這可能讓你想起了“繼承”,但是這裏不能用繼承,而是“裝飾者模式(Decorator Pattern)”!

下面是三種對a對象進行增強的手段:

  • 繼承:AA類繼承a對象的類型:A類,然後重寫fun1()方法,其中重寫的fun1()方法就是被增強的方法。但是,繼承必須要知道a對象的真實類型,然後才能去繼承。如果我們不知道a對象的確切類型,而只知道a對象是IA接口的實現類對象,那麼就無法使用繼承來增強a對象了;
  • 裝飾者模式:AA類去實現a對象相同的接口:IA接口,還需要給AA類傳遞a對象,然後在AA類中所有的方法實現都是通過代理a對象的相同方法完成的,只有fun1()方法在代理a對象相同方法的前後添加了一些內容,這就是對fun1()方法進行了增強;
  • 動態代理:動態代理與裝飾者模式比較相似,而且是通過反射來完成的。動態代理會在最後一天的基礎加強中講解,這裏就不再廢話了。

對request對象進行增強的條件,剛好符合裝飾者模式的特點!因爲我們不知道request對象的具體類型,但我們知道request是HttpServletRequest接口的實現類。這說明我們寫一個類EncodingRequest,去實現HttpServletRequest接口,然後再把原來的request傳遞給EncodingRequest類!在EncodingRequest中對HttpServletRequest接口中的所有方法的實現都是通過代理原來的request對象來完成的,只有對getParameter()方法添加了增強代碼!

JavaEE已經給我們提供了一個HttpServletRequestWrapper類,它就是HttpServletRequest的包裝類,但它做任何的增強!你可能會說,寫一個裝飾類,但不做增強,其目的是什麼呢?使用這個裝飾類的對象,和使用原有的request有什麼分別呢?

HttpServletRequestWrapper類雖然是HttpServletRequest的裝飾類,但它不是用來直接使用的,而是用來讓我們去繼承的!當我們想寫一個裝飾類時,還要對所有不需要增強的方法做一次實現是很心煩的事情,但如果你去繼承HttpServletRequestWrapper類,那麼就只需要重寫需要增強的方法即可了。

3 代碼

public class EncodingRequest extends HttpServletRequestWrapper {
	private String charset;
	public EncodingRequest(HttpServletRequest request, String charset) {
		super(request);
		this.charset = charset;
	}

	public String getParameter(String name) {
		HttpServletRequest request = (HttpServletRequest) getRequest();
		
		String method = request.getMethod();
		if(method.equalsIgnoreCase("post")) {
			try {
				request.setCharacterEncoding(charset);
			} catch (UnsupportedEncodingException e) {}
		} else if(method.equalsIgnoreCase("get")) {
			String value = request.getParameter(name);
			try {
				value = new String(name.getBytes("ISO-8859-1"), charset);
			} catch (UnsupportedEncodingException e) {
			}
			return value;
		}
		return request.getParameter(name);
	}
}

public class EncodingFilter extends HttpFilter {
	public void doFilter(HttpServletRequest request,
			HttpServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		String charset = this.getInitParameter("charset");
		if(charset == null || charset.isEmpty()) {
			charset = "UTF-8";
		}
		response.setCharacterEncoding(charset);
		response.setContentType("text/html;charset=" + charset);
		EncodingRequest res = new EncodingRequest(request, charset);
		chain.doFilter(res, response);
	}
}

  <filter>
  	<filter-name>EncodingFilter</filter-name>
  	<filter-class>cn.itcast.filter.EncodingFilter</filter-class>
  	<init-param>
  		<param-name>charset</param-name>
  		<param-value>UTF-8</param-value>
  	</init-param>
  </filter>
  <filter-mapping>
  	<filter-name>EncodingFilter</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>


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