Appearance
序列化与反序列化
说明
为了统一参数格式和数据精度丢失等问题,本项目做了采用jackson进行全局的序列化和反序列化配置。
名词解释:
- 序列化:Controller层接口返回值 转成 json 格式的过程
- 反序列化:前端请求通过json格式提交参数到 Controller 层的过程
全局配置
在BaseConfig类配置了全局的ObjectMapper 实例, 并对objectMapper进行了自定义配置。
注意
配置全局ObjectMapper类后,会和yml配置文件中 spring.jackson.xxx 的配置产生冲突,所以请勿在yml中重复配置
java
@Bean
@Primary
@ConditionalOnClass(ObjectMapper.class)
@ConditionalOnMissingBean
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
objectMapper
// 设置当前位置
.setLocale(Locale.CHINA)
//去掉默认的时间戳格式
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
// 时区
.setTimeZone(TimeZone.getTimeZone(ZoneId.systemDefault()))
//Date参数日期格式
.setDateFormat(new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT, Locale.CHINA))
//该特性决定parser是否允许JSON字符串包含非引号控制字符(值小于32的ASCII字符,包含制表符和换行符)。 如果该属性关闭,则如果遇到这些字符,则会抛出异常。JSON标准说明书要求所有控制符必须使用引号,因此这是一个非标准的特性
.configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true)
// 忽略不能转义的字符
.configure(JsonReadFeature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER.mappedFeature(), true)
//在使用spring boot + jpa/hibernate,如果实体字段上加有FetchType.LAZY,并使用jackson序列化为json串时,会遇到SerializationFeature.FAIL_ON_EMPTY_BEANS异常
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
//忽略未知字段
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
//单引号处理
.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
// 注册自定义模块
objectMapper.registerModule(new AcuityJacksonModule())
.findAndRegisterModules();
}
public class AcuityJacksonModule extends SimpleModule {
public AcuityJacksonModule() {
super();
this.addDeserializer(LocalDateTime.class, AcuityLocalDateTimeDeserializer.INSTANCE);
this.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
this.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
this.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
this.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
this.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
this.addSerializer(Long.class, ToStringSerializer.instance);
this.addSerializer(Long.TYPE, ToStringSerializer.instance);
this.addSerializer(BigInteger.class, ToStringSerializer.instance);
this.addSerializer(BigDecimal.class, ToStringSerializer.instance);
// 4.x 版本无需枚举类序列化为{"code":xx,"desc":""} 的格式,需要回显枚举的,请在枚举上加 @Echo(api = Echo.ENUM_API) 注解 。
// this.addSerializer(BaseEnum.class, EnumSerializer.INSTANCE);
// 3.2.1 版本以后,覆盖官方的EnumDeserializer
// this.addDeserializer(Enum.class, EnumDeserializer.INSTANCE);
}
}
@Bean
@Primary
@ConditionalOnClass(ObjectMapper.class)
@ConditionalOnMissingBean
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
objectMapper
// 设置当前位置
.setLocale(Locale.CHINA)
//去掉默认的时间戳格式
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
// 时区
.setTimeZone(TimeZone.getTimeZone(ZoneId.systemDefault()))
//Date参数日期格式
.setDateFormat(new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT, Locale.CHINA))
//该特性决定parser是否允许JSON字符串包含非引号控制字符(值小于32的ASCII字符,包含制表符和换行符)。 如果该属性关闭,则如果遇到这些字符,则会抛出异常。JSON标准说明书要求所有控制符必须使用引号,因此这是一个非标准的特性
.configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true)
// 忽略不能转义的字符
.configure(JsonReadFeature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER.mappedFeature(), true)
//在使用spring boot + jpa/hibernate,如果实体字段上加有FetchType.LAZY,并使用jackson序列化为json串时,会遇到SerializationFeature.FAIL_ON_EMPTY_BEANS异常
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
//忽略未知字段
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
//单引号处理
.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
// 注册自定义模块
objectMapper.registerModule(new AcuityJacksonModule())
.findAndRegisterModules();
}
public class AcuityJacksonModule extends SimpleModule {
public AcuityJacksonModule() {
super();
this.addDeserializer(LocalDateTime.class, AcuityLocalDateTimeDeserializer.INSTANCE);
this.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
this.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
this.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
this.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
this.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
this.addSerializer(Long.class, ToStringSerializer.instance);
this.addSerializer(Long.TYPE, ToStringSerializer.instance);
this.addSerializer(BigInteger.class, ToStringSerializer.instance);
this.addSerializer(BigDecimal.class, ToStringSerializer.instance);
// 4.x 版本无需枚举类序列化为{"code":xx,"desc":""} 的格式,需要回显枚举的,请在枚举上加 @Echo(api = Echo.ENUM_API) 注解 。
// this.addSerializer(BaseEnum.class, EnumSerializer.INSTANCE);
// 3.2.1 版本以后,覆盖官方的EnumDeserializer
// this.addDeserializer(Enum.class, EnumDeserializer.INSTANCE);
}
}
序列化自定义配置项
Long -> String
- 实现代码
javapublic AcuityJacksonModule() { this.addSerializer(Long.class, ToStringSerializer.instance); this.addSerializer(Long.TYPE, ToStringSerializer.instance); }
public AcuityJacksonModule() { this.addSerializer(Long.class, ToStringSerializer.instance); this.addSerializer(Long.TYPE, ToStringSerializer.instance); }
- 最终效果 Controller层接口返回参数中,Long类型的字段,会转成字符串。
json{ "id": "29984253320102284" }
{ "id": "29984253320102284" }
- 解决问题: 解决前端获取到Long类型的字段后,精度丢失问题。 (更多信息自行百度&谷歌)
BigInteger -> String
- 实现代码
javapublic AcuityJacksonModule() { this.addSerializer(BigInteger.class, ToStringSerializer.instance); }
public AcuityJacksonModule() { this.addSerializer(BigInteger.class, ToStringSerializer.instance); }
- 最终效果&解决问题:同上
BigDecimal -> String
- 实现代码
javapublic AcuityJacksonModule() { this.addSerializer(BigDecimal.class, ToStringSerializer.instance); }
public AcuityJacksonModule() { this.addSerializer(BigDecimal.class, ToStringSerializer.instance); }
- 最终效果&解决问题:同上
Date -> String
- 实现代码
javapublic class BaseConfig { public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) { objectMapper //Date参数日期格式 .setDateFormat(new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT, Locale.CHINA)) // ... } }
public class BaseConfig { public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) { objectMapper //Date参数日期格式 .setDateFormat(new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT, Locale.CHINA)) // ... } }
- 最终效果 Controller层接口返回参数中,Date类型的字段,会转成字符串。
json{ "date": "yyyy-MM-dd HH:mm:ss" // 这里的格式由上面的 DEFAULT_DATE_TIME_FORMAT 决定 }
{ "date": "yyyy-MM-dd HH:mm:ss" // 这里的格式由上面的 DEFAULT_DATE_TIME_FORMAT 决定 }
- 解决问题: 统一日期参数的统一格式
LocalDateTime -> String
- 实现代码
javapublic AcuityJacksonModule() { this.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))); }
public AcuityJacksonModule() { this.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))); }
- 最终效果 Controller层接口返回参数中,LocalDateTime类型的字段,会转成字符串。
json{ "createTime": "yyyy-MM-dd HH:mm:ss" }
{ "createTime": "yyyy-MM-dd HH:mm:ss" }
- 解决问题: 同上
LocalDate -> String
- 实现代码
javapublic AcuityJacksonModule() { this.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))); }
public AcuityJacksonModule() { this.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))); }
- 最终效果 Controller层接口返回参数中,LocalDate类型的字段,会转成字符串。
json{ "createTime": "yyyy-MM-dd" }
{ "createTime": "yyyy-MM-dd" }
- 解决问题: 同上
LocalTime -> String
- 实现代码
javapublic AcuityJacksonModule() { this.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT))); }
public AcuityJacksonModule() { this.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT))); }
- 最终效果 Controller层接口返回参数中,LocalTime类型的字段,会转成字符串。
json{ "createTime": "HH:mm:ss" }
{ "createTime": "HH:mm:ss" }
- 解决问题: 同上
反序列化自定义配置项
String -> Long 字符串类型的长整型数字,会转换为Long
Object -> BaseEnum 符合 {"code":"xx"} 格式的对象,可以转换为BaseEnum
String -> BaseEnum 符合枚举值的字符串,可以转换为BaseEnum
String -> LocalDate, 支持前端传递格式:
yyyy-MM-dd
: 如:2021-11-11
String -> LocalDateTime, 支持前端传递格式:
yyyy-MM-dd
: 如:2021-11-11yyyy/MM/dd
: 如:2021/11/11yyyy年MM月dd日
: 如:2021年11月11日yyyy-MM-dd HH:mm:ss
: 如:2021-11-11 11:11:11yyyy/MM/dd HH:mm:ss
: 如:2021/11/11 11:11:11yyyy年MM月dd日HH时mm分ss秒
: 如:2021年11月11日11时11分11秒
String -> LocalTime
支持前端传递格式:
HH:mm:ss