spring中解决中文乱码问题,是CharacterEncodingFilter通过拦截器解决的 我们来看一下这个拦截器的源码。
public class CharacterEncodingFilter extends OncePerRequestFilter {
//编码格式
@Nullable
private String encoding;
// 请求参数是否使用encoding属性设置的编码格式
private boolean forceRequestEncoding;
// 返回参数是否使用encoding属性设置的编码格式
private boolean forceResponseEncoding;
// 过滤器中会执行的方法
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String encoding = this.getEncoding();
if (encoding != null) {
// 设置请求参数的编码格式
if (this.isForceRequestEncoding() || request.getCharacterEncoding() == null) {
request.setCharacterEncoding(encoding);
}
// 设置返回参数的编码格式
if (this.isForceResponseEncoding()) {
response.setCharacterEncoding(encoding);
}
}
filterChain.doFilter(request, response);
}
}
通过上面的源码可以得出,encoding是没有默认值的,所以需要我们自己指定编码格式,一般前后端约定好就行,通常是utf-8 来看下springMvc中如何指定编码格式。 springMvc项目过滤器需要在web.xml中配置
<filter>
<filter-name>encodingFilter</filter-name> spring内置的过滤器
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name> 指定参数的格式为utf-8
<param-value>UTF8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name> 请求参数和返回参数都是使用上面设置的编码格式
<param-value>true</param-value>
</init-param>
</filter>
有些朋友看到这里可能会很奇怪,CharacterEncodingFilter中根本没有forceEncoding这个属性啊。哈哈,我开始也是一脸懵逼,怎么可以这样设置。后来发现,CharacterEncodingFilter中有下面两个构造方法
// 很明显web.xml中的配置是通过这个构造方法,为三个属性赋值
public CharacterEncodingFilter(String encoding, boolean forceEncoding) {
this(encoding, forceEncoding, forceEncoding);
}
public CharacterEncodingFilter(String encoding, boolean forceRequestEncoding, boolean forceResponseEncoding) {
this.forceRequestEncoding = false;
this.forceResponseEncoding = false;
Assert.hasLength(encoding, "Encoding must not be empty");
this.encoding = encoding;
this.forceRequestEncoding = forceRequestEncoding;
this.forceResponseEncoding = forceResponseEncoding;
}
下面再看看springBoot项目中怎样解决参数中文乱码问题吧。 大家应该都知道,不就是在yml或者properties配置文件中加一个配置嘛。对的加如下配置,已yml为例
spring:
http:
encoding:
force: true
charset: UTF-8
enabled: true
至于为什么加这个配置就行了,才是我们要弄懂的重点啊。 大家都知道,springBoot的自动装配吧。会在容器启动的时候将很多配置类加载到ioc容器中。 下面我们来看看这个配置类HttpEncodingAutoConfiguration
这里是简化后的源码,只留下了与编码问题相关的
// 表示这是一个配置类,和以前编写的配置文件一样,也可以给容器中添加组件
@Configuration(proxyBeanMethods = false)
// 启动指定类的ConfigurationProperties功能;将配置文件中对应的值和HttpProperties中的属性映射
@EnableConfigurationProperties(HttpProperties.class)
// 判断当前项目有没有这个CharacterEncodingFilter : SpringMVC中进行乱码解决的过滤器
@ConditionalOnClass(CharacterEncodingFilter.class)
public class HttpEncodingAutoConfiguration {
// 它已经和SpringBoot配置文件中的值进行映射了
private final HttpProperties.Encoding properties;
// 只有一个有参构造器的情况下,参数的值就会从容器中拿
public HttpEncodingAutoConfiguration(HttpProperties properties) {
this.properties = properties.getEncoding();
}
@Bean //给容器中添加一个组件,这个组件中的某些值需要从properties中获取
@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;
}
}
@EnableConfigurationProperties注解,会将配置文件中的属性值,映射到HttpProperties类中 至于注解怎样实现这些功能的,暂时不做研究
HttpProperties代码如下
@ConfigurationProperties(prefix = "spring.http")
public class HttpProperties {
private boolean logRequestDetails;
private final Encoding encoding = new Encoding();
public boolean isLogRequestDetails() {
return this.logRequestDetails;
}
public void setLogRequestDetails(boolean logRequestDetails) {
this.logRequestDetails = logRequestDetails;
}
public Encoding getEncoding() {
return this.encoding;
}
/**
* Configuration properties for http encoding.
*/
public static class Encoding {
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
private Charset charset = DEFAULT_CHARSET;
private Boolean force;
private Boolean forceRequest;
private Boolean forceResponse;
private Map<Locale, Charset> mapping;
public boolean shouldForce(Type type) {
Boolean force = (type != Type.REQUEST) ? this.forceResponse : this.forceRequest;
if (force == null) {
force = this.force;
}
if (force == null) {
force = (type == Type.REQUEST);
}
return force;
}
public enum Type {
REQUEST, RESPONSE
}
}
看了HttpProperties中的属性,你应该会发现这些属性就是我们在配置文件中配置的属性。并且默认utf-8. 给这些属性赋值后,再来看看他们怎样与CharacterEncodingFilter关联。
下面这个方法可以找到答案
这个方法在HttpEncodingAutoConfiguration中,对CharacterEncodingFilter进行了实例化
this.properties就是HttpProperties.Encoding。shouldForce是里面一个方法。代码在上面
@Bean //给容器中添加一个组件,这个组件中的某些值需要从properties中获取
@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;
}
好了,这配置的时候不会很懵逼,不知道为什么要这样配置了