我们一般会配置CharacterEncodingFilter来解决中文编码乱码的问题
CharacterEncodingFilter:过滤器,解决请求编码和返回响应编码,继承了OncePerRequestFilter,重写了doFilterInternal方法
过滤器执行顺序:顺序就是filter Mapping的配置的先后顺序,filter的执行顺序就靠filter mapping在web.xml中的顺序,非web.xml中使用@Order指定执行顺序
<filter>
<filter-name>CharacterEncodingFilter</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>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
所以在非spring-boot的项目中,我们会这样建立过滤器
/**
* OncePerRequestFilter:比使用Filter更方便,不能在此处定义拦截请求,可在web.xml中配置
*/
@Component("test01Filter")
@Order(1)//使用@Order指定执行顺序,越小越优先
public class Test01Filter extends OncePerRequestFilter {
/**
* 该方法会执行两次:GenericFilterBean-afterPropertiesSet,GenericFilterBean-init
*/
重写doFilterInternal方法
}
而在spring boot有了更强大,更简化的写法
//不能加@Component注解,会多注册一个拦截所有请求的Filter
@Order(4) //过滤顺序,值越小越先执行
@WebFilter(urlPatterns = {"/testFilter"}, filterName = "test02Filter")
public class Test02Filter implements Filter {
重写doFilter方法,略
}
常见Filter分析
- 指定请求和响应编码:CharacterEncodingFilter
编码自动配置类:HttpEncodingAutoConfiguration
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
return filter;
}
可配置属性spring.http.encoding开启(默认开启),在spring boot中采取了自动配置的方式注入该拦截器(在spring-boot-autoconfigure包里的spring.factories中添加了此配置)
当然也可手动配置
@Bean
public FilterRegistrationBean<CharacterEncodingFilter> characterEncodingFilterRegister() {
FilterRegistrationBean<CharacterEncodingFilter> filterRegistrationBean = new FilterRegistrationBean<>();
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setForceEncoding(true);
characterEncodingFilter.setEncoding("UTF-8");
filterRegistrationBean.setFilter(characterEncodingFilter);
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
- 请求属性保存到上下文:RequestContextFilter
spring boot自动配置类:WebMvcAutoConfiguration
@Bean
@ConditionalOnMissingBean({ RequestContextListener.class, RequestContextFilter.class })
@ConditionalOnMissingFilterBean(RequestContextFilter.class)
public static RequestContextFilter requestContextFilter() {
return new OrderedRequestContextFilter();
}
注册了把RequestContextFilter包装成了带有顺序的OrderedRequestContextFilter,作用是把请求参数放到线程的TheadLocal中,而无需传递请求的参数,线程中存放了两个重要的对象:
org.springframework.context.i18n.LocaleContextHolder
org.springframework.web.context.request.RequestContextHolder
此外,使用RequestContextListener(For JSF…)或DispatcherServlet(默认暴露)也都能满足需求,区别是如果请求未到达DispatcherServlet而被拦截(如匿名对象访问需要权限的数据),则可使用RequestContextFilter,所以一般情况下无需手动注册该拦截器
注意:缺省情况下,Servlet容器对一个请求的整个处理过程,是由同一个线程完成的,中途不会切换线程。但这个线程在处理完一个请求后,会被放回到线程池用于处理其他请求。