知用网
霓虹主题四 · 更硬核的阅读氛围

参数校验在哪个层做?别再搞混了

发布时间:2026-01-11 17:21:11 阅读:22 次

开发接口的时候,总有人争论:参数校验到底该放在哪一层?Controller?Service?还是 DTO 里?

常见的三层结构

大多数项目都分 Controller、Service、DAO 三层。用户请求进来,先到 Controller,再调 Service 处理业务,最后访问数据库。那参数校验放哪儿合适?

放在 Controller 层最合理

Controller 是入口,就像小区的门卫。快递员来了,门卫先看是不是合法访客,带不带证件,包裹有没有贴单。不符合条件直接拦下,不用让住户出来处理。

同理,前端传了个空字符串或者格式错误的邮箱过来,Controller 应该第一时间发现并返回 400 错误,别把脏数据往里面传。Spring Boot 用 @Valid 注解就能轻松实现:

@PostMapping("/users")
public ResponseEntity<String> createUser(@Valid @RequestBody UserRequest request) {
    userService.create(request);
    return ResponseEntity.ok("创建成功");
}

配合 @NotBlank、@Email 这些注解,基本的合法性检查就有了。

Service 层要不要再校验?

如果你觉得“万一对方绕过 Controller 直接调 Service 呢”,那确实得防一手。但这种情况属于内部调用,责任分明。比如你同事写了个定时任务调你的方法,传了个 null 进来,这时候报错让他自己改就行。

Service 更关注业务规则,比如“用户年龄必须大于18才能注册会员”,这种不是格式问题,而是逻辑约束。这类判断留在 Service 没毛病。

if (user.getAge() < 18) {
    throw new BusinessException("未成年人不能开通会员");
}

DTO 自带校验注解

很多人喜欢在 DTO(数据传输对象)上加 @NotNull、@Min 这些注解,然后在 Controller 里用 @Valid 触发。这其实是推荐做法,把校验规则定义在数据结构上,清晰又复用。

比如同一个 UserRequest,在新增和修改时可能校验规则不同,可以用分组来区分:

public class UserRequest {
    @Null(groups = Create.class)
    @NotNull(groups = Update.class)
    private Long id;

    @NotBlank
    private String name;
}

别在 DAO 层做参数校验

DAO 只管和数据库打交道。你让它去判断字符串长度是不是超了,等于让收银员去检查顾客身份证真伪——职责错乱。而且等走到 DAO,说明前面层层失守,系统已经处于异常状态了。

小项目可以灵活点

两三个接口的小工具,非要把校验拆来拆去反而累赘。直接在 Controller 里 if 判断也无妨。重点是别让错误数据流入核心流程。

就像煮面,水没开就下面条,结果只能是一锅糊。参数校验就是烧开水这一步,别省。