引言
在开发接口时,参数校验是必不可少的环节:前端传参是否为空、格式是否正确、数值是否合法,都需要后端严格校验,否则很容易出现脏数据、程序异常。
传统的 if-else 判空不仅代码臃肿,还容易遗漏,维护成本极高。
springboot 官方推荐使用 bean validation(jsr-380) 实现优雅的参数校验,通过注解一键完成校验,配合全局异常处理,让接口更健壮、代码更简洁。
今天就来介绍一下基础注解、实战使用、分组校验、自定义注解、嵌套校验、全局异常处理。
一、为什么要用 bean validation?
告别繁琐 if-else:不用写大量判空、判断逻辑,代码更简洁
注解式开发:一个注解完成一类校验,可读性极强
校验规则统一:团队协作无歧义
配合全局异常:校验失败自动返回友好提示,无需手动处理
支持复杂场景:分组校验、自定义校验、嵌套对象校验
二、核心依赖引入
springboot 2.x 版本直接引入以下依赖即可:
<dependency> <groupid>org.springframework.bootgroupid> <artifactid>spring-boot-starter-validationartifactid> <dependency> <dependency> <groupid>org.springframework.bootgroupid> <artifactid>spring-boot-starter-webartifactid> <dependency>
三、最常用校验注解
1. 空与非空校验
@notblank:字符串不能为 null,且去除空格后长度大于0(专用字符串)
@notnull:不能为 null,但可以是空字符串、空集合
@notempty:不能为 null,且长度/大小大于0(字符串、集合、数组)
2. 数值校验
@min:数值最小值@max:数值最大值@positive:正数@positiveorzero:正数或0@negative:负数@negativeorzero:负数或0
3. 格式校验
@email:邮箱格式@pattern:正则表达式自定义格式@length:字符串长度限制
4. 日期与时间
@past:必须是过去时间@pastorpresent:过去或当前时间@future:必须是未来时间@futureorpresent:未来或当前时间
四、单对象参数校验
1. 封装实体类 + 校验注解
importlombok.data;
importjavax.validation.constraints.*;
/**
* 用户参数接收类
*/
@data
publicclassuserdto{
@notblank(message ="用户id不能为空")
privatestring userid;
@notblank(message ="用户名不能为空")
@length(min =2, max =10, message ="用户名长度必须在2-10位之间")
privatestring username;
@notnull(message ="年龄不能为空")
@min(value =18, message ="年龄必须大于等于18岁")
@max(value =60, message ="年龄必须小于等于60岁")
privateinteger age;
@email(message ="邮箱格式不正确")
@notblank(message ="邮箱不能为空")
privatestring email;
@pattern(regexp ="^1[3-9]\\d{9}$", message ="手机号格式不正确")
privatestring phone;
}2. controller 开启校验(@valid)
@valid 是开启校验的核心注解,必须添加在参数前:
importorg.springframework.validation.bindingresult;
importorg.springframework.web.bind.annotation.postmapping;
importorg.springframework.web.bind.annotation.requestbody;
importorg.springframework.web.bind.annotation.requestmapping;
importorg.springframework.web.bind.annotation.restcontroller;
importjavax.validation.valid;
@restcontroller
@requestmapping("/user")
publicclassusercontroller{
/**
* 新增用户
*/
@postmapping("/add")
publicresult<string>adduser(@valid@requestbodyuserdto userdto){
// 校验通过,执行业务逻辑
returnresult.success("用户新增成功");
}
}五、配合全局异常处理
参数校验失败会抛出 methodargumentnotvalidexception,我们在全局异常处理器中捕获,统一返回格式:
importlombok.extern.slf4j.slf4j;
importorg.springframework.web.bind.methodargumentnotvalidexception;
importorg.springframework.web.bind.annotation.exceptionhandler;
importorg.springframework.web.bind.annotation.restcontrolleradvice;
importjava.util.stream.collectors;
@slf4j
@restcontrolleradvice
publicclassglobalexceptionhandler{
/**
* 捕获参数校验异常
*/
@exceptionhandler(methodargumentnotvalidexception.class)
publicresult<string>handlevalidexception(methodargumentnotvalidexception e){
// 拼接所有错误提示
string errormsg = e.getbindingresult().getfielderrors().stream()
map(error -> error.getfield()+":"+ error.getdefaultmessage())
collect(collectors.joining(";"));
log.error("参数校验异常:{}", errormsg);
returnresult.fail(400, errormsg);
}
}校验失败返回示例
{
"code":400,
"msg":"年龄必须大于等于18岁;邮箱格式不正确",
"data":null
}六、分组校验
实际业务中,新增和修改的校验规则不同:
- 新增:不需要传 id
- 修改:必须传 id
使用分组校验可完美解决。
1. 定义分组接口
/**
* 新增分组
*/
publicinterfaceaddgroup{
}
/**
* 修改分组
*/
publicinterfaceupdategroup{
}2. 实体类标注分组
@data
publicclassuserdto{
// 修改时必须传id,新增时不需要
@notblank(message ="用户id不能为空", groups =updategroup.class)
privatestring userid;
@notblank(message ="用户名不能为空", groups ={addgroup.class,updategroup.class})
privatestring username;
}3. controller 指定分组
使用 @validated 注解指定分组:
@restcontroller
@requestmapping("/user")
@validated
publicclassusercontroller{
// 新增:使用 addgroup 分组校验
@postmapping("/add")
publicresult<string>add(@validated(addgroup.class)@requestbodyuserdto userdto){
returnresult.success("新增成功");
}
// 修改:使用 updategroup 分组校验
@postmapping("/update")
publicresult<string>update(@validated(updategroup.class)@requestbodyuserdto userdto){
returnresult.success("修改成功");
}
}七、自定义校验注解
当内置注解不满足业务时,可自定义注解,例如校验性别只能是男/女。
1. 自定义注解@gender
importjavax.validation.constraint;
importjavax.validation.payload;
importjava.lang.annotation.*;
@target({elementtype.field})
@retention(retentionpolicy.runtime)
@constraint(validatedby =gendervalidator.class)// 绑定校验器
public@interfacegender{
stringmessage()default"性别只能输入:男/女";
class<?>[]groups()default{};
class<?extendspayload>[]payload()default{};
}2. 自定义校验器
importjavax.validation.constraintvalidator;
importjavax.validation.constraintvalidatorcontext;
publicclassgendervalidatorimplementsconstraintvalidator<gender,string>{
@override
publicbooleanisvalid(string value,constraintvalidatorcontext context){
// 校验逻辑
return"男".equals(value)||"女".equals(value);
}
}3. 使用自定义注解
@gender privatestring gender;
八、嵌套对象校验
如果参数是嵌套对象,需要在嵌套对象上添加 @valid 才能开启校验:
@data
publicclassuserdto{
@notblank
privatestring username;
@valid// 开启嵌套校验
@notnull(message ="地址信息不能为空")
privateaddressdto address;
}
@data
classaddressdto{
@notblank(message ="详细地址不能为空")
privatestring detail;
@notblank(message ="城市不能为空")
privatestring city;
}九、单个参数校验(非实体类)
如果接口是零散参数,在类上添加 @validated,直接给参数加注解:
@restcontroller
@requestmapping("/user")
@validated
publicclassusercontroller{
@getmapping("/get")
publicresult<string>getuser(
@notblank(message ="用户id不能为空")string userid,
@notnull(message ="状态不能为空")integer status
){
returnresult.success("查询成功");
}
}十、总结
@valid:开启实体类参数校验@validated:开启分组校验、单个参数校验- 常用注解:
@notblank、@notnull、@min、@max、@email - 全局异常捕获:校验失败自动返回友好提示
- 分组校验:适配新增/修改不同规则
- 自定义注解:满足复杂业务校验
学会这套参数校验方案,你的接口健壮性、规范性、安全性直接拉满!
以上就是springboot接口参数校验(bean validation)实战指南的详细内容,更多关于springboot接口参数校验的资料请关注代码网其它相关文章!
发表评论