感謝:http://blog.csdn.net/heidan2006/article/details/3075730web
很簡單很實用的一個過濾器,當前臺JSP頁面和JAVA代碼中使用了不一樣的字符集進行編碼的時候就會出現表單提交的數據或者上傳/下載中文名稱文件出現亂碼的問題,那這個類就能夠出場了。spring
從名字就能夠看出來它是個過濾器了,因此就要想配置普經過濾器那樣配置到web.xml中去了,配置方式以下:app
- <filter>
- <filter-name>encodingFilter</filter-name>
- <filter-class>
- org.springframework.web.filter.CharacterEncodingFilter
- </filter-class>
- <init-param>
- <param-name>encoding</param-name>
- <param-value>UTF-8</param-value>
- </init-param>
- <init-param>
- <param-name>forceEncoding</param-name>
- <param-value>false</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>encodingFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
和普經過濾器配置沒什麼區別,就是多了兩個初始化參數,兩個參數的做用分別是:框架
encoding----->用來指定一個具體的字符集this
forceEncoding------->Spring的早期版本這個參數做用很單一,當request中已經被指定了一個字符集的時候是否再將用endcoding對應的字符集設置到request中去。舉個例子來講明,假如說過濾器就像上面那樣被配置到web.xml了,當請求被提交以後,過濾器會判斷request.getCharacterEncoding()是否爲null,若是是null那麼就會進行request.setCharacterEncoding("UTF-8")的操做,若是不是null那麼過濾器什麼也不會作。編碼
不過Spring目前得版本這個類的代碼已經被重構了,代碼更加「漂亮」了,這個參數的做用也發生了細微的改變。url
爲了加深印象從源碼來分析一下這個參數的變化。.net
首先,說明 一下CharacterEncodingFilter是繼承OncePerRequestFilter抽象類而來的,OncePerRequestFilter實現了doFilter方法:xml
- public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
- throws ServletException, IOException {
- ...........
- ...........
- String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
- if (request.getAttribute(alreadyFilteredAttributeName) != null || shouldNotFilter(httpRequest)) {
- filterChain.doFilter(request, response);
- }
- else {
- request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
- try {
- doFilterInternal(httpRequest, httpResponse, filterChain);
- }
- finally {
- request.removeAttribute(alreadyFilteredAttributeName);
- }
- }
- }
- public static final String ALREADY_FILTERED_SUFFIX = ".FILTERED";(在OncePerRequestFilter中定義的常量)
說明:blog
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中被實現的,實現以下:
- protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
- throws ServletException, IOException {
- if (this.encoding != null && (this.forceEncoding || request.getCharacterEncoding() == null)) {
- request.setCharacterEncoding(this.encoding);
- if (this.forceEncoding && responseSetCharacterEncodingAvailable) {
- response.setCharacterEncoding(this.encoding);
- }
- }
- filterChain.doFilter(request, response);
- }
- private final static boolean responseSetCharacterEncodingAvailable = ClassUtils.hasMethod(
- HttpServletResponse.class, "setCharacterEncoding", new Class[] {String.class});
說明:
1. 靜態常量responseSetCharacterEncodingAvailable 是經過反射來判斷response是否有setCharacterEncoding方法,返回值應該都是true.
2. this.encoding != null :當encoding初始化參數被指定時條件知足。
3. (this.forceEncoding || request.getCharacterEncoding() == null )==true:當forceEncoding初始化參數設置爲true或者request已經被指定了一個字符編碼的時候條件知足。
若是沒記得錯,Spring早期版本這個方法得實現應該是:
- protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
- throws ServletException, IOException {
- if (this.forceEncoding || request.getCharacterEncoding() == null) {
- request.setCharacterEncoding(this.encoding);
- }
- filterChain.doFilter(request, response);
- }
參數forceEncoding的做用很明顯了吧!之前只是對request字符編碼起做用,如今若是將forceEncoding設爲true也會影響到response中的字符編碼,一般這個是咱們不但願的。
總結:
1. OncePerRequestFilter這個抽象過濾器很好的實現了對每一個request只執行一次過濾操做,若是有相似的需求能夠繼承該類並實現doFilterInternal方法來完成。
2. CharacterEncodingFilter類能夠經過簡單配置來幫咱們實現字符集轉換的功能。另外多說一句,若是採用Struts2.0的MVC框架我我的感受中文問題已經不是問題了,能夠經過配置struts.i18n.encoding常量來實現統一字符編碼。