前置知识
Content-Type
Content-Type(内容类型),常作用于HTTP消息头,表示内容编码类型。可以根据编码类型使用特定的解析方式,获取数据流中的数据。
Media Type
Media Type,即媒体类型,也叫做于MIME类型,有时在一些协议的消息头中叫做“Content-Type”。它使用两部分标识符来确定一个类型。在HTTP中,消息头Content-Type对应的值就可以叫做是Media Type。
Media Type对象包含了三种信息:type 、subtype、charset,比如下面表示这个数据流的媒体类型为:
- type值是text,表示是文本这一大类;
- / 后面的x-markdown是subtype,表示是文本这一大类下的markdown这一小类;
- charset=utf-8 则表示采用UTF-8编码
text/x-markdown; charset=utf-8
在Spring中,提供了MediaType类来表示媒体类型,提供了MediaType 类型的各种常量、字符串常量,表示各种媒体类型。
private static final long serialVersionUID = 2069937152339670231L;
// */* 支持所有的媒体类型
public static final MediaType ALL = new MediaType("*", "*");
public static final String ALL_VALUE = "*/*";
// Application:用于传输应用程序数据或者二进制数据;
// application/atom+xml Atom XML聚合格式
public static final MediaType APPLICATION_ATOM_XML = new MediaType("application", "atom+xml");
public static final String APPLICATION_ATOM_XML_VALUE = "application/atom+xml";
// application/cbor cbor类型二进制形式JSON格式
public static final MediaType APPLICATION_CBOR = new MediaType("application", "cbor");
public static final String APPLICATION_CBOR_VALUE = "application/cbor";
// application/x-www-form-urlencoded 即表单默认的数据提交格式,提交的数据以key=val形式编码,用&连接,如
public static final MediaType APPLICATION_FORM_URLENCODED = new MediaType("application", "x-www-form-urlencoded");
public static final String APPLICATION_FORM_URLENCODED_VALUE = "application/x-www-form-urlencoded";
// application/json JSON数据格式
public static final MediaType APPLICATION_JSON = new MediaType("application", "json");
public static final String APPLICATION_JSON_VALUE = "application/json";
// application/json;charset=UTF-8 指定为JSON格式,以UTF-8字符编码进行编码
/** @deprecated */
@Deprecated
public static final MediaType APPLICATION_JSON_UTF8;
/** @deprecated */
@Deprecated
public static final String APPLICATION_JSON_UTF8_VALUE = "application/json;charset=UTF-8";
// application/octet-stream 二进制流数据(如常见的文件下载)
public static final MediaType APPLICATION_OCTET_STREAM;
public static final String APPLICATION_OCTET_STREAM_VALUE = "application/octet-stream";
// application/pdf pdf格式
public static final MediaType APPLICATION_PDF;
public static final String APPLICATION_PDF_VALUE = "application/pdf";
// application/problem+json 错误信息Json格式
public static final MediaType APPLICATION_PROBLEM_JSON;
public static final String APPLICATION_PROBLEM_JSON_VALUE = "application/problem+json";
// application/problem+json;charset=UTF-8 错误信息Json格式,以UTF-8字符编码进行编码
/** @deprecated */
@Deprecated
public static final MediaType APPLICATION_PROBLEM_JSON_UTF8;
/** @deprecated */
@Deprecated
public static final String APPLICATION_PROBLEM_JSON_UTF8_VALUE = "application/problem+json;charset=UTF-8";
// application/problem+xml 错误信息XML格式
public static final MediaType APPLICATION_PROBLEM_XML;
public static final String APPLICATION_PROBLEM_XML_VALUE = "application/problem+xml";
// application/rss+xml RSS格式的XML文件
public static final MediaType APPLICATION_RSS_XML;
public static final String APPLICATION_RSS_XML_VALUE = "application/rss+xml";
// application/x-ndjson ndJSON的Json标准
public static final MediaType APPLICATION_NDJSON;
public static final String APPLICATION_NDJSON_VALUE = "application/x-ndjson";
/** @deprecated */
// application/stream+json JSON数据流
@Deprecated
public static final MediaType APPLICATION_STREAM_JSON;
/** @deprecated */
@Deprecated
public static final String APPLICATION_STREAM_JSON_VALUE = "application/stream+json";
// application/xhtml+xml XHTML系列文档的类型
public static final MediaType APPLICATION_XHTML_XML;
public static final String APPLICATION_XHTML_XML_VALUE = "application/xhtml+xml";
// application/xml XML数据格式
public static final MediaType APPLICATION_XML;
public static final String APPLICATION_XML_VALUE = "application/xml";
// 图片相关
// image/gif gif图片格式
public static final MediaType IMAGE_GIF;
public static final String IMAGE_GIF_VALUE = "image/gif";
// image/jpeg jpg图片格式
public static final MediaType IMAGE_JPEG;
public static final String IMAGE_JPEG_VALUE = "image/jpeg";
// image/png png图片格式
public static final MediaType IMAGE_PNG;
public static final String IMAGE_PNG_VALUE = "image/png";
// Multipart:用于连接消息体的多个部分构成一个消息,这些部分可以是不同类型的数据
// multipart/form-data 会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件
public static final MediaType MULTIPART_FORM_DATA;
public static final String MULTIPART_FORM_DATA_VALUE = "multipart/form-data";
// multipart/mixed 变成 Stream 流的方式
public static final MediaType MULTIPART_MIXED;
public static final String MULTIPART_MIXED_VALUE = "multipart/mixed";
// multipart/related 多种格式
public static final MediaType MULTIPART_RELATED;
public static final String MULTIPART_RELATED_VALUE = "multipart/related";
// Text:用于标准化地表示的文本信息,文本消息可以是多种字符集和或者多种格式
// text/event-stream 事件流
public static final MediaType TEXT_EVENT_STREAM;
public static final String TEXT_EVENT_STREAM_VALUE = "text/event-stream";
// text/html html格式文本
public static final MediaType TEXT_HTML;
public static final String TEXT_HTML_VALUE = "text/html";
// ext/markdown markdown格式文本
public static final MediaType TEXT_MARKDOWN;
public static final String TEXT_MARKDOWN_VALUE = "text/markdown";
// text/plain 纯文本格式
public static final MediaType TEXT_PLAIN;
public static final String TEXT_PLAIN_VALUE = "text/plain";
// text/xml XML格式文本
public static final MediaType TEXT_XML;
public static final String TEXT_XML_VALUE = "text/xml";
HttpMessageConverter使用fastjson
Spring MVC提供了很多消息转换器,在之前消息转换源码中我们分析到报文是由MappingJackson2HttpMessageConverter转换器进行转换的,其使用的是Jackson 2.X。
如果我们想使用fastjson该如何设置呢?
思路
默认转换器
之前分析,MVC会添加十个默认的转换器,我们了解下具体都是干嘛的,以下表格按照顺序排列。
转换器 | 支持的MediaType | 默认字符集 | 作用 |
---|---|---|---|
ByteArrayHttpMessageConverter | application/octet-stream;* / * | 无 | 读写字节数组 |
StringHttpMessageConverter | text/plain;* / * | UTF-8 | 读写字符串 |
StringHttpMessageConverter | text/plain;* / * | ISO-8859-1 | 读写字符串 |
ResourceHttpMessageConverter | * / * | 无 | 可以读/写 {@link Resource Resources} ,并支持字节范围请求 |
ResourceRegionHttpMessageConverter | * / * | 无 | 可以读取单个 {@link ResourceRegion} 或 {@link ResourceRegion } 的集合。 |
SourceHttpMessageConverter | application/xml;text/xml;application/*+xml | 无 | 可以读写 {@link Source} 对象 |
AllEncompassingFormHttpMessageConverter | application/x-www-form-urlencoded;multipart/form-data;multipart/mixed | UTF-8 | 添加对基于 XML 和 JSON 的部分的支持。对FormHttpMessageConverter的扩展 |
MappingJackson2HttpMessageConverter | application/json;application/*+json | 无 | Jackson 2.x 读取和 写入 JSON {@link ObjectMapper}。 |
MappingJackson2HttpMessageConverter | 重复了 | 重复了 | 重复了 |
Jaxb2RootElementHttpMessageConverter | application/xml;text/xml;application/*+xml | 无 | 可以使用 JAXB2 读写 XML |
WebMvcConfigurer配置类
spring MVC提供了WebMvcConfigurer接口,可以自定义配置类,实现configureMessageConverters或者extendMessageConverters就可以添加自定义消息转换器了。
/**
* 配置 {@link HttpMessageConverter HttpMessageConverter} 用于从请求报文读取和写入响应报文。
* 默认情况下,只要类路径中存在相应的第三方库,例如 Jackson JSON、JAXB2 和其他库,就会配置所有内置转换器。
* 使用此方法会关闭默认转换器注册。
*/
default void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
}
/**
* 扩展或修改转换器列表,请注意,转换器注册的顺序很重要。
* 特别是在客户端接受 {@link org.springframework.http.MediaType#ALL} 的情况下更早配置的转换器将是首选。
*/
default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
}
FastJsonHttpMessageConverter类
在fastjson中,默认已经实现了一个HttpMessageConverter消息转换器,直接拿来就可以使用了。
在FastJsonHttpMessageConverter,还可以设置FastJsonConfig,提供了更加丰富的功能。
我们可以通过FastJsonConfig配置序列化过滤器、序列化特性、特殊字段序列化等功能。
FastJsonConfig还可以配置SerializerFeature,用于对响应数据进行特殊处理,比如常用的有,时间格式化、null转空、Long转字符串等。
SerializerFeature类配置项如下:
public enum SerializerFeature {
// 输出key时是否使用双引号,默认为true
QuoteFieldNames,
// 使用单引号,默认为false
UseSingleQuotes,
// 是否输出值为null的字段,默认为false
WriteMapNullValue,
// 使用ToString写入枚举,默认为false
WriteEnumUsingToString,
// 使用名称写入枚举,默认为false
WriteEnumUsingName,
// Date使用ISO8601格式输出,默认为false
UseISO8601DateFormat,
// List字段如果为null,输出为[],而非null
WriteNullListAsEmpty,
// 字符类型字段如果为null,输出为"",而非null
WriteNullStringAsEmpty,
// 数值字段如果为null,输出为0,而非null
WriteNullNumberAsZero,
// Boolean字段如果为null,输出为false,而非null
WriteNullBooleanAsFalse,
// 如果是true,类中的Get方法对应的Field是transient,序列化时将会被忽略。默认为true
SkipTransientField,
// 按字段名称排序后输出。默认为false
SortField,
/** @deprecated */
@Deprecated
// 把\t做转义输出,默认为false
WriteTabAsSpecial,
// 结果是否格式化,默认为false
PrettyFormat,
// 序列化时写入类型信息,默认为false。反序列化是需用到
WriteClassName,
// 消除对同一对象循环引用的问题,默认为false
DisableCircularReferenceDetect,
// 对斜杠'/'进行转义
WriteSlashAsSpecial,
// 将中文都会序列化为\uXXXX格式,字节数会多一些,但是能兼容IE 6,默认为false
BrowserCompatible,
// 全局修改日期格式,默认为false。JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd";JSON.toJSONString(obj, SerializerFeature.WriteDateUseDateFormat);
WriteDateUseDateFormat,
// 不打印最外层根对象的类名,例如一个DO里面引入了另一个DO,外层DO不会打印类名
NotWriteRootClassName,
/** @deprecated */
// 一个对象的字符串属性中如果有特殊字符如双引号,将会在转成json时带有反斜杠转移符。如果不需要转义,可以使用这个属性。默认为false
DisableCheckSpecialChar,
// 把Bean转换成数组
BeanToArray,
// 如果key不为String 则转换为String 比如Map的key为Integer
WriteNonStringKeyAsString,
// 将基础类型的默认值屏蔽
NotWriteDefaultValue,
// 防御xss安全攻击
BrowserSecure,
// 不是类 field 字段对应的getter 方法会被忽略
IgnoreNonFieldGetter,
// 是把不是字符串形式的value转成字符串的形式
WriteNonStringValueAsString,
// 用于忽略那些抛错的getter方法
IgnoreErrorGetter,
// BigDecimal使用科学计数法
WriteBigDecimalAsPlain,
// Map做排序再输出
MapSortField;
}
案例演示
1. 添加fastjson包
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
</dependency>
2. 添加配置类
自定义配置类实现WebMvcConfigurer 接口,主要有以下几步:
- 清理默认的转换器,重新添加,因为扩展的话,要排序什么的,比较麻烦
- 参考WebMvcConfigurationSupport类添加一些必须的转转器,
- 添加FastJson转换器FastJsonHttpMessageConverter ,指定支持的MediaType并添加相关配置
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
private static final boolean shouldIgnoreXml = SpringProperties.getFlag("spring.xml.ignore");
/**
* 自定义消息转换器,覆盖默认
*/
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
// 清理默认
messageConverters.clear();
// 添加
messageConverters.add(new ByteArrayHttpMessageConverter());
messageConverters.add(new StringHttpMessageConverter());
messageConverters.add(new ResourceHttpMessageConverter());
messageConverters.add(new ResourceRegionHttpMessageConverter());
if (!shouldIgnoreXml) {
messageConverters.add(new SourceHttpMessageConverter<>());
}
messageConverters.add(new AllEncompassingFormHttpMessageConverter());
// 配置FastJson并添加
FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
fastJsonHttpMessageConverter.setSupportedMediaTypes(getSupportedMediaTypes()); // 支持的MediaType
fastJsonHttpMessageConverter.setDefaultCharset(StandardCharsets.UTF_8); // 默认字符集
fastJsonHttpMessageConverter.setFastJsonConfig(getFastJsonConfig());
messageConverters.add(fastJsonHttpMessageConverter);
}
/**
* FastJson 配置
*/
private FastJsonConfig getFastJsonConfig() {
FastJsonConfig fastJsonConfig = new FastJsonConfig();
// 配置序列化器功能
fastJsonConfig.setSerializerFeatures(
SerializerFeature.PrettyFormat,
SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.WriteNullListAsEmpty
);
// 序列化配置,将Long类型转为字符串
//不要使用全局的,会影响其他地方的JSON序列化SerializeConfig serializeConfig = SerializeConfig.globalInstance;
SerializeConfig serializeConfig =new SerializeConfig();
serializeConfig.put(BigInteger.class, ToStringSerializer.instance);
serializeConfig.put(Long.class, ToStringSerializer.instance);
serializeConfig.put(Long.TYPE, ToStringSerializer.instance);
serializeConfig.put(long.class, ToStringSerializer.instance);
fastJsonConfig.setSerializeConfig(serializeConfig);
return fastJsonConfig;
}
/**
* 配置支持的媒体类型
*/
private List<MediaType> getSupportedMediaTypes() {
List<MediaType> supportedMediaTypes = Lists.newArrayList();
supportedMediaTypes.add(MediaType.APPLICATION_JSON);
supportedMediaTypes.add(new MediaType("application", "*+json"));
return supportedMediaTypes;
}
}
3. 测试
在AbstractMessageConverterMethodProcessor的writeWithMessageConverters打上断点。
可以看到在读写的时候,使用的是FastJsonHttpMessageConverter。
版权声明:本文不是「本站」原创文章,版权归原作者所有 | 原文地址: