Jackson在Spring Boot中的开发技巧详解
Jackson 是 Spring Boot 中默认的 JSON 处理库,用于对象与 JSON 之间的序列化和反序列化。它在日常开发中扮演着重要角色,掌握其开发技巧能够显著提升开发效率和系统的稳定性。本文将详细介绍 Jackson 在 Spring Boot 中的各种开发技巧,涵盖基础配置、注解使用、自定义序列化器和反序列化器、以及处理复杂数据类型等方面。
基础配置
1. 全局配置
在 Spring Boot 中,可以通过 application.properties
或 application.yml
文件对 Jackson 进行全局配置。
- 日期格式化:设置日期类型的全局格式化规则,例如:
spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8
- Long 型字段转字符串:为了避免 JavaScript 在处理 Long 型字段时可能出现的精度丢失问题,可以将 Long 型字段序列化为字符串:
或者在字段级别使用spring: jackson: default-property-inclusion: non_null serialization: write_bigdecimal_as_plain: true
@JsonFormat
注解:public class MyClass { @JsonFormat(shape = JsonFormat.Shape.STRING) private Long lng; }
2. 默认配置
Spring Boot 默认集成了 Jackson,无需额外配置即可处理 JSON。例如,使用 @RequestBody
和 @ResponseBody
注解时,Spring Boot 会自动将 JSON 数据与 Java 对象进行转换。
注解使用
Jackson 提供了丰富的注解,用于定制化数据转换的行为。
- @JsonProperty:指定属性在 JSON 中的名称。
- @JsonIgnore:忽略某个属性,不进行序列化和反序列化。
- @JsonFormat:指定日期、时间等的格式。
- @JsonInclude:指定属性在何种条件下包含在 JSON 中,例如
non_null
表示只包含非空值。 - @JsonCreator 和 @JsonValue:用于指定构造函数和序列化时的值。
下面把 Jackson 中最常用的 5 个注解(@JsonProperty
、@JsonIgnore
、@JsonFormat
、@JsonInclude
、@JsonCreator
/@JsonValue
)的
① 作用、② 常用属性、③ 典型代码示例、④ 运行效果一次讲清,拿来即用。
1. @JsonProperty
—— 给 JSON 字段起别名
作用 | 把 Java 字段名映射成任意 JSON 键名,或反向映射 |
---|---|
常用属性 | value (JSON 键名)、required (反序列化时是否必须存在) |
public class User {
@JsonProperty("user_name") // 序列化/反序列化都用 "user_name"
private String userName;
@JsonProperty(value = "age", required = true)
private Integer age;
}
效果
{"user_name":"Tom","age":18}
2. @JsonIgnore
—— 完全忽略字段
作用 | 序列化 & 反序列化都跳过该字段 |
---|---|
无常用属性 | 直接打在字段或 getter 上即可 |
public class User {
private String name;
@JsonIgnore // 密码不出现在 JSON 中
private String password;
}
效果
{"name":"Tom"}
3. @JsonFormat
—— 控制日期/数字/枚举格式
作用 | 精准控制日期、时间、数字、枚举的字符串格式 |
---|---|
常用属性 | pattern (格式模板)、timezone 、shape (STRING/NUMBER) |
public class Order {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime createTime;
@JsonFormat(shape = JsonFormat.Shape.STRING) // Long → String,防 JS 精度丢失
private Long orderId;
}
效果
{"createTime":"2024-06-01 15:30:00","orderId":"9223372036854775807"}
4. @JsonInclude
—— 条件化序列化
作用 | 仅当字段满足给定条件时才输出到 JSON |
---|---|
常用取值 | NON_NULL 、NON_EMPTY 、NON_DEFAULT 、CUSTOM |
@JsonInclude(JsonInclude.Include.NON_NULL) // 类级别:所有 null 字段都不输出
public class User {
private String name;
private String email; // 为 null 时会被忽略
}
效果(email==null)
{"name":"Tom"}
5. @JsonCreator
+ @JsonValue
—— 自定义构造 & 单值序列化
注解 | 作用 |
---|---|
@JsonCreator |
反序列化:告诉 Jackson 用指定构造器/工厂方法创建对象 |
@JsonValue |
序列化:把整个对象变成单一值(字符串、数字等) |
public class Distance {
private final int meters;
@JsonCreator // 反序列化 {"distance": 1200}
public Distance(@JsonProperty("distance") int meters) {
this.meters = meters;
}
@JsonValue // 序列化时只返回这个数字
public int getMeters() {
return meters;
}
}
序列化效果
1200
反序列化示例
{"distance":1200} → new Distance(1200)
一张图速记
注解 | 主要场景 | 一句话记忆 |
---|---|---|
@JsonProperty |
字段名不一致 | “换个名字” |
@JsonIgnore |
敏感/无用字段 | “当它不存在” |
@JsonFormat |
日期/数字格式 | “按模板输出” |
@JsonInclude |
过滤空值 | “非空才要” |
@JsonCreator /@JsonValue |
构造/单值序列化 | “对象 ↔ 单值” |
把这些注解组合起来,就能覆盖 90% 的日常 JSON 定制化需求。
自定义序列化与反序列化
当注解和全局配置无法满足需求时,可以通过自定义序列化器和反序列化器来实现更复杂的功能。
1. 自定义序列化器
public class CustomDateSerializer extends JsonSerializer<Date> {
@Override
public void serialize(Date date, JsonGenerator gen, SerializerProvider serializers) throws IOException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String formattedDate = sdf.format(date);
gen.writeString(formattedDate);
}
}
在 Java 类中使用 @JsonSerialize
注解来指定自定义序列化器:
public class User {
@JsonSerialize(using = CustomDateSerializer.class)
private Date birthday;
}
2. 自定义反序列化器
public class CustomDateDeserializer extends JsonDeserializer<Date> {
@Override
public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
JsonNode node = p.getCodec().readTree(p);
String date = node.asText();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
return sdf.parse(date);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
在 Java 类中使用 @JsonDeserialize
注解来指定自定义反序列化器:
public class User {
@JsonDeserialize(using = CustomDateDeserializer.class)
private Date birthday;
}
处理复杂数据类型
1. 枚举与 JSON 的互转
在开发中,为了避免过多的魔法值,使用枚举类来封装一些静态的状态代码。例如:
public enum StatusEnums {
NORMAL(1, "正常"),
LOCK(2, "锁定"),
DELETE(3, "删除");
private Integer code;
private String desc;
// 构造方法、getter 和 setter
}
使用
@JsonValue
注解:通过@JsonValue
注解,可以控制枚举序列化的结果。@JsonValue public Integer getCode() { return code; }
自定义序列化器和反序列化器:通过自定义序列化器和反序列化器,可以实现更复杂的枚举与 JSON 的互转逻辑。
2. 处理嵌套对象
Jackson 可以轻松处理嵌套对象的序列化和反序列化。例如:
public class Order {
private Long orderId;
private User user;
// getter 和 setter
}
public class User {
private Long id;
private String name;
// getter 和 setter
}
性能优化
1. 使用流式 API
对于大型 JSON 数据,使用流式 API(如 JsonParser
和 JsonGenerator
)可以逐步处理 JSON 数据,避免一次性加载整个 JSON 文档,从而提高性能。
2. 使用缓存机制
Jackson 内部采用了对象缓存机制,通过对象缓存可以显著提升序列化与反序列化的性能。
常见问题与解决方案
1. 循环依赖问题
如果对象之间存在循环引用,Jackson 默认会抛出异常。可以使用 @JsonManagedReference
和 @JsonBackReference
注解来避免循环依赖。
public class Department {
@JsonManagedReference
private List<User> users;
}
public class User {
@JsonBackReference
private Department department;
}
2. 错误处理机制
在进行 JSON 处理时,可能会遇到错误。可以通过全局异常处理器捕捉并返回错误信息。