源本科技 | 码上会

使用 Jackson 处理 JSON

2026/03/31
9
0

引言

JSON(JavaScript Object Notation)是轻量级、跨语言、语法简洁的数据交换格式,是 RESTful API 前后端数据交互的事实标准。 在 Spring Boot 中,Jackson 是官方内置的默认 JSON 处理框架,随 spring-boot-starter-web 自动集成,无需手动配置。它核心完成两大关键操作:

  • 序列化:Java 对象 → JSON 字符串(后端返回数据给前端)

  • 反序列化:JSON 字符串 → Java 对象(接收前端请求体数据)


Jackson

自动依赖集成

Spring Web 场景会自动引入 Jackson,无需额外添加依赖;仅处理 Java 8+ 日期(LocalDate/LocalDateTime)时,需补充日期模块:

<!-- Spring Web(自带Jackson核心) -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- 必须:Java 8 日期格式化支持 -->
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
</dependency>

工作流程

  1. 接收请求:前端 JSON → Jackson 反序列化 → Controller 方法参数(Java 对象)

  2. 返回响应:Java 对象 → Jackson 序列化 → 前端 JSON 数据


高频注解

注解用于自定义 JSON 转换规则,是企业开发必备,覆盖最常用场景:

注解

作用位置

核心功能

典型使用场景

@JsonProperty

字段

重命名 JSON 键名

前后端字段命名不一致

@JsonIgnore

字段

忽略单个字段(不序列化 / 反序列化)

隐藏密码、敏感信息

@JsonIgnoreProperties

① 忽略多个字段 ② 忽略未知字段

批量忽略、兼容前端多余参数

@JsonInclude

类 / 字段

控制空值是否序列化

不返回 null 字段

@JsonFormat

字段

格式化日期、数字、枚举

统一日期格式:yyyy-MM-dd

@JsonCreator

构造方法

自定义反序列化构造器

特殊对象创建场景


实战代码

核心优化

  1. Lombok 消除冗余 get/set/构造方法

  2. 补全完整 CRUD 接口

  3. 规范注解使用

  4. 增加全局配置,减少重复注解

实体类

package com.example.demo.model;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDate;

/**
 * 用户实体类
 * Lombok 注解说明:
 * @Data:自动生成get/set/toString/equals/hashCode
 * @NoArgsConstructor:Jackson 反序列化【必须有无参构造】
 * @AllArgsConstructor:全参构造
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
// 序列化规则:值为 null 的字段不输出到 JSON
@JsonInclude(JsonInclude.Include.NON_NULL)
// 忽略前端传递的多余字段,避免报错(企业必备)
// @JsonIgnoreProperties(ignoreUnknown = true)
public class User {

    private Integer id;

    // 重命名:Java 字段 name → JSON 字段 full_name
    @JsonProperty("full_name")
    private String name;

    // 忽略字段:不返回给前端,也不接收前端数据
    @JsonIgnore
    private String password;

    // 日期格式化:指定格式 + 时区
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    private LocalDate dob;

    private String email;
}

Controller

package com.example.demo.controller;

import com.example.demo.model.User;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDate;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;

@RestController
@RequestMapping("/api/users")
public class UserController {

    // 线程安全集合,模拟数据库存储
    private final List<User> userList = new CopyOnWriteArrayList<>();
    // 原子ID生成器,保证线程安全
    private final AtomicInteger idGenerator = new AtomicInteger(1);

    // 初始化测试数据
    public UserController() {
        userList.add(new User(
                idGenerator.getAndIncrement(),
                "Vishnu Chauhan",
                "secret123",
                LocalDate.of(1998,5,20),
                "vishnu@example.com"
        ));
    }

    // 1. 查询所有用户 GET /api/users
    @GetMapping
    public List<User> getAllUsers() {
        return userList;
    }

    // 2. 根据ID查询用户 GET /api/users/{id}
    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable Integer id) {
        return userList.stream()
                .filter(user -> user.getId().equals(id))
                .findFirst()
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }

    // 3. 新增用户 POST /api/users
    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        user.setId(idGenerator.getAndIncrement());
        userList.add(user);
        // REST 规范:新增资源返回 201 状态码
        return ResponseEntity.status(HttpStatus.CREATED).body(user);
    }

    // 4. 全量更新用户 PUT /api/users/{id}
    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(
            @PathVariable Integer id,
            @RequestBody User user
    ) {
        return userList.stream()
                .filter(u -> u.getId().equals(id))
                .findFirst()
                .map(existUser -> {
                    existUser.setName(user.getName());
                    existUser.setDob(user.getDob());
                    existUser.setEmail(user.getEmail());
                    return ResponseEntity.ok(existUser);
                })
                .orElse(ResponseEntity.notFound().build());
    }

    // 5. 删除用户 DELETE /api/users/{id}
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Integer id) {
        userList.removeIf(user -> user.getId().equals(id));
        // REST 规范:删除成功返回 204 无内容
        return ResponseEntity.noContent().build();
    }
}

启动类

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

全局配置

无需在每个实体类加注解,全局统一配置更简洁,在 application.yml 中配置:

spring:
  jackson:
    # 全局忽略 null 字段(替代 @JsonInclude)
    default-property-inclusion: non_null
    # 全局日期格式化
    date-format: yyyy-MM-dd HH:mm:ss
    # 时区
    time-zone: GMT+8
    # 格式化输出 JSON(方便调试)
    serialization:
      indent-output: true

优先级规则:注解 > 全局配置(注解可覆盖全局设置)


接口测试

请求地址

GET http://localhost:8080/api/users

响应 JSON

[
    {
        "id": 1,
        "full_name": "Vishnu Chauhan",
        "dob": "1998-05-20",
        "email": "vishnu@example.com"
    }
]

验证结果:

  1. namefull_name@JsonProperty 重命名生效

  2. password 字段消失:@JsonIgnore 忽略生效

  3. 日期格式标准化:@JsonFormat 格式化生效

  4. 无 null 字段:@JsonInclude 空值过滤生效


核心知识点

反序列化硬性要求

Jackson 将 JSON 转为 Java 对象时,必须有无参构造器,Lombok @NoArgsConstructor 可自动生成。

@JsonInclude 常用可选值

  • NON_NULL:忽略 null 字段(最常用)

  • NON_EMPTY:忽略 null + 空字符串 + 空集合

  • ALWAYS:始终序列化(默认值)

兼容前端多余字段

前端传递实体类不存在的字段时,添加注解避免 400 错误:

@JsonIgnoreProperties(ignoreUnknown = true)
public class User {}

最佳实践

  1. 统一规范:全局配置 Jackson,减少冗余注解

  2. 数据安全:密码、密钥等敏感数据必须用 @JsonIgnore 忽略

  3. 格式统一:全局固定日期格式、时区、空值处理规则

  4. 兼容性:默认忽略前端多余字段,提升接口健壮性

  5. 代码简化:必用 Lombok 简化实体类代码

  6. 分层清晰:JSON 转换仅在 Controller 层处理,不侵入业务逻辑


总结

  1. 核心定位:Jackson 是 Spring Boot 默认 JSON 库,自动完成序列化 / 反序列化

  2. 核心注解@JsonProperty(重命名)、@JsonIgnore(忽略字段)、@JsonFormat(格式化)、@JsonInclude(空值过滤)

  3. 必备条件:实体类必须有无参构造器,日期处理需引入专用依赖

  4. 最佳方案:全局配置为主,注解为辅,兼顾简洁性与灵活性