Java 请求与领域校验

校验应放在哪一层:输入边界校验与领域不变量如何分工。

#type / concept #status / growing #tech / dev #resource / java

[!info] 关联笔记

Java 请求与领域校验

这个概念为什么出现

不可信输入是常态。校验失败应快速、明确;领域不变量应在对象出生与状态迁移时守住,而不是只靠数据库报错。

[!abstract] 一句话理解 边界校验形状与权限;领域校验业务不变量;两者都不可只信客户端。

最小可运行示例

场景:下单命令校验

public record PlaceOrder(String skuId, int qty) {
    public PlaceOrder {
        if (skuId == null || skuId.isBlank()) throw new IllegalArgumentException("skuId");
        if (qty <= 0 || qty > 100) throw new IllegalArgumentException("qty");
    }
}

public class PlaceOrderValidationDemo {
    public static void main(String[] args) {
        try {
            new PlaceOrder("", 1);
        } catch (IllegalArgumentException ex) {
            System.out.println("reject: " + ex.getMessage());
        }
        System.out.println(new PlaceOrder("S1", 2));
    }
}
javac PlaceOrderValidationDemo.java && java PlaceOrderValidationDemo

期望含:

reject: skuId
PlaceOrder[skuId=S1, qty=2]

结合场景再看三个关注点

  1. 构造期守不变量
  2. 错误消息可映射到 API 字段
  3. Bean Validation 注解是工程化选项,不取代领域规则。

核心概念与准确模型

1. 分层

校验什么
控制器类型、必填、格式
应用服务用例前置条件
领域深度不变量
数据库最后防线约束

2. Bean Validation

jakarta.validation 注解与校验器(框架集成)。

边界情况与反直觉行为

  1. 部分更新(PATCH)校验不同。
  2. 国际化消息。
  3. 校验与事务顺序。

常见误区

[!warning] 常见误区:只做前端校验 可被绕过。

工程实践

  1. 统一错误响应结构。
  2. 复杂规则单测。
  3. 数据库约束双保险。
  4. 避免校验逻辑复制三份却不一致。

本节总结

  • 边界 + 领域双层
  • 失败要明确
  • 框架注解是工具

自测题

  1. 为什么领域层仍要校验?
  2. 校验失败用 400 还是 422?
参考答案
  1. 用例可能被多种入口调用,不变量必须在核心守住。
  2. 团队约定;关键是稳定且文档化(常 400 覆盖校验失败)。

延伸阅读与资料来源

资料类型支撑内容
Bean Validation规范/社区注解校验
创建于 2026/7/15 更新于 2026/7/15