对于我们新手来说,似乎按照对应的规则配置, 就能接受返回参数, controller层上得到或返回一个对象; 其实内部有个序列化/反序列化操作,上文实体类的注解就需要我们理解一下这些逻辑了
为什么必须序列化/反序列化?
HTTP 协议传输的数据本质上是文本(字符串),它不认识 Java 对象或 JavaScript 对象。所以对象在传输前必须转换成字符串,接收方再把字符串还原成对象。
后端 Java 对象 ──[序列化]──→ JSON 字符串 ──[HTTP 传输]──→ JSON 字符串 ──[反序列化]──→ 前端 JS 对象
前端 JS 对象 ──[序列化]──→ JSON 字符串 ──[HTTP 传输]──→ JSON 字符串 ──[反序列化]──→ 后端 Java 对象
后端 → 前端
// 后端:Java 对象
Order order = new Order();
order.setId(1L);
order.setCreateTime(LocalDateTime.now());
// 序列化:Java 对象 → JSON 字符串
// {"id":1,"createTime":"2026-07-15 10:50:00"}
return order; // Spring 自动通过 Jackson/FastJSON 序列化后返回
// 前端:收到 JSON 字符串,自动反序列化为 JS 对象
fetch('/order/1').then(res => res.json()).then(data => {
console.log(data.id); // 1
console.log(data.createTime); // "2026-07-15 10:50:00"
});
前端 → 后端
// 前端:JS 对象
const order = {
id: 1,
createTime: "2026-07-15 10:50:00"
};
// 序列化:JS 对象 → JSON 字符串,通过 HTTP 发送
fetch('/order', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(order) // 手动或框架自动序列化
});
// 后端:收到 JSON 字符串,反序列化为 Java 对象
@PostMapping("/order")
public void createOrder(@RequestBody Order order) { // Spring 自动反序列化
System.out.println(order.getId()); // 1
System.out.println(order.getCreateTime()); // LocalDateTime 对象
}
| 传输内容 | 是否需要序列化 | 说明 |
|---|---|---|
| 对象/复杂数据结构 | ✅ 必须 | 转成 JSON 字符串传输 |
| 简单类型(String、Number) | 可以看作隐式序列化 | 本质也是转成字符串 |
| 文件(二进制) | ✅ 但方式不同 | 通常用 multipart/form-data,不是 JSON 序列化 |
| URL 参数(?id=1&name=xxx) | ✅ 但方式不同 | 用 URL 编码,不是 JSON 序列化 |
这也是为什么前面讨论的 @JsonFormat、@JSONField、@DateTimeFormat 这些注解如此重要——它们就是在控制序列化和反序列化过程中日期字段的格式。
规则
JSON 序列化框架(FastJSON、Jackson)的默认规则是:
序列化:把对象中所有非静态、非瞬态的字段(或有 getter 的属性)转成 JSON 键值对
反序列化:把 JSON 中的键值对,按字段名匹配,自动赋值给对象的对应属性(通过 setter 或直接字段访问)
@Data
public class Order {
private Long id;
private String name;
private Integer relatedFundProjectCount; // 普通属性,什么都没加
}
// 序列化:Java → JSON
Order order = new Order();
order.setId(1L);
order.setName("测试订单");
order.setRelatedFundProjectCount(5);
String json = JSON.toJSONString(order);
// 输出:{"id":1,"name":"测试订单","relatedFundProjectCount":5} ✅ 正常
// 反序列化:JSON → Java
String jsonInput = "{\"id\":2,\"name":"另一个订单","relatedFundProjectCount":10}";
Order order2 = JSON.parseObject(jsonInput, Order.class);
System.out.println(order2.getRelatedFundProjectCount()); // 10 ✅ 正常
类的转换
实体类里, 以下常见类型都不需要加任何注解,框架内置了转换器:
| 类型 | 示例 |
|---|---|
| 基本类型及包装类 | Integer、Long、Boolean、Double |
| 字符串 | String |
| 集合 | List、Set、Map |
| 数组 | String[]、Integer[] |
| 嵌套对象 | User、OrderItem 等自定义类 |
只有框架不知道该怎么转的类型,才需要加注解或自定义转换器:
| 类型 | 问题 | 解决方案 |
|---|---|---|
Date / LocalDateTime | 格式不统一 | @JSONField(format = ...) |
LocalDate | 格式不统一 | @JSONField(format = ...) |
| 枚举 | 默认输出序号或名称,可能不符合需求 | @JSONField 或自定义序列化器 |
特殊对象(如 BigDecimal 需要指定精度) | 默认行为不满足 | 自定义序列化器 |
普通属性(Integer、String、Long 等)什么都不加,序列化和反序列化都能正常工作。
加注解(如 @JSONField)只是用来覆盖默认行为,比如改格式、改字段名、忽略字段等。不需要特殊处理时,就不用加。
Jackson(Spring Boot 默认)
为什么要写@Data
除了在代码里 使用set, get方法, 用这个注解的还有个重要作用就是 Spring Boot 默认Jackson默认的字段可见性策略是
- 序列化:找 public 的 getter 方法 或 public 的字段
- 反序列化:找 public 的 setter 方法 或 public 的字段
所以,不写 getter/setter 也能序列化/反序列化,只是 Jackson 默认配置下不行,需要额外配置。而 FastJSON 和 Lombok 方案天然支持。
JSON.toJSONString, JSON.parseObject
有时候 数据库存了一个json类型的字符串, 用的就是上的方法
// 序列化:Java → JSON
Order order = new Order();
order.setId(1L);
order.setName("测试订单");
order.setRelatedFundProjectCount(5);
String json = JSON.toJSONString(order);
// 输出:{"id":1,"name":"测试订单","relatedFundProjectCount":5} ✅ 正常
// 反序列化:JSON → Java
String jsonInput = "{\"id\":2,\"name":"另一个订单","relatedFundProjectCount":10}";
Order order2 = JSON.parseObject(jsonInput, Order.class);
System.out.println(order2.getRelatedFundProjectCount()); // 10 ✅ 正常
160



被折叠的 条评论
为什么被折叠?



