需要引入
java
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
功能互补:
@JsonIgnore是完全忽略某个字段,
@JsonProperty是显式指定字段的序列化/反序列化名称
经常成对出现:在实体类中,这两个注解经常被一起讨论和使用
命名相似性:都有 "Property" 这个词,容易让人联想到它们是一组相关注解
java
public class User {
@JsonIgnore // 完全忽略这个字段,不参与JSON序列化/反序列化
private String password;
@JsonProperty("user_name") // 序列化时使用 "user_name" 而不是 "userName"
private String userName;
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY) // 只允许反序列化,不允许序列化
private String email;
}
@JsonIgnoreProperties
关系:@JsonIgnoreProperties是类级别的注解,@JsonIgnore是字段级别的
用途:@JsonIgnoreProperties({"field1", "field2"})可以忽略多个字段
@JsonInclude
关系:控制字段在什么情况下才被包含在JSON中
对比:@JsonIgnore是完全排除,@JsonInclude是条件性包含
@Transient(JPA注解)
混淆点:很多人会把 JPA 的 @Transient和 Jackson 的 @JsonIgnore搞混
区别:@Transient表示数据库忽略该字段,@JsonIgnore表示JSON序列化忽略该字段
这是 @Transient最核心的用途。当使用 JPA(如 Hibernate)操作数据库时,它会将实体类的字段与数据库表的列进行映射。如果你有一些字段不需要存储到数据库,只是用于在业务逻辑中临时计算或展示,就需要用到 @Transient。
java
import javax.persistence.Transient; // JPA 标准
// 或者
import org.hibernate.annotations.Transient; // Hibernate 扩展(功能类似)
告诉 JPA/Hibernate:"这个字段是临时的,请不要为它创建数据库列,在插入和更新时也请忽略它。"
java
import javax.persistence.*;
import lombok.Data;
@Entity
@Table(name = "sys_user")
@Data
public class SysUser {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long userId;
private String userName;
private String nickName;
// ... 其他数据库字段 (email, phonenumber, etc.)
/**
* 临时字段:全名
* 这个字段不会映射到数据库的 'sys_user' 表中
* 我们只是在内存中用它来拼接 userName 和 nickName
*/
@Transient
private String fullName;
// 一个用于业务逻辑的方法
public String getFullName() {
if (this.fullName == null) {
// 如果 fullName 为空,则动态拼接
return this.userName + "(" + this.nickName + ")";
}
return this.fullName;
}
}
在这个例子中:
数据库表 sys_user不会有 full_name这一列。
当你执行 userRepository.save(user)时,fullName的值不会被存入数据库。
当你从数据库查询出一个 SysUser对象时,fullName字段会是 null(除非你在查询后手动调用 getFullName()方法为其赋值)
java
@Entity
@Table(name = "sys_user")
@Data
public class SysUser {
@Id
private Long userId;
private String userName;
// 1. 密码字段:需要存在数据库中,但不应通过API返回给前端
private String password;
// 2. 临时计算字段:不应存入数据库,但可能需要返回给前端
@Transient
private String displayName;
// 3. 敏感且临时的字段:既不存数据库,也不返回给前端
@Transient
@JsonIgnore
private String tempSecretKey;
// Getter 方法,用于业务逻辑
public String getDisplayName() {
return this.nickName + " (" + this.userName + ")";
}
}
password: 会被存入数据库,但通过 API 返回时会被 @JsonIgnore过滤掉。
displayName: 不会被存入数据库(因为有 @Transient),但可以被序列化为 JSON 返回给前端(因为没有 @JsonIgnore)。
tempSecretKey: 既不会被存入数据库(因为有 @Transient),也不会出现在任何 API 的 JSON 中(因为有 @JsonIgnore)。
@JsonInclude
这是 Jackson 库中的一个注解,用于控制 JSON 序列化时哪些字段应该包含在输出中。
控制序列化时忽略空值或空集合字段,使 JSON 输出更简洁。
java
public enum Include {
ALWAYS, // 总是包含(默认)
NON_NULL, // 不为 null 时包含
NON_ABSENT, // 不为 null 或 Optional.absent 时
NON_EMPTY, // 不为空时(最常用)
NON_DEFAULT, // 不是默认值时
CUSTOM, // 自定义规则
USE_DEFAULTS // 使用默认设置
}
java
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
@Data
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class User {
private Long id;
private String name;
private String email;
private List<String> hobbies = new ArrayList<>();
private Map<String, Object> attributes = new HashMap<>();
private String emptyString = "";
private Integer zeroValue = 0;
private Boolean falseValue = false;
private int[] emptyArray = new int[0];
}
// 测试
User user = new User();
user.setId(1L);
user.setName(null); // null
user.setEmail(""); // 空字符串
user.setHobbies(new ArrayList<>()); // 空列表
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(user);
// 输出结果:
// {"id":1} // 只有 id 被序列化
// name=null, email="", hobbies=[] 等都被忽略
类级别
java
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@Data
public class ApiResponse<T> {
private boolean success;
private String code;
private String message;
private T data;
private List<String> errors = new ArrayList<>();
// 返回结果会很干净
}
// 成功时
ApiResponse<User> success = ApiResponse.success(user);
// 输出:{"success":true,"code":"200","data":{...}}
// 失败时(无错误详情)
ApiResponse<Void> error = ApiResponse.error("系统错误");
// 输出:{"success":false,"code":"500","message":"系统错误"}
// errors=[] 被忽略
字段级别
java
@Data
public class ProductDetail {
private Long id;
private String name;
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private String description; // 只有这个字段应用 NON_EMPTY
@JsonInclude(JsonInclude.Include.NON_NULL)
private List<String> tags; // 这个字段用 NON_NULL
private BigDecimal price = BigDecimal.ZERO; // 默认规则
}
@JsonFormat
这是 Jackson 库中用于控制日期时间序列化和反序列化格式的注解。
java
import com.fasterxml.jackson.annotation.JsonFormat;
import java.util.Date;
@Data
public class User {
private Long id;
private String name;
// 序列化格式:yyyy-MM-dd HH:mm:ss
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date birthday;
@JsonFormat(pattern = "HH:mm:ss")
private Date alarmTime;
}