@JsonIgnore,@JsonProperty, @JsonInclude,@JsonFormat

参考示例

需要引入

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;
}
相关推荐
风哥2号4 小时前
数据库教程FGMT33‑MySQL主从复制项目实施与维护06(MySQL8.4/9.7 MGR组复制)
数据库·mysql
liangsheng_g4 小时前
Spring事务传播行为分派与挂起恢复源码实战
数据库·sql·spring
蓝速科技5 小时前
信创终端 POC 测试实战与选型避坑指南丨蓝速科技
运维·数据库·人工智能·科技·自然语言处理
风哥2号5 小时前
数据库教程FGMT29‑Linux平台MySQL5.7安装配置与管理入门
数据库
杨云龙UP5 小时前
MySQL Host is blocked because of many connection errors 导致 JDBC 连接失败排查与解决
linux·运维·网络·数据库·sql·mysql·登录失败
这个DBA有点耶7 小时前
数据库数据同步解决方案怎么选?6款主流工具横向对比与信创选型指南
数据库·架构·dba
刃神太酷啦7 小时前
Redis 核心进阶:哨兵、集群、缓存问题与分布式锁详解----《Hello Redis!》(6)
linux·c语言·数据库·c++·redis·分布式·缓存
小雷信息医学7 小时前
不会写复杂代码也能发 SCI?手把手教你用 InSpireR 交互系统一键提取、合并与导出临床科研宽表【第三章】
数据库
旺仔不是程序员8 小时前
复合索引最左前缀原则:PostgreSQL 的 WHERE 为什么必须命中第一列
数据库·后端·sql
旺仔不是程序员8 小时前
字段类型不一致:PostgreSQL 报错与索引失效的第一元凶
数据库·后端·sql