感谢: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常量来实现统一字符编码。