Spring Boot 通过@JsonComponent注解完全控制JSON数据

文摘   科技   2024-12-24 08:00   新疆  

Spring Boot 3实战案例合集》现已囊括超过60篇精选实战文章,并且此合集承诺将永久持续更新,为您带来最前沿的技术资讯与实践经验。欢迎积极订阅,享受不断升级的知识盛宴!订阅用户将特别获赠合集内所有文章的最终版MD文档(详尽学习笔记),以及完整的项目源码,助您在学习道路上畅通无阻。

环境:SpringBoot2.7.18



1. 简介

在之前的一篇文章中详细的介绍了如何优雅的定制JSON数据格式的响应,文章地址如下:

SpringBoot优雅地定制JSON响应数据

在该篇文章中,我们介绍了通过两种主要方式来自定义JSON的序列化:注解和编程方式。注解方式允许我们在类、字段或方法上使用特定的标记来指示JSON序列化的行为。然而,有时我们可能需要更细粒度的控制,这时就可以使用编程方式来实现。

本篇文章将重点介绍如何通过编程方式自定义JSON的序列化和反序列化。编程方式通常涉及到实现特定的接口或扩展框架提供的类,以便在序列化和反序列化过程中插入自定义的逻辑。

在Spring Boot中使用Jackson库时,我们可以创建自定义的序列化器和反序列化器来处理JSON的转换。自定义序列化器需要实现JsonSerializer<T>、JsonObjectSerializer 接口,而自定义反序列化器则需要实现JsonDeserializer<T>、JsonObjectDeserializer接口。这些接口提供了必要的方法来定义如何将Java对象转换为JSON字符串(序列化),以及如何将JSON字符串转换为Java对象(反序列化)。

2. 实战案例

在Spring Boot环境下你可以自定义 JsonSerializerJsonDeserializer KeyDeserializer 的实现类上直接使用 @JsonComponent 注解。也可以在包含序列化器/解序列化器作为内部类的类中使用。

2.1 自定义JsonSerializer/Deserializer

@JsonComponentpublic 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)@Componentpublic @interface JsonComponent {  // ...}

接下来介绍另外一种自定义的方式。

2.2 自定义JsonObjectSerializer/Deserializer

Spring Boot 还提供了 JsonObjectSerializerJsonObjectDeserializer 基类,在序列化对象时,它们为标准的 Jackson 版本提供了有用的替代方法。

@JsonComponentpublic class PackJsonComponent {
public static class Serializer extends JsonObjectSerializer<User> {
@Override 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> { @Override 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的序列化和反序列化,都将只针对你指定的泛型类型有效,其它对象类型不会生效。

以上是本篇文章的全部内容,如对你有帮助帮忙点赞+转发+收藏

推荐文章

Spring6.2新特性@Fallback候选Bean

一文让你彻底搞定Spring Security的基本使用

性能优化!Spring Boot 通过10个技巧优化API接口响应时间

@Transactional用错!严重影响性能,Spring Boot 事务最佳实践

任务重复执行?SpringBoot 一个注解轻松搞定分布式任务调度

面试官:说说@Configuration与@Component有什么区别?

通过Spring AOP结合SpEL表达式:构建强大且灵活的权限控制体系

新一代WebFlux框架核心技术Reactor响应式编程基本用法

【网关大解密】SpringCloud Gateway 打造极简网关API服务,你一定没用过

掌握API接口优化:高效秘籍,打造极致性能

【值得收藏】JDK10到21!新特性一网打尽!

不想被坑?快来了解BigDecimal的陷阱

并发控制实战:乐观锁与Spring AOP重试的完美结合

Spring全家桶实战案例源码
spring, springboot, springcloud 案例开发详解
 最新文章