PG官网

400-920-5594
173-6014-8050
首页 > 资讯中心 > 技术分享
后端参数校验实战复盘:参数混乱、非法入参、空指针、业务错乱的统一校验治理方案
2026-09-30 30 技术分享

几乎所有后端项目初期都会出现一个通病:参数校验随心所欲。

开发为了快速迭代,所有参数判断全部手写if/else,有的接口校验、有的不校验、有的校验规则不一致。上线后频繁出现:空指针异常、负数金额入库、手机号格式错误、超出范围参数导致业务报错、非法脏数据落库。

零散的手写校验代码,不仅臃肿难维护,还极易出现校验遗漏。本文梳理参数校验所有高频坑点,给出可直接上线的统一注解校验规范 + 全局异常捕获 + 分组校验实战,适配所有SpringBoot项目。

一、参数校验最常见5大致命坑点

1. 全量手写if判断,代码极度冗余

每个接口单独写null判断、空串判断、长度判断、范围判断,重复代码满天飞,项目臃肿难维护,新增接口需要重复写大量校验逻辑。

2. 校验规则不统一,同字段不同规则

用户手机号、订单金额、账号状态等通用字段,不同接口校验规则不一致,有的宽松、有的严格,导致系统数据标准混乱,对账异常。

3. 只校验非空,不校验参数范围与格式

很多接口仅判断参数不为空,忽略数值正负、长度上限、正则格式。出现负数金额、超长备注、非法手机号、异常状态码,引发业务逻辑错乱。

4. 嵌套对象、集合参数完全不校验

单层参数偶尔校验,List集合、嵌套DTO内部字段完全裸奔,批量提交场景下,子参数非法无拦截,批量数据脏入库。

5. 校验异常无统一处理,返回格式混乱

参数错误直接抛出原生异常,前端返回信息杂乱、报错不友好,无法精准提示用户输入错误位置,前后端联调效率极低。

二、传统手写校验 VS 注解统一校验(优劣对比)

传统错误写法(冗余且极易漏判)

// 臃肿、重复、难维护
public Result createOrder(OrderDTO dto){
    if(dto == null){
        return Result.fail("参数不能为空");
    }
    if(dto.getAmount() == null || dto.getAmount() <= 0){
        return Result.fail("订单金额必须大于0");
    }
    if(dto.getPhone() == null || "".equals(dto.getPhone())){
        return Result.fail("手机号不能为空");
    }
    if(dto.getPhone().length() != 11){
        return Result.fail("手机号格式错误");
    }
    // 大量重复判断...
}

企业级正确写法(注解零代码校验)

public Result createOrder(@Valid @RequestBody OrderDTO dto){
    // 无需任何手写校验代码,全部注解自动校验
    return orderService.create(dto);
}

三、生产级DTO注解校验规范

基于 Hibernate Validator 实现,覆盖空值、长度、数值、正则、嵌套、集合全场景

@Data
public class OrderDTO {

    // 非空+数值范围校验
    @NotNull(message = "订单金额不能为空")
    @DecimalMin(value = "0.01", message = "订单金额必须大于0")
    private BigDecimal amount;

    // 手机号正则校验
    @NotBlank(message = "手机号不能为空")
    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
    private String phone;

    // 长度限制
    @Size(max = 200, message = "备注内容不能超过200字")
    private String remark;

    // 嵌套对象递归校验
    @Valid
    @NotNull(message = "收货信息不能为空")
    private AddressDTO address;

    // 集合批量递归校验
    @Valid
    @NotEmpty(message = "订单商品列表不能为空")
    private List<OrderItemDTO> itemList;
}

四、分组校验实战(新增/修改不同校验规则)

业务高频场景:新增无需ID、修改必须传ID,通过分组校验完美解决,无需拆分DTO

// 分组标识
public interface AddGroup {}
public interface UpdateGroup {}

@Data
public class UserDTO {
    // 新增不校验,修改必填
    @NotNull(message = "用户ID不能为空", groups = UpdateGroup.class)
    private Long userId;

    // 新增修改都必填
    @NotBlank(message = "用户名不能为空", groups = {AddGroup.class, UpdateGroup.class})
    private String username;
}

// 接口使用
@PostMapping("/add")
public Result add(@Validated(AddGroup.class) @RequestBody UserDTO dto){}

@PostMapping("/update")
public Result update(@Validated(UpdateGroup.class) @RequestBody UserDTO dto){}

五、全局异常统一处理(规范前端返回)

统一拦截参数校验异常,返回标准化JSON,前端无需适配多种报错格式

@RestControllerAdvice
public class GlobalExceptionHandler {

    // 拦截参数校验异常
    @ExceptionHandler(MethodArgumentValidException.class)
    public Result validException(MethodArgumentValidException e){
        String message = e.getBindingResult().getFieldError().getDefaultMessage();
        return Result.fail(message);
    }
}

六、参数校验落地规范

PG官网

  1. 所有接口入参统一使用注解校验,禁止手写if/else基础判断

  2. 基础字段统一校验规则:手机号、身份证、金额、账号全局统一正则与范围

  3. 嵌套对象、集合必须加@Valid,防止批量参数校验遗漏

  4. 区分分组校验,新增、修改、查询场景差异化校验

  5. 禁止参数裸奔入库,所有前端传入参数必须经过校验拦截

  6. 统一异常返回格式,杜绝原生异常直接返回前端

七、落地检查清单

PG官网

  • 项目是否去除大量冗余手写参数判断?

  • 非空、数值、长度、正则是否全部使用注解校验?

  • 嵌套对象、集合参数是否开启递归校验?

  • 新增/修改差异化场景是否使用分组校验?

  • 是否配置全局异常拦截,统一报错返回?

  • 通用字段是否全局统一校验标准?

八、总结

参数校验看似是基础小事,却是提升项目整洁度、减少线上BUG、规范数据标准的核心关键。

抛弃杂乱的手写if判断,统一使用注解校验+全局异常处理,不仅能大幅精简代码、降低维护成本,还能从源头拦截非法参数、杜绝脏数据,彻底解决因入参不规范导致的空指针、业务错乱、数据异常等顽固问题。

推荐文章查看更多》

网站地图