介绍
众所周知默认情况下将实体类序列化会生成key-value的JSON字符串,但是某些情况下不一定适合,比如如果需要对 金钱数值 进行一些操作,但是浮点数的精度不足,正常情况下一般使用 Money 实体类封装金钱金额,但是在输出JSON 字符串时只想要 Money 的值,此时就要用到自定义序列化。
代码
User
@Data
@Component
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id;
private String name;
private Money money;
}
Money
@Data
@Component
@AllArgsConstructor
@NoArgsConstructor
public class Money {
private Long value;
}
自定义序列和反序列化
- 采用 @JsonComponent 注解注册 JSON bean
- 实现序列化和反序列化内部类
- 在内部类中调用具体方法
- 具体执行过程可以看注释
@JsonComponent
public class Example {
public static class Serializer extends JsonSerializer<Money>{
@Override
public void serialize(Money money, JsonGenerator gen, SerializerProvider serializers) throws IOException {
// 使money对象序列化时只输出 value 变量,而不是输出JSON对象字符串
gen.writeString(money.getValue().toString());
}
}
public static class Deserializer extends JsonDeserializer<Money>{
@Override
public Money deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
// 将 value 属性取出来重新封装到 Maney 对象上
return new Money(Long.valueOf(String.valueOf(p)));
}
}
}
定义 Controllr 返回 User 对象查看序列化后的成果
@RestController
@RequestMapping("/user")
public class MyRestController {
@RequestMapping(value = "/testSer",method = RequestMethod.GET)
public User getUser() throws JsonProcessingException {
Money money = new Money(100L);
User user = new User(123,"zhangsan",money);
// 通过 JackSon 序列化 User 对象输出
// {"id":123456,"name":"zhangsan","money":{"value":100}}
System.out.println(new ObjectMapper().writeValueAsString(user));
return user;
}
}
查看前端返回的JSON字符串
{
"id": 123,
"name": "zhangsan",
"money": "100"
}
注意:观察通过正常序列化工具类序列化后的字符串和经过自定义序列化器实现的字符串的区别可以观察到Money类的字符串已经被转化为 类名首字母小写对应 Money 类中的 value 值的键值对字符串。
总结
自定义序列化器和反序列化器的使用实际就是通过 AOP 的方式改变 JSON 字符串与实体类之间相互转换的规则。