1. 程式人生 > >過濾器-解決全站字元亂碼(POST和GET中文編碼問題)

過濾器-解決全站字元亂碼(POST和GET中文編碼問題)

servlet:

  1. POST:request.setCharacterEncoding(“utf-8”);
  2. GET:
  • String username = request.getParameter(“username”);
  • username = new String(username.getBytes(“ISO-8859-1”), “utf-8”);

1 說明

亂碼問題:

  1. 獲取請求引數中的亂碼問題;
  • POST請求:request.setCharacterEncoding(“utf-8”);
  • GET請求:new String(request.getParameter(“xxx”).getBytes(“iso-8859-1”), “utf-8”);
  1. 響應的亂碼問題: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 {

this.getInitParameter("charset");[崔1] 

if(charset == null || charset.isEmpty()) {

           charset = "UTF-8";

       }

       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物件進行增強的手段:

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

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

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

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

3 程式碼

EncodingRequest

public class EncodingRequest extends[崔5] {

    private String charset;

    public[崔6] (HttpServletRequest request, String charset) {

       super(request);

       this.charset = charset;

    }

    public[崔7] (String name) {

       HttpServletRequest request [崔8] = (HttpServletRequest) getRequest();

       if(method.equalsIgnoreCase("post[崔10] ")) {

           try {

           } catch (UnsupportedEncodingException e) {}

       } else if(method.equalsIgnoreCase("get[崔12] ")) {

           try {

new String(name.getBytes("ISO-8859-1"), charset);[崔14] 

           } catch (UnsupportedEncodingException e) {

           }

           return value[崔15] ;

       }

       return request.getParameter(name);

    }

}

EncodingFilter

public class EncodingFilter extends HttpFilter {

    public void doFilter(HttpServletRequest request,

           HttpServletResponse response, FilterChain chain)

           throws IOException, ServletException {

this.getInitParameter("charset");[崔16] 

       if(charset == null || charset.isEmpty()) {

           charset = "UTF-8";

       }[崔17] 

       response.setCharacterEncoding(charset);

       response.setContentType("text/html;charset=" + charset);

new EncodingRequest(request, charset);[崔18] 

    }

}

web.xml

  <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>