在 SSM 框架中,通常会在 web.xml 中配置编码过滤器 CharacterEncodingFilter,但在 Spring Boot 应用中却没有要求人为配置编码过滤器,是因为 Spring Boot 基于 习惯优于配置 的原则,默认情况下自动配置了编码过滤器,采用的 UTF-8 编码。
本篇分析 Spring Boot 的编码过滤器的自动配置,也更详细的理解和体会 Spring Boot 自动配置的使用。
在 spring-boot-start 包默认依赖了 spring-boot-aotuconfig 包,Spring Boot 默认支持的组件的自动配置全在 spring-boot-aotuconfig 包里面,只要引入这些组件就可以基于很少的配置来使用。
HTTP编码属性配置
自动配置少不了属性配置类,在 org.springframework.boot.autoconfigure.http 包下有个 HttpEncodingProperties 的属性配置类,原码及解读如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| @ConfigurationProperties(prefix = "spring.http.encoding") public class HttpEncodingProperties {
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 Charset getCharset() { return this.charset; }
public void setCharset(Charset charset) { this.charset = charset; }
public boolean isForce() { return Boolean.TRUE.equals(this.force); }
public void setForce(boolean force) { this.force = force; }
public boolean isForceRequest() { return Boolean.TRUE.equals(this.forceRequest); }
public void setForceRequest(boolean forceRequest) { this.forceRequest = forceRequest; }
public boolean isForceResponse() { return Boolean.TRUE.equals(this.forceResponse); }
public void setForceResponse(boolean forceResponse) { this.forceResponse = forceResponse; }
public Map<Locale, Charset> getMapping() { return this.mapping; }
public void setMapping(Map<Locale, Charset> mapping) { this.mapping = 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 } }
|
也可在 application.properties 配置文件使用 spring.http.encoding 前缀指定编码格式:
1 2
| spring.http.encoding.charset=UTF-8 spring.http.encoding.force=true
|
HTTP编码自动配置
编码过滤器的类 CharacterEncodingFilter 还是要用到的,自动配置类里注入了属性配置类,用于给编码过滤器设置参数并将 CharacterEncodingFilter 注册为 Bean。
Http 编码自动配置类在 org.springframework.boot.autoconfigure.web.servlet 包下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| @Configuration
@EnableConfigurationProperties(HttpEncodingProperties.class) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true) public class HttpEncodingAutoConfiguration {
private final HttpEncodingProperties properties; public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) { this.properties = properties; }
@Bean @ConditionalOnMissingBean(CharacterEncodingFilter.class) 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; } }
|
字符编码过滤器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| public class CharacterEncodingFilter extends OncePerRequestFilter {
@Nullable private String encoding;
private boolean forceRequestEncoding = false;
private boolean forceResponseEncoding = false;
public CharacterEncodingFilter() { }
public CharacterEncodingFilter(String encoding) { this(encoding, false); }
public CharacterEncodingFilter(String encoding, boolean forceEncoding) { this(encoding, forceEncoding, forceEncoding); }
public CharacterEncodingFilter(String encoding, boolean forceRequestEncoding, boolean forceResponseEncoding) { Assert.hasLength(encoding, "Encoding must not be empty"); this.encoding = encoding; this.forceRequestEncoding = forceRequestEncoding; this.forceResponseEncoding = forceResponseEncoding; }
public void setEncoding(@Nullable String encoding) { this.encoding = encoding; }
@Nullable public String getEncoding() { return this.encoding; }
public void setForceEncoding(boolean forceEncoding) { this.forceRequestEncoding = forceEncoding; this.forceResponseEncoding = forceEncoding; }
public void setForceRequestEncoding(boolean forceRequestEncoding) { this.forceRequestEncoding = forceRequestEncoding; }
public boolean isForceRequestEncoding() { return this.forceRequestEncoding; }
public void setForceResponseEncoding(boolean forceResponseEncoding) { this.forceResponseEncoding = forceResponseEncoding; }
public boolean isForceResponseEncoding() { return this.forceResponseEncoding; }
@Override protected void doFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String encoding = getEncoding(); if (encoding != null) { if (isForceRequestEncoding() || request.getCharacterEncoding() == null) { request.setCharacterEncoding(encoding); } if (isForceResponseEncoding()) { response.setCharacterEncoding(encoding); } } filterChain.doFilter(request, response); } }
|