Spring Validation 参数校验框架
文章目录
步骤
-
引入Spring Validation 的起步依赖
-
在阐述前面添加@Pattern注解
-
在 Controller 类上添加 @Validated 注解
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
@RestController
@Validated
@RequestMapping("/user")
public class UserController {
@PostMapping("/register")
public Result UserRegister(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$")String password) {
//查询用户
User user = userService.findByUserName(username);
if (user == null) {
//注册
userService.register(username, password);
return Result.success();
} else {
return Result.error("用户已存在!");
}
}
}
校验规则
@Pattern(regexp=“正则表达式”)
下面是常用的正则表达式:
1 匹配首尾空格的正则表达式:(^\s*)|(\s*$)
2 整数或者小数:^[0-9]+\.{0,1}[0-9]{0,2}$
3 只能输入数字:"^[0-9]*$"。
4 只能输入n位的数字:"^\d{n}$"。
5 只能输入至少n位的数字:"^\d{n,}$"。
6 只能输入m~n位的数字:。"^\d{m,n}$"
7 只能输入零和非零开头的数字:"^(0|[1-9][0-9]*)$"。
8 只能输入有两位小数的正实数:"^[0-9]+(.[0-9]{2})?$"。
9 只能输入有1~3位小数的正实数:"^[0-9]+(.[0-9]{1,3})?$"。
10 只能输入非零的正整数:"^\+?[1-9][0-9]*$"。
11 只能输入非零的负整数:"^\-[1-9][]0-9"*$。
12 只能输入长度为3的字符:"^.{3}$"。
13 只能输入由26个英文字母组成的字符串:"^[A-Za-z]+$"。
14 只能输入由26个大写英文字母组成的字符串:"^[A-Z]+$"。
15 只能输入由26个小写英文字母组成的字符串:"^[a-z]+$"。
16 只能输入由数字和26个英文字母组成的字符串:"^[A-Za-z0-9]+$"。
17 只能输入由数字、26个英文字母或者下划线组成的字符串:"^\w+$"。
18 验证用户密码:"^[a-zA-Z]\w{5,17}$"正确格式为:以字母开头,长度在6~18之间,只能包含字符、数字和下划线。
19 验证是否含有^%&',;=?$\"等字符:"[^%&',;=?$\x22]+"。
20 只能输入汉字:"^[\u4e00-\u9fa5]{0,}$"
21 验证Email地址:"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$"。
22 验证InternetURL:"^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$"。
23 验证电话号码:"^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$"正确格式为:"XXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"和"XXXXXXXX"。
24 验证身份证号(15位或18位数字):"^\d{15}|\d{18}$"。
25 验证一年的12个月:"^(0?[1-9]|1[0-2])$"正确格式为:"01"~"09"和"1"~"12"。
26 验证一个月的31天:"^((0?[1-9])|((1|2)[0-9])|30|31)$"正确格式为;"01"~"09"和"1"~"31"。
27 匹配中文字符的正则表达式: [\u4e00-\u9fa5]
28 匹配双字节字符(包括汉字在内):[^\x00-\xff]
29 应用:计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)
30 String.prototype.len=function(){return this.replace(/[^\x00-\xff]/g,"aa").length;}
31 匹配空行的正则表达式:\n[\s| ]*\r
32 匹配html标签的正则表达式:<(.*)>(.*)<\/(.*)>|<(.*)\/>
参数校验失败异常处理
-
导入 validation 坐标
-
在参数上添加 @Pattern 注解,指定校验规则
-
在 Controller 类上添加 @Validated 注解
-
在全局异常处理器中处理参数校验失败的异常
/** * 全局异常处理器 */ @RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public Result handlerException(Exception e){ e.printStackTrace(); return Result.error(StringUtils.hasLength(e.getMessage())?e.getMessage():"操作失败!"); } }
对实体类参数进行校验
-
@NotNull 值不能为空
-
@NotEmpty 值不能为空,并且内容不为空
-
@Email 满足邮箱格式
-
此外在引入实体类时只有加上 @Validared 注解才会生效
//lombok 编译阶段西东为实体类生成setter getter toString //使用方法:引入pom依赖,在实体类上添加注解 @Data public class User { @NotNull//值不能为空 private Integer id;//主键ID private String username;//用户名 @JsonIgnore//让 springmvc 把当前对象转化为 json 字符串的时候,忽略 password,最终 json 字符串中就没有 password 这个属性了 private String password;//密码 @NotEmpty//值不能为空,并且内容不为空 @Pattern(regexp = "^\\S{1,10}") private String nickname;//昵称 @Email//满足邮箱格式 private String email;//邮箱 private String userPic;//用户头像地址 private LocalDateTime createTime;//创建时间 private LocalDateTime updateTime;//更新时间 }
分组校验
方法一:
把校验项进行归类分组,在完成不同的功能的时候,校验指定组中的校验项
- 定义分组
- 定义校验项时指定归属的分组
- 校验是指定要校验的分组
实体类代码
实体类建立分组,使用groups属性进行分组
//实体类代码
@Data
public class Category {
//分组校验
public interface Add{//添加组
}
public interface update{//更新组
}
@NotNull(groups =update.class)
private Integer id;//主键ID
@NotEmpty(groups ={update.class,Add.class})//非空
private String categoryName;//分类名称
@NotEmpty(groups ={update.class,Add.class})//非空
private String categoryAlias;//分类别名
private Integer createUser;//创建人ID
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")//限定时间格式为 2024年3月4日 14:45:00
private LocalDateTime createTime;//创建时间
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;//更新时间
}
conlltroller 层代码
Controller中进行绑定需要校验的数据采用哪种组别进行校验
@PostMapping
public Result add(@RequestBody @Validated(Category.Add.class) Category category){
categoryService.add(category);
return Result.success();
}
@PutMapping
public Result update(@RequestBody @Validated(Category.update.class) Category category){
categoryService.update(category);
return Result.success();
}
方法二:
借助于 groups
属性
- 如果说校验项没有分组,默认属于
default
分组 - 分组之间可以继承,
a extends b
那么a
中拥有b
中所有校验项
@Data
public class Category {
//分组校验
//如果说校验项没有分组,默认属于 `default` 分组
//分组之间可以继承,a extends b 那么 a 中拥有 b 中所有校验项
public interface Add extends Default {//添加组
}
public interface update extends Default{//更新组
}
@NotNull(groups =update.class)
private Integer id;//主键ID
@NotEmpty//非空
private String categoryName;//分类名称
@NotEmpty//非空
private String categoryAlias;//分类别名
private Integer createUser;//创建人ID
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")//限定时间格式为 2024年3月4日 14:45:00
private LocalDateTime createTime;//创建时间
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;//更新时间
}
自定义校验
已有的注解不能满足所有的校验要求,特殊的情况需要自定义校验(自定义校验注解)
- 自定义注解State
- 自定义校验数据的类 StateValidation 实现 ConstraintValidator 接口
- 在需要校验的地方使用自定义注解
自定义校验接口
@Documented//元注解
//元注解 标明注解可以用在哪里,属性,方法,类....
//我们这里用到属性上,只需有field即可
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)//标明我们的注解会在哪个阶段保留,源码,编译,运行,
@Constraint(
validatedBy = {StateValidation.class}//指定提供校验规则的类
)//用来指定谁给注解提供校验规则
public @interface State {//自定义注解
String message() default "state 参数的值只能是已发布或草稿";//提供校验失败后的提示信息
//制定分组
Class<?>[] groups() default {};
//负载 获取到State注解的附加信息
Class<? extends Payload>[] payload() default {};
}
自定义规则类
/**
* ConstraintValidator<给那个注解提供校验,校验的数据类型>
*/
public class StateValidation implements ConstraintValidator<State,String> {
/**
*
* @param value 需要校验的数据
* @param constraintValidatorContext
* @return true:校验通过 false:校验不通过
*/
@Override
public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
//提供校验规则
if(value==null){
return false;//校验不通过
}
if(value.equals("已发布")||value.equals("草稿")){
return true;
}
return false;
}
}