大数跨境
0
0

Jackson才是王!SpringBoot优雅的控制JSON数据

Jackson才是王!SpringBoot优雅的控制JSON数据 Spring全家桶实战案例
2024-08-22
0
导读:SpringBoot强大的Jackson,这些高级注解太实用了

环境:SpringBoot3.2.5



1. 简介

Spring Boot 提供与三个 JSON 映射库的集成:

  • Gson

  • Jackson

  • JSON-B

Jackson 是首选的默认库。

本篇文章将深入学习 Jackson 注释,了解如何使用现有注释、如何创建自定义注释以及如何禁用注释。

2. 实战案例

2.1 序列化注解

  • @JsonAnyGetter

该注解会自动的将Map集合中的key/value映射为普通属性展示,如下示例:

public class User {  private String name;  private Map<String, String> properties;  // getters, setters}

定义一个接口返回该User对象

@GetMapping("/jsonanygetter")public User jsonanygetter() {  User user = new User("张三", Map.of("key1", "value1", "key2", "value2")) ;  return user ;}

如上示例,在默认情况下输出结果:

将@JsonAnyGetter注解添加到properties的Getter方法上

@JsonAnyGetterpublic Map<String, String> getProperties() {    return properties;}

再次方法接口,输出结果:

将Map中的key/value自动展开成为普通属性。如下配置将禁用此功能

@JsonAnyGetter(enabled = false)

这时有该注解和没有该注解将一样了,也就是默认情况。

  • @JsonGetter

@JsonGetter 注解是 @JsonProperty 注解的替代注解,后者将方法标记为 getter 方法,如下示例:

public class User {  private String name;  private Map<StringString> properties;  // getters, setters  @JsonGetter  public String info() {    return "info - " + new Random().nextInt(10000) ;  }}

这里并没有定义info属性,而是将info方法上添加了@JsonGetter注解,输出结果:

自动将方法名info映射为info属性输出,你也可以指定属性名:

@JsonGetter("fullinfo")

输出的json字段将是:fullinfo。

  • @JsonPropertyOrder

该注解可以指定json字段的输出顺序,如下示例:

@JsonPropertyOrder({"fullinfo", "name", "properties"})public class User {}

输出结果

输出结果为你上面指定的字段顺序。

  • @JsonRawValue

该注解可以指示 Jackson 按原样序列化一个属性。在下面的示例中,我们使用 @JsonRawValue 将一些自定义 JSON 作为实体的值嵌入:

public class User {  private String name;  private Map<String, String> properties;  @JsonRawValue  private String json ;}

接口定义

@GetMapping("/jsonanygetter")public User jsonanygetter() {  User user = new User("张三", Map.of("key1", "value1", "key2", "value2")) ;  user.setJson("""      {        "age": 22,        "birhday": "1999-12-12"      }    """) ;  return user ;}

输出结果

将字符串JSON,按照指定格式输出

  • @JsonValue

该注解表示将使用的单一方法,用于序列化整个实例。例如,在枚举类型中,我们为getName()方法添加了@JsonValue注解,这样任何此类实体都将通过其名称进行序列化:

public static class User {  // other  private Gender gender = Gender.FEMALE ;}// 枚举类public enum Gender {  FEMALE(1, "女"), MALE(2, "男") ;  private Integer code ;  private String name ;  private Gender(Integer code, String name) {    this.code = code ;    this.name = name ;  }}

有如上数据结构,输出结果如下:

接下来,我们在枚举类上的getName方法上添加@JsonValue注解,如下:

@JsonValuepublic String getName() {  return name;}

输出结果

此时输出的是name属性,这可能看的还不够清楚,接下来我们在添加另外一个实体对象

public class User {  // other  private Address address = new Address(1L, "新疆", "八楼") ;}public class Address {  private Long id ;  private String city ;  private String details ;  @JsonValue  public String getDetails() {    return details;  }}

输出结果

address属性是Address对象,结果通过@JsonValue注解添加到该对象的某个属性上,结果输出的是这个属性值,而非整个对象。

  • @JsonSerialize

该注解用来指定自定在输出时使用的序列化器,如下示例:

public static record Person(  Long id,   String name,   Integer age,   @JsonSerialize(using = CustomDateSerializer.class) Date birthday) {}

自定义序列化

public class CustomDateSerializer extends StdSerializer<Date{  private static SimpleDateFormat sdf = new SimpleDateFormat("HH:ss");  public CustomDateSerializer() {     this(null);   }   protected CustomDateSerializer(Class<Date> t) {    super(t) ;  }  @Override  public void serialize(Date value, JsonGenerator gen, SerializerProvider provider) throws IOException {    gen.writeString(sdf.format(value)) ;  }}

输出结果

2.2 反序列化注解

  • @JsonCreator

该注解来调整反序列化中使用的构造函数/工厂。当我们需要反序列化一些与我们需要获取的目标实体不完全匹配的 JSON 时,它就非常有用了。

public static class Order {  private String orderNo ;  private BigDecimal amount ;  @JsonCreator  public Order(      @JsonProperty("no") String orderNo,       BigDecimal amount    ) {    this.orderNo = orderNo ;    this.amount = amount ;  }}

请求结果

  • @JsonAnySetter

该注解允许我们灵活地使用映射作为标准属性,如下示例

public static class MockBean {  private String name;  private Map<String, String> properties = new HashMap<>() ;
@JsonAnySetter public void add(String key, String value) { properties.put(key, value); } // getters, setters}

请求输出结果

除了name属性外,其它属性自动映射到Map集合中。

  • @JsonSetter

该注解是 @JsonProperty 的替代方法,它将方法标记为setter方法。当我们需要读取一些 JSON 数据,但目标实体类与这些数据并不完全匹配,因此我们需要调整处理过程使其符合要求,如下示例:

public class MyObject {  private Long id ;  @JsonSetter("fistName")  private String name ;  private String infos ;  // getters, setters}

请求输出结果

  • @JsonAlias

该注解为反序列化过程中的属性定义了一个或多个替代名称,如下示例:

public static class AliasObject {  @JsonAlias({ "fName", "f_name", "fullName" })  private String name;}

如上定义了3个别名,请求时你设置这3个别名任意一个都能被name接收。

2.3 其它实用注解

@JsonIgnoreProperties

JSON输出时会忽略配置的属性。

@JsonIgnoreProperties({"id"})public static record Customer(Long id, String name) {}

输出结果

@JsonIgnore

该注解用于忽略字段级的属性

public static record Customer(@JsonIgnore Long id, String name) {}

如上将忽略id字段的输出。

@JsonIgnoreType

该注解将会忽略指定类型下的所有属性

public static record Customer(@JsonIgnore Long id, String name, Other other) {}@JsonIgnoreTypepublic static record Other(String info, String details) {}

输出结果

 @JsonInclude

使用 @JsonInclude 来排除empty/null/默认值的属性。

@JsonInclude(Include.NON_NULL)public class MyBean {  public Integer id;  public String name;}

测试接口

@GetMapping("/jsoninclude")public MyBean jsoninclude() {  MyBean bean = new MyBean() ;  bean.name = "中国🇨🇳" ;  return bean ;}

输出结果

@JsonIncludeProperties

该注解是请求最多的 Jackson 功能之一。它在 Jackson 2.12 中引入,可用于标记一个属性或一个属性列表,Jackson 将在序列化和反序列化过程中包含这些属性。

@JsonIncludeProperties({"name", "email"})public static class People {  private String name ;  private String sex ;  private Integer age ;  private String email;}

这将只会输出name和email属性。

@JsonFormat

该注解用来格式化日期时间,如下示例:

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private Date birthday = new Date();

输出将会按照给定的格式输出。否则输出的将会是时间戳。

2.4 自定义注解

我们可以使用 @JacksonAnnotationsInside注解:

@Retention(RetentionPolicy.RUNTIME)@JacksonAnnotationsInside@JsonInclude(Include.NON_NULL)// 定义了输出顺序@JsonPropertyOrder({ "name", "id", "email" })public static @interface Packnnotation {}
@Packnnotationpublic static class Pack { public Integer id ; public String name ; public String email;}

输出结果

2.5 禁用注解

通过JsonMapper.builder().disable方法可以禁止Jackson的注解,如下示例:

@JsonInclude(Include.NON_NULL)@JsonPropertyOrder({ "name", "id" })public static class PackObject {  public Integer id ;  public String name ;  public String email;}

该类上添加了2个注解,一个用于控制不输出空值,一个用于控制输出顺序。

@GetMapping("/disableannotation")public String disableannotation() throws Exception {  JsonMapper mapper = JsonMapper.builder().disable(MapperFeature.USE_ANNOTATIONS).build() ;  String result = mapper.writeValueAsString(new PackObject(1, "张三", null));  return result ;}

输出结果

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

推荐文章

基于SpringBoot支持任意文件在线预览

高性能缓存神器Caffeine

建议收藏!SpringBoot项目实战开发技巧

放弃ThreadLocal!TTL真香

优雅!SpringBoot通过函数式编程模型声明Restful API接口

Controller接口地址还能这样玩?

完美!SpringBoot + HTML模板高效生成PDF文档

强大!SpringBoot结合STOMP简化数据实时通信

优雅!SpringBoot统一返回结果就该这样处理

SpringBoot强大的分布式锁组件Lock4j,支持多种实现

SpringBoot自带Controller接口监控,赶紧用起来

SpringBoot这几个工具类太有用了

Java开发人员必须掌握的11种干净代码最佳实践

警惕!SpringBoot错误发布事件,造成死锁Deadlock

提升系统吞吐量,详解JDK21虚拟线程,炸裂

SpringBoot优雅定制接口参数格式转换

SpringBoot3虚拟线程 & 反应式(WebFlux) & 传统Tomcat线程池 性能对比

【声明】内容源于网络
0
0
Spring全家桶实战案例
Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
内容 832
粉丝 0
Spring全家桶实战案例 Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
总阅读285
粉丝0
内容832