pojo 应仅定义领域状态结构,禁用框架注解与业务逻辑;dto 需按接口边界独立设计,命名体现用途;转换须显式(如 mapstruct),禁用 beanutils;pojo 与 dto 均不得混入表现层注解。

POJO 里别放业务逻辑和框架注解
很多人一写 UserInfo 就顺手加上 @Data(Lombok)、@Entity、@Table,甚至 @NotBlank 校验注解。这直接破坏了 POJO 的纯粹性:它本该只是数据载体,不是 ORM 映射器,也不是校验规则容器。
真正高内聚的 POJO 只做一件事:清晰定义领域内的状态结构。其他职责全得剥离。
- 去掉所有 Lombok 注解(
@Data、@Builder等),手动写get/set和toString——哪怕多几行,也换来可调试性与 IDE 友好性 - 不引入任何 Spring、Hibernate、Validation 包的类或注解;包路径建议用
com.example.domain.model - 字段类型优先选不可变类型:
String没问题,但避免裸露ArrayList;集合用List<string></string>而非ArrayList<string></string>,构造时用Arrays.asList()或Collections.unmodifiableList()
DTO 必须按接口边界切分,不能复用 POJO
常见错误是把 User POJO 直接当 DTO 传给前端或 Feign 接口,结果数据库字段(如 passwordSalt)漏删,或响应字段名(user_name)和前端约定(userName)不一致,又或者新增字段没同步导致 JSON 序列化失败。
DTO 不是“简化版 POJO”,而是为**某一次具体通信契约**定制的数据结构。
- 每个 HTTP 接口的请求/响应各建独立类,例如
CreateUserRequestDto、UserProfileResponseDto,命名体现用途和方向 - 字段名严格匹配调用方要求,用
@JsonProperty("user_name")控制序列化键,而不是靠全局配置驼峰转下划线 - 禁止在 DTO 中加方法(哪怕是
toPojo());转换逻辑统一交给Mapper层(如 MapStruct)或 Service 方法 - 如果多个 DTO 需共享部分字段(如分页信息),抽成
PageQueryDto或BaseResponseDto,但绝不继承 POJO
POJO ↔ DTO 转换必须显式、不可省略
用 BeanUtils.copyProperties() 或手动赋值看似简单,实则埋雷:字段名稍有差异就静默失败;新增字段不自动同步;集合嵌套时直接浅拷贝出错;泛型擦除后类型丢失。
显式转换的核心是「可查、可控、可测」。
- 禁用 Spring
BeanUtils和 Apache CommonsBeanUtils;它们跳过异常、不报类型不匹配、无法处理嵌套对象 - 推荐 MapStruct:编译期生成类型安全的转换代码,字段名不一致会编译报错,支持
@Mapping(target = "userName", source = "pojo.name") - 如果不用 MapStruct,至少封装一个
UserConverter工具类,每个转换方法单独写,不共用通用 copy 方法 - 所有转换入口必须带断言或日志:比如
Objects.requireNonNull(pojo, "pojo must not be null"),避免空指针穿透到下游
警惕「伪解耦」:JSON 序列化层的隐式绑定
你以为 POJO 和 DTO 分开了,但 Jackson 默认会把 @JsonIgnore、@JsonInclude 这些注解写在 POJO 上,等于又把表现层逻辑污染回领域模型。
更隐蔽的问题是:前端传了个 {"id":"abc"},后端 POJO 的 id 是 Long 类型,Jackson 默默转成 0 —— 没报错,但业务逻辑崩了。
- DTO 类上统一加
@JsonInclude(JsonInclude.Include.NON_NULL),POJO 类上绝对不加任何 Jackson 注解 - 对关键字段(如 ID、金额、时间戳)启用严格反序列化:
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", lenient = false) - 接收参数统一用
@Valid+@RequestBody,校验失败返回 400 并带明确字段错误(BindingResult处理) - 不要依赖 Jackson 的自动类型推断;枚举字段必须用
@JsonValue/@JsonCreator显式控制序列化行为
@Column 或 @ApiModelProperty。那几毫秒的偷懒,会在三个月后的联调现场变成两小时的排查。










