结论先行:
前端统一 snake_case,后端统一 camelCase,由 Jackson 全局自动完成双向映射。
这是 Jackson 层面的统一协议问题,不应该在 DTO/VO 上"手工处理"。
在 大项目体量里,必须做到全局自动转换、零侵入、零重复注解。
一、核心机制:Jackson 命名策略(双向自动)
Jackson 原生支持 序列化 & 反序列化同时生效。
| 场景 | 行为 |
|---|---|
| Request JSON → Java DTO | access_token → accessToken |
| Java VO → Response JSON | accessToken → access_token |
无需在字段上写任何注解。
二、推荐方案(全局配置,唯一入口)
1. application.yml(首选,最干净)
yaml
spring:
jackson:
property-naming-strategy: SNAKE_CASE
这一行就够了。
2. 等价 Java 配置(如果你偏代码化)
java
@Configuration
public class JacksonConfig {
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
return mapper;
}
}
建议用 yml,避免 ObjectMapper 多实例污染。
三、示例:LoginRequest / LoginVO
1. LoginRequest(后端代码,驼峰)
java
public class LoginRequest {
private String account;
private String password;
private String loginType;
}
前端请求 JSON(下划线)
json
{
"account": "13800138000",
"password": "123456",
"login_type": "PASSWORD"
}
Jackson 自动映射为:
java
loginRequest.getLoginType(); // PASSWORD
2. LoginVO(后端代码,驼峰)
java
public class LoginVO {
private String accessToken;
private String refreshToken;
private Long expiresIn;
}
返回给前端 JSON(自动下划线)
json
{
"access_token": "xxx",
"refresh_token": "yyy",
"expires_in": 7200
}
四、为什么这是大项目必须采用的方式
1. 前端世界就是 snake_case
- iOS / Android / 小程序 / OpenAPI
- 多语言 SDK 生成器默认 snake_case
- JSON Schema / OpenAPI 更友好
2. Java 世界必须 camelCase
- Lombok / Bean 规范
- MyBatis / MapStruct
- IDE 自动补全
3. 中间层自动转换,才是工业级解法
五、禁止的"反模式"(踩一个就会后悔)
❌ 每个字段写 @JsonProperty
java
@JsonProperty("access_token")
private String accessToken;
问题:
- DTO 爆炸
- 重构成本极高
- 其他开发人员一定骂你
❌ Request / Response 分两套字段名
java
private String access_token;
问题:
- Java 规范被破坏
- IDE / Lombok / Mapper 全部痛苦
六、特殊情况如何处理(白名单)
1. 单字段例外
java
@JsonProperty("openid")
private String openId;
只在:
- 第三方强绑定字段
- 历史兼容接口
2. 禁止自动转换的字段
java
@JsonNaming(PropertyNamingStrategies.LowerCamelCaseStrategy.class)
public class ThirdPartyCallbackRequest {
}
七、与 Swagger / OpenAPI 的一致性
启用后:
- Swagger 显示字段名:
access_token - 后端字段:
accessToken - 文档 = 实际接口
八、最终统一规范(一句话版)
后端代码只写驼峰;
API 协议只暴露下划线;
Jackson 全局负责翻译。