《Spring Boot 3实战案例合集》现已囊括超过60篇精选实战文章,并且此合集承诺将永久持续更新,为您带来最前沿的技术资讯与实践经验。欢迎积极订阅,享受不断升级的知识盛宴!订阅用户将特别获赠合集内所有文章的最终版MD文档(详尽学习笔记),以及完整的项目源码,助您在学习道路上畅通无阻。
环境:SpringBoot2.7.18
1. 简介
在之前的一篇文章中详细的介绍了如何优雅的定制JSON数据格式的响应,文章地址如下:
在该篇文章中,我们介绍了通过两种主要方式来自定义JSON的序列化:注解和编程方式。注解方式允许我们在类、字段或方法上使用特定的标记来指示JSON序列化的行为。然而,有时我们可能需要更细粒度的控制,这时就可以使用编程方式来实现。
本篇文章将重点介绍如何通过编程方式自定义JSON的序列化和反序列化。编程方式通常涉及到实现特定的接口或扩展框架提供的类,以便在序列化和反序列化过程中插入自定义的逻辑。
在Spring Boot中使用Jackson库时,我们可以创建自定义的序列化器和反序列化器来处理JSON的转换。自定义序列化器需要实现JsonSerializer<T>、JsonObjectSerializer
接口,而自定义反序列化器则需要实现JsonDeserializer<T>、JsonObjectDeserializer接口。这些接口提供了必要的方法来定义如何将Java对象转换为JSON字符串(序列化),以及如何将JSON字符串转换为Java对象(反序列化)。
2. 实战案例
在Spring Boot环境下你可以自定义 JsonSerializer、JsonDeserializer 或 KeyDeserializer 的实现类上直接使用 @JsonComponent 注解。也可以在包含序列化器/解序列化器作为内部类的类中使用。
2.1 自定义JsonSerializer/Deserializer
@JsonComponent
public class PackJsonComponent {
// 自定义序列化
public static class Serializer extends JsonSerializer<User> {
@Override
public void serialize(User value, JsonGenerator jgen, SerializerProvider serializers) throws IOException {
jgen.writeStartObject() ;
jgen.writeStringField("name", value.getName()) ;
jgen.writeNumberField("age", value.getAge()) ;
jgen.writeEndObject() ;
}
}
// 自定义反序列化
public static class Deserializer extends JsonDeserializer<User> {
@Override
public User deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException {
ObjectCodec codec = jsonParser.getCodec() ;
JsonNode tree = codec.readTree(jsonParser) ;
String name = tree.get("name").textValue() ;
int age = tree.get("age").intValue() ;
// 为了区分这里故意做了+操作,以表示生效
long id = tree.get("id").longValue() + 1000L ;
return new User(id, name, age) ;
}
}
}
上面自定义PackJsonComponent类中定义了序列化和反序列化组件,他们的父类都指定了泛型的类型,这里你也可以指定Object,在进行处理时再进行类型的判断。
测试接口
@RestController
@RequestMapping("/jackson")
public class JacksonController {
@GetMapping("/user")
public User queryUser() {
return new User(1L, "张三", 10) ;
}
@PostMapping("/save")
public User queryUser(@RequestBody User user) {
return user ;
}
}
// User对象
public class User {
private Long id ;
private String name ;
private Integer age ;
// getter, setter
}
测试/queryUser接口
测试/save接口
注意:在测试该/save接口时,你需要先将序列号的类注释了,不然你看不到效果。
ApplicationContext容器中的所有 @JsonComponent Bean 都会自动向 Jackson 注册。因为 @JsonComponent 是用 @Component 元标注的,所以通常的组件扫描规则也适用。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface JsonComponent {
// ...
}
接下来介绍另外一种自定义的方式。
2.2 自定义JsonObjectSerializer/Deserializer
Spring Boot 还提供了 JsonObjectSerializer 和 JsonObjectDeserializer 基类,在序列化对象时,它们为标准的 Jackson 版本提供了有用的替代方法。
public class PackJsonComponent {
public static class Serializer extends JsonObjectSerializer<User> {
protected void serializeObject(User value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
jgen.writeNumberField("id", value.getId()) ;
jgen.writeStringField("name", value.getName()) ;
jgen.writeNumberField("age", value.getAge());
// 添加新的属性
jgen.writeStringField("nation", "中国🇨🇳") ;
// 自定义写入其它的对象
Map<String, Object> params = new HashMap<>() ;
params.put("q", "java") ;
params.put("s", "pack") ;
jgen.writeObjectField("params", params) ;
}
}
public static class Deserializer extends JsonObjectDeserializer<User> {
protected User deserializeObject(JsonParser jsonParser,
DeserializationContext context,
ObjectCodec codec,
JsonNode tree) throws IOException {
long id = nullSafeValue(tree.get("id"), Long.class) + 1L ;
String name = nullSafeValue(tree.get("name"), String.class);
int age = nullSafeValue(tree.get("age"), Integer.class) ;
return new User(id, name, age) ;
}
}
}
通过以上的方式都可以自定义JSON对象的序列化和反序列化。
需要注意:你不能在序列化时直接通过writeObject方法输出当前方法参数的value对象
// 不允许这样操作,这会报错;但你可以像上面那样输出其它的对象
jgen.writeObject(value);
上面不管你通过什么方式自定义JSON的序列化和反序列化,都将只针对你指定的泛型类型有效,其它对象类型不会生效。
以上是本篇文章的全部内容,如对你有帮助帮忙点赞+转发+收藏
推荐文章
性能优化!Spring Boot 通过10个技巧优化API接口响应时间
@Transactional用错!严重影响性能,Spring Boot 事务最佳实践
任务重复执行?SpringBoot 一个注解轻松搞定分布式任务调度
面试官:说说@Configuration与@Component有什么区别?
通过Spring AOP结合SpEL表达式:构建强大且灵活的权限控制体系
新一代WebFlux框架核心技术Reactor响应式编程基本用法