CharacterEncodingFilter作用

很簡單很實用的一個過濾器,當前臺JSP頁面和JAVA代碼中使用了不同的字符集進行編碼的時候就會出現表單提交的數據或者上傳/下載中文名稱文件出現亂碼的問題,那這個類就可以出場了。

        從名字就可以看出來它是個過濾器了,所以就要想配置普通過濾器那樣配置到web.xml中去了,配置方式如下:

1.        <filter>
2.                <filter-name>encodingFilter</filter-name>
3.                    <filter-class>
4.                        org.springframework.web.filter.CharacterEncodingFilter
5.                    </filter-class>
6.                <init-param>
7.                    <param-name>encoding</param-name>
8.                    <param-value>UTF-8</param-value>
9.                </init-param>
10.                <init-param>
11.                    <param-name>forceEncoding</param-name>
12.                    <param-value>false</param-value>
13.               </init-param>
14.        </filter>
15.16.        <filter-mapping>
17.                <filter-name>encodingFilter</filter-name>
18.                <url-pattern>/*</url-pattern>
19.       </filter-mapping>
20.        和普通過濾器配置沒什麼區別,就是多了兩個初始化參數,兩個參數的作用分別是:

    encoding----->用來指定一個具體的字符集

    forceEncoding------->Spring的早期版本這個參數作用很單一,當request中已經被指定了一個字符集的時候是否再將用endcoding對應的字符集設置到request中去。舉個例子來說明,假如說過濾器就像上面那樣被配置到web.xml了,當請求被提交之後,過濾器會判斷request.getCharacterEncoding()是否爲null,如果是null那麼就會進行request.setCharacterEncoding("UTF-8")的操作,如果不是null那麼過濾器什麼也不會做。

    不過Spring目前得版本這個類的代碼已經被重構了,代碼更加“漂亮”了,這個參數的作用也發生了細微的改變。

    爲了加深印象從源碼來分析一下這個參數的變化。

    首先,說明 一下CharacterEncodingFilter是繼承OncePerRequestFilter抽象類而來的,OncePerRequestFilter實現了doFilter方法:

1. public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
2.   throws ServletException, IOException {
3.4.         ...........
5.6.         ...........
7.8.      String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
9.      if (request.getAttribute(alreadyFilteredAttributeName) != null || shouldNotFilter(httpRequest)) {
10.11.           filterChain.doFilter(request, response);
12.      }
13.      else {
14.           request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
15.       try {
16.            doFilterInternal(httpRequest, httpResponse, filterChain);
17.           }
18.       finally {
19.20.            request.removeAttribute(alreadyFilteredAttributeName);
21.           }
22.      }
23. }
24.25.public static final String ALREADY_FILTERED_SUFFIX = ".FILTERED";(在OncePerRequestFilter中定義的常量)
26.說明:

1. getAlreadyFilteredAttributeName()方法返回的字符串是="我們給filter配置的名字+ALREADY_FILTERED_SUFFIX",所以request請求第一次到達過濾器的時候request.getAttribute(alreadyFilteredAttributeName) 值一定是null ,shouldNotFilter(httpRequest)方法默認實現始終返回false(這個方法也可以在子類中進行擴展);

2. 當request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE)之後就會執行doFilterInternal(httpRequest, httpResponse, filterChain);方法了,doFilterInternal這裏是個抽象方法,它是在子類CharacterEncodingFilter中被實現的,實現如下:

1. protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
2.   throws ServletException, IOException {
3.4.         if (this.encoding != null && (this.forceEncoding || request.getCharacterEncoding() == null)) {
5.                request.setCharacterEncoding(this.encoding);
6.               if (this.forceEncoding && responseSetCharacterEncodingAvailable) {
7.                    response.setCharacterEncoding(this.encoding);
8.                   }
9.              }
10.              filterChain.doFilter(request, response);
11.  }
12.13.private final static boolean responseSetCharacterEncodingAvailable = ClassUtils.hasMethod(
14.   HttpServletResponse.class, "setCharacterEncoding", new Class[] {String.class});
15.說明:

1. 靜態常量responseSetCharacterEncodingAvailable 是通過反射來判斷response是否有setCharacterEncoding方法,返回值應該都是true.

2. this.encoding != null :當encoding初始化參數被指定時條件滿足。

3. (this.forceEncoding || request.getCharacterEncoding() == null )==true:當forceEncoding初始化參數設置爲true或者request已經被指定了一個字符編碼的時候條件滿足。

如果沒記得錯,Spring早期版本這個方法得實現應該是:

1. protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
2.   throws ServletException, IOException {
3.4.         if (this.forceEncoding || request.getCharacterEncoding() == null) {
5.                   request.setCharacterEncoding(this.encoding);
6.              }
7.              filterChain.doFilter(request, response);
8.  }
9.參數forceEncoding的作用很明顯了吧!以前只是對request字符編碼起作用,現在如果將forceEncoding設爲true也會影響到response中的字符編碼,通常這個是我們不希望的。

總結:

1.  OncePerRequestFilter這個抽象過濾器很好的實現了對每個request只執行一次過濾操作,如果有類似的需求可以繼承該類並實現doFilterInternal方法來完成。

2.  CharacterEncodingFilter類可以通過簡單配置來幫我們實現字符集轉換的功能。另外多說一句,如果採用Struts2.0的MVC框架我個人感覺中文問題已經不是問題了,可以通過配置struts.i18n.encoding常量來實現統一字符編碼。

說明:所寫內容純屬個人理解和認識,如有理解偏差希望有熱心的朋友可以指出,如有描述有含糊不清的地方希望可以和你得到溝通和交流!

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