0


SpringBoot参数校验

  • Session 认证和 Token 认证
  • 过滤器和拦截器
  • 基于Token认证的登录功能实现
  • SpringBoot统一返回和统一异常处理
  • SpringBoot项目logback日志配置
  • Spring事务
  • Spring AOP
  • 常用注解
  • SpringBoot参数校验

在日常项目开发中,我们都知道参数验证是必不可少的一环,但是有时候为了偷懒,把参数校验交给前端开发人员去处理,这样很容易影响系统稳定性和安全性,毕竟现在有很多手段可以绕过前端,直接后端请求接口。

本文就来介绍一下在

SpringBoot

应用中怎么进行参数校验。

一、使用参数校验注解

SpringBoot

项目中可以引用

spring-boot-starter-validation

实现数据验证。

spring-boot-starter-validation

不仅支持

JSR-303(Bean Validation 1.0)

规范,还提供了对

JSR-380(Bean Validation 2.0)

规范的全面支持。可以利用

Bean Validation 2.0

的新特性,更灵活地定义验证规则,包括对集合、嵌套对象的验证等。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>2.4.3</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>

通常在实体类上的字段上使用标准的

Bean Validation

注解,以下是一些常用的参数校验注解以及相关例子。

注解名称

功能

@Null

检查该字段为空

@NotNull

不能为null

@NotBlank

不能为空,常用于检查空字符串

@NotEmpty

不能为空,多用于检测list是否size是0

@Max

该字段的值只能小于或等于该值

@Min

该字段的值只能大于或等于该值

@Past

检查该字段的日期是在过去

@Future

检查该字段的日期是否是属于将来的日期

@Email

检查是否是一个有效的email地址

@Pattern(regex=,flag=)

被注释的元素必须符合指定的正则表达式

@Range(min=,max=,message=)

被注释的元素必须在合适的范围内

@Size(min=, max=)

检查该字段的size是否在min和max之间,可以是字符串、数组、集合、Map等

@Length(min=,max=)

检查所属的字段的长度是否在min和max之间,只能用于字符串

@AssertTrue

用于boolean字段,该字段只能为true

@AssertFalse

该字段的值只能为false

1.1、基本用法

1.@NotNull:校验元素值不能为空,如果为空,则校验失败。

@NotNull(message ="名字不能为空")privateString userName;

2.@NotBlank:校验字符串值不能为null和空字符串,必须包含至少一个非空字符即执行

trim

(之后不为’‘)。如果元素为

null

或者’',则验证失败。

@NotBlank(message ="昵称不能为null和空字符串")privateString nickName;

3.@NotEmpty:校验集合或者数组或者字符串是否非空,通常用于集合和数组字段,需要集合和数组元素个数大于

0

。也可以作用于字符串,此时校验字符串不能为

null

或空串(可以是一个空格)。

@NotEmpty(message ="postIds不能为空")privateLong[] postIds;

4.@Max:校验数字元素最大值。

@Max(value=100,message ="年龄最大100")privateString age;

5.@Min:校验数字元素最小值。

@Min(value=18,message ="年龄最小100")privateString age;

6.@Past:校验日期或时间元素是否在当前时间之前。即是否是过去时间。作用于

Date

相关类型的字段。

@Past(message ="")privateDate createTime;

7.@Future:校验日期或时间元素是否在当前时间之前。即是否是过去时间。作用于

Date

相关类型的字段。

@Future(message ="")privateDate createTime;

8.@Email:校验字符串元素是否为有效的电子邮件地址。

@Email(message ="")privateString email;

9.@Pattern:根据正则表达式校验字符串元素的格式。

@Pattern(regexp ="[a-zA-Z0-9]+")privateString userName;

10.@Size:校验集合元素个数或字符串的长度在指定范围内。

@Size(min =3, max =10, message ="长度在3到10之间")privateString username;

11.@Length:校验字符串元素的长度。作用于字符串。

@Length(min =3, max =10, message ="长度在3到10之间")privateString username;

以上只是部分注解和他们的功能,需要详细的了解需要查看源码。

1.2、用法示例

定义入参请求参数

packagecom.duan.pojo.vo;importcom.baomidou.mybatisplus.annotation.TableField;importio.swagger.annotations.ApiModelProperty;importlombok.Data;importjavax.validation.constraints.Email;importjavax.validation.constraints.NotBlank;/**
 * @author db
 * @version 1.0
 * @description SysUserVO
 * @since 2024/6/17
 */@DatapublicclassSysUserVO{@ApiModelProperty("部门ID")privateLong deptId;@NotBlank(message ="名字不能为空")@ApiModelProperty("用户名")privateString userName;@NotBlank(message ="昵称不能为null和空字符串")@ApiModelProperty("昵称")privateString nickName;@ApiModelProperty("密码")privateString password;@ApiModelProperty("用户性别(0男,1女")privateInteger gender;@ApiModelProperty("手机号码")privateString phone;@Email(message ="请填写正确的邮箱地址")@ApiModelProperty("邮箱")privateString email;@ApiModelProperty("头像地址")privateString avatarName;@ApiModelProperty("用户类型(0管理员,1普通用户")privateInteger userType;@ApiModelProperty("状态:1启用、0禁用")privateInteger status;@ApiModelProperty("备注")privateString remark;}

定义

mapper
packagecom.duan.mapper;importcom.baomidou.mybatisplus.core.mapper.BaseMapper;importcom.duan.pojo.SysUser;importorg.apache.ibatis.annotations.Mapper;@MapperpublicinterfaceUserMapperextendsBaseMapper<SysUser>{}

定义接口

packagecom.duan.service;importcom.baomidou.mybatisplus.extension.service.IService;importcom.duan.pojo.SysUser;publicinterfaceUserServiceextendsIService<SysUser>{voidAddUser(SysUserVO sysUserVO);}

定义接口实现

packagecom.duan.service.impl;importcom.baomidou.mybatisplus.extension.service.impl.ServiceImpl;importcom.duan.mapper.UserMapper;importcom.duan.pojo.SysUser;importcom.duan.service.UserService;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;/**
 * @author db
 * @version 1.0
 * @description UserServiceImpl
 * @since 2024/4/15
 */@ServicepublicclassUserServiceImplextendsServiceImpl<UserMapper,SysUser>implementsUserService{@AutowiredprivateUserMapper userMapper;@OverridepublicvoidAddUser(SysUserVO sysUserVO){SysUser sysUser =newSysUser();BeanUtils.copyProperties(sysUserVO,sysUser);
        userMapper.insert(sysUser);}}

定义

controller
packagecom.duan.controller;importcom.duan.pojo.ResponseResult;importcom.duan.pojo.Result;importcom.duan.pojo.SysUser;importcom.duan.service.UserService;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.validation.annotation.Validated;importorg.springframework.web.bind.annotation.PostMapping;importorg.springframework.web.bind.annotation.RequestBody;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;/**
 * @author db
 * @version 1.0
 * @description UserController
 * @since 2024/4/15
 */@RestController@RequestMapping("/user")publicclassUserController{@AutowiredprivateUserService userService;@PostMapping("/addUser")publicResponseResultaddUser(@RequestBody@ValidatedSysUserVO sysUserVO){userService.AddUser(sysUserVO);returnResponseResult.okResult();}}
1.3、示例测试

调用增加用户接口

注意:我们需要捕获一下

MethodArgumentNotValidException

,才能如上图显示的那样。

1.4、嵌套对象的验证

SysUserVO

中增加一个

address

的校验,即需要对嵌套对象进行校验。

packagecom.duan.pojo.vo;importlombok.Data;importjavax.validation.constraints.NotBlank;/**
 * @author db
 * @version 1.0
 * @description AddressVO
 * @since 2024/6/17
 */@DatapublicclassAddressVO{@NotBlank(message ="省份不能为空")privateString province;@NotBlank(message ="城市不能为空")privateString city;}
AddressVO

对象如下所示:

packagecom.duan.pojo.vo;importlombok.Data;importjavax.validation.constraints.NotBlank;/**
 * @author db
 * @version 1.0
 * @description AddressVO
 * @since 2024/6/17
 */@DatapublicclassAddressVO{@NotBlank(message ="省份不能为空")privateString province;@NotBlank(message ="城市不能为空")privateString city;}

测试

说明:为了能够进行嵌套对象验证,必须手动在

SysUserVO

实体的

addressVo

字段上明确指出这个字段里面的实体需要验证,由于

@Vaildated

不能作用在成员属性上,而且

@Valid

能加在成员属性上,同时配合

controller

中在方法参数上

@Validated

@Valid

来进行嵌套验证。

这里必须要说明一下

@Validated

@Valid

的区别

  1. 来源
  • @Validated:Spring 框架特有的注解,是标准 JSR-303 的一个变种,提供了一个分组功能
  • @Valid:标准 JSR-303 规范的标记型注解。
  1. 注解位置
  • @Validated:作用在类上、方法上、方法参数上,不能作用于成员属性上。
  • @Valid:方法、构造函数、方法参数、成员属性上。
  1. 分组
  • @Validated:支持分组验证。
  • @Valid:支持标准的 Bean 验证功能,不支持分组验证。
  1. 嵌套验证
  • @Validated:不支持嵌套验证。
  • @Valid:支持嵌套验证。

二、分组验证

同一个应用中,会出现不同的场景,比如:用户创建、用户更新、用户删除,针对不同的场景,有些字段在一个场景中需要验证,但是在另一个场景中该字段就不需要验证,我们可以选择新建不同的实体类去解决这类问题,比如:用户创建

UserCreateVO

、用户更新

UserUpdate

等,但是这样的做法会造成类的膨胀、代码的冗余。其实我们可以使用分组校验有选择的执行特定组的参数校验。定义分组校验需要注意两点:

  1. 定义分组必须使用接口。
  2. 要校验的字段必须加上分组,分组只对指定分组生效,不加分组不校验。
2.1、创建分组

创建两个分组接口,标识不同的业务场景CreateGroup用于创建时指定的分组

packagecom.duan.validatedGroup;/**
 * @author db
 * @version 1.0
 * @description CreateUserGroup
 * @since 2024/6/24
 */publicinterfaceCreateUserGroup{}
UpdateGroup

用于更新时指定的分组

packagecom.duan.validatedGroup;/**
 * @author db
 * @version 1.0
 * @description UpdateUserGroup
 * @since 2024/6/24
 */publicinterfaceUpdateUserGroup{}
2.2、使用分组校验

分组校验是通过在验证注解上指定

groups

属性来实现的。这个属性允许你为验证规则分配一个或多个验证组。假设用户创建时不传递用户

ID

,其余的参数必传,用户更新接口必须传递用户

ID

,可以不传递用户名,其他参数必须传递。

packagecom.duan.pojo.vo;importcom.baomidou.mybatisplus.annotation.TableField;importcom.duan.validatedGroup.CreateUserGroup;importcom.duan.validatedGroup.UpdateUserGroup;importio.swagger.annotations.ApiModelProperty;importlombok.Data;importjavax.validation.Valid;importjavax.validation.constraints.Email;importjavax.validation.constraints.NotBlank;importjavax.validation.constraints.NotNull;importjava.util.List;/**
 * @author db
 * @version 1.0
 * @description SysUserVO
 * @since 2024/6/17
 */@DatapublicclassSysUserVO{@NotBlank(message ="请选择用户",groups =UpdateUserGroup.class)privateLong id;@ApiModelProperty("部门ID")privateLong deptId;@NotBlank(message ="名字不能为空",groups =CreateUserGroup.class)@ApiModelProperty("用户名")privateString userName;@NotBlank(message ="昵称不能为null和空字符串")@ApiModelProperty("昵称")privateString nickName;@ApiModelProperty("密码")privateString password;@ApiModelProperty("用户性别(0男,1女")privateInteger gender;@ApiModelProperty("手机号码")privateString phone;@Email(message ="请填写正确的邮箱地址")@ApiModelProperty("邮箱")privateString email;@ApiModelProperty("头像地址")privateString avatarName;@ApiModelProperty("用户类型(0管理员,1普通用户")privateInteger userType;@ApiModelProperty("状态:1启用、0禁用")privateInteger status;@ApiModelProperty("备注")privateString remark;@NotNull(message ="请输入地址信息")@ValidprivateAddressVO addressVO ;}
2.3、在Controller中使用分组

使用

@Validated

注解,并指定要执行的验证。

packagecom.duan.controller;importcom.duan.pojo.ResponseResult;importcom.duan.pojo.Result;importcom.duan.pojo.SysUser;importcom.duan.pojo.vo.SysUserVO;importcom.duan.service.UserService;importcom.duan.validatedGroup.CreateUserGroup;importcom.duan.validatedGroup.UpdateUserGroup;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.validation.annotation.Validated;importorg.springframework.web.bind.annotation.PostMapping;importorg.springframework.web.bind.annotation.RequestBody;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;/**
 * @author db
 * @version 1.0
 * @description UserController
 * @since 2024/4/15
 */@RestController@RequestMapping("/user")publicclassUserController{@AutowiredprivateUserService userService;@PostMapping("/addUser")publicResponseResultaddUser(@RequestBody@Validated(value =CreateUserGroup.class)SysUserVO sysUserVO){
        userService.addUser(sysUserVO);returnResponseResult.okResult();}@PostMapping("/updateUser")publicResponseResultupdateUser(@RequestBody@Validated(value =UpdateUserGroup.class)SysUserVO sysUserVO){
        userService.updateUser(sysUserVO);returnResponseResult.okResult();}}
2.4、测试
  • 创建用户接口

username 不传值,即不满足 username 不能为空的条件,应该校验不通过。通过测试发现,会提示username不能为空。

  • 更新用户update接口

id写成0,

username

还是为空,只是报了

id

不能小于1

三、自定义验证注解

在项目开发中,我们也经常使用自定义注解去完成字段校验。自定义校验注解步骤如下:

  1. 编写一个自定义校验注解
  2. 编写一个自定义的校验器
  3. 关联自定义的校验器和自定义的校验注解

假如:

user

实体中的

password

字段,格式是大于八位且包含数字大写字母小写字母,这个自定义校验怎么实现呢?

1、首先定义一个注解
PasswordValid
packagecom.duan.anno;importcom.duan.config.PasswordValidValidator;importjavax.validation.Constraint;importjavax.validation.Payload;importjava.lang.annotation.Retention;importjava.lang.annotation.Target;importstaticjava.lang.annotation.ElementType.*;importstaticjava.lang.annotation.ElementType.TYPE_USE;importstaticjava.lang.annotation.RetentionPolicy.RUNTIME;@Constraint(validatedBy ={PasswordValidValidator.class})@Target({METHOD,FIELD,ANNOTATION_TYPE,CONSTRUCTOR,PARAMETER,TYPE_USE})@Retention(RUNTIME)public@interfacePasswordValid{Stringmessage()default"{密码格式不对}";Class<?>[]groups()default{};Class<?extendsPayload>[]payload()default{};}
2、定义一个校验器
PasswordValidValidator

自定义校验器需要实现

ConstraintValidator<A extends Annotation, T>

这个接口,第一个泛型是校验注解,第二个是参数类型。

packagecom.duan.config;importcom.duan.anno.PasswordValid;importjavax.validation.ConstraintValidator;importjavax.validation.ConstraintValidatorContext;/**
 * @author db
 * @version 1.0
 * @description PasswordValidValidator
 * @since 2024/6/25
 */publicclassPasswordValidValidatorimplementsConstraintValidator<PasswordValid,String>{@Overridepublicvoidinitialize(PasswordValid constraintAnnotation){}@OverridepublicbooleanisValid(String value,ConstraintValidatorContext context){if(value ==null){returnfalse;}boolean hasUppercase = value.chars().anyMatch(Character::isUpperCase);boolean hasLowercase = value.chars().anyMatch(Character::isLowerCase);boolean hasDigit = value.chars().anyMatch(Character::isDigit);return value.length()>=8&& hasUppercase && hasLowercase && hasDigit;}}
3、关联自定义的校验器和自定义的校验注解

当你使用

@Constraint(validatedBy = EnumValidator.class)

注解时,

Java Bean Validation

的实现框架会自动发现并注册相应的验证器。

@Constraint(validatedBy = { PasswordValidValidator.class})

SysUserVO

中使用

    @PasswordValid(groups = CreateUserGroup.class)
    @ApiModelProperty("密码")
    private String password;

模拟输入

password

为纯数字时,校验不通过。

代码地址:

https://gitee.com/duan138/practice-code/tree/master/paramValidated
四、总结

本文我们了解和实践在

SpringBoot

项目中,怎么去使用基本的校验注解、嵌套校验、分组校验,同时又学习了怎么使用自定义校验注解,在项目中合理地使用相关校验注解,可以简化代码、提高代码可读性和可维护性。


改变你能改变的,接受你不能改变的,关注公众号:程序员康康,一起成长,共同进步。

标签: spring boot 后端 java

本文转载自: https://blog.csdn.net/abc_138/article/details/141904973
版权归原作者 cxykk1217 所有, 如有侵权,请联系我们删除。

“SpringBoot参数校验”的评论:

还没有评论