java后端参数校验validaction(用法详解)
Posted 野生java研究僧
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java后端参数校验validaction(用法详解)相关的知识,希望对你有一定的参考价值。
validaction详解
1.前言
beanvalidation官网:https://beanvalidation.org/(是规范,api接口)
hibernate官网:https://hibernate.org/validator/(是beanvalidation的最佳实现)
添加依赖包
hibernate-validator 或jakarta.activation
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.2.Final</version>
</dependency>
<!-- jakarta 规范版本,和javax版本内容一样,只是包名不同而已 -->
<dependency>
<groupId>jakarta.activation</groupId>
<artifactId>jakarta.activation-api</artifactId>
<version>2.0.1</version>
</dependency>
springBoot项目可以引入这个:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>1.4.0.RELEASE</version>
</dependency>
或
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
校验提示信息
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
<version>9.0.29</version>
</dependency>
2.初体验
ValidationUtil工具类
public class ValidationUtil {
// 线程安全
private static Validator validator ;
static{
validator = Validation.buildDefaultValidatorFactory().getValidator();
}
/**
* 校验
* @param userInfo 校验的对象
* @return 校验失败的信息
*/
public static List<String> valid(UserInfo userInfo){
// 没有通过,则set里面就哟校验信息
Set<ConstraintViolation<UserInfo>> set = validator.validate(userInfo);
List<String> list = set.stream().map(v -> "属性:" + v.getPropertyPath()
+ " 属性值:" + v.getInvalidValue()
+ " 提示信息:" + v.getMessage()).collect(Collectors.toList());
list.stream().forEach(System.out::println);
return list;
}
}
需要校验的Bean
public class UserInfo {
private Long id;
@Null
private String name;
private Integer age;
private String email;
private String phone;
private LocalDateTime birthDay;
private String personalPage;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public LocalDateTime getBirthDay() {
return birthDay;
}
public void setBirthDay(LocalDateTime birthDay) {
this.birthDay = birthDay;
}
public String getPersonalPage() {
return personalPage;
}
public void setPersonalPage(String personalPage) {
this.personalPage = personalPage;
}
@Override
public String toString() {
return "UserInfo{" +
"id=" + id +
", name='" + name + '\\'' +
", age=" + age +
", email='" + email + '\\'' +
", phone='" + phone + '\\'' +
", birthDay=" + birthDay +
", personalPage='" + personalPage + '\\'' +
'}';
}
}
校验
@Test
void test2(){
UserInfo userInfo = new UserInfo();
userInfo.setName(null);
ValidationUtil.valid(userInfo);
}
校验结果:
3.JSR校验注解
可以在javax.validation.constraints包下看到支持的所有注解
注解 | 注解作用说明 |
---|---|
@Null | 被注释的元素值必须为 null |
@NotNull | 被注释的元素值必须不为 null |
@Pattern(regex=) | 被注释的元素字符串必须符合指定的正则表达式 |
@Size(max=, min=) | 集合元素数量必须在min和max范围内 |
@AssertTrue | 被注释的元素必须为 true |
@AssertFalse | 被注释的元素必须为 false |
@Min(value) | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值(为null校验通过) |
@Max(value) | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值(为null校验通过 |
@Range(min,max) | 数字必须在min和max范围内(为null校验通过) |
@DecimalMin(value) | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 |
@DecimalMax(value) | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 |
@Digits (integer, fraction) | 被注释的元素必须是一个数字,其值必须在可接受的范围内 |
@Past | 被注释的元素必须是一个过去的日期 |
@Future | 被注释的元素必须是一个将来的日期 |
字符串必须是Email地址 | |
@Safehtml | 字符串必须是安全的html |
@URL | 字符串必须是合法的URL |
| @Size(max,min) | 限制字符长度必须在min到max之间 |
4.Hibernate Validator校验注解:
可以在org.hibernate.validator.constraints包下看到支持的所有注解【该注解中有说明支持那些数据类型】,重复的我就省略掉了
注解 | 注解作用说明 |
---|---|
@NotBlank(message =) | 验证字符串非null,且trim后长度必须大于0 |
@Length(min=,max=) | 被注释的字符串的大小必须在指定的范围内 |
@NotEmpty | 被注释的字符串的必须非空(null,"") |
| @Valid | 对bean实体类进行级联校验 |
注:每个注解的属性值中都有一个message属性,可以自己定义校验未通过消息
@Min(value = 18,message = "年龄小于{value}岁,校验失败")
private Integer age; // 大于等于18
// 属性:age 属性值:17 提示信息:年龄小于18岁,校验失败
5.分组校验
默认的组为:javax.validation.groups.Default
例如:我们一个字段Id,需要在不同的场景下,进行不同的校验,向下面这样的方式就行不可以的,需要进行一个分组
@NotNull // 适应于修改
@Null //适应与新增
private Long id;
结局方案:使用分组校验 在实体类中定义需要分组的接口标记
public class UserInfo {
// 新增组标记接口
public interface UserInfoAdd{
}
// 修改组标记接口
public interface UserInfoUpdate{
}
@NotNull(groups = {UserInfoUpdate.class}) // 适应于修改
@Null(groups = {UserInfoAdd.class}) //适应与新增
private Long id;
}
ValidationUtil中稍作修改,进行校验的时候,指定使用那个组进行校验,记得加上默认组,避免之前的校验规则失效
public class ValidationUtil {
// 线程安全
private static Validator validator ;
static{
validator = Validation.buildDefaultValidatorFactory().getValidator();
}
/**
* 校验
* @param userInfo 校验的对象
* @return 校验失败的信息
*/
public static List<String> valid(UserInfo userInfo, Class<?> group){
// 没有通过,则set里面就哟校验信息
Set<ConstraintViolation<UserInfo>> set = validator.validate(userInfo, Default.class,group);
List<String> list = set.stream().map(v -> "属性:" + v.getPropertyPath()
+ " 属性值:" + v.getInvalidValue()
+ " 提示信息:" + v.getMessage()
+ " 消息模板:"+v.getMessageTemplate()
).collect(Collectors.toList());
list.stream().forEach(System.out::println);
return list;
}
}
6.级联校验
假设我们在UserInfo中有一个Grade属性然后设置@NotNull是可以校验成功的,但是我们Grade类本身字节有个number属性,也设置了@NotBlank,此时在进行校验的时候就不可以了,无法校验,此时就需要使用级联校验。只需要在引用的对象上加上 @Valid,被引用的对象中的校验规则也会随着生效
@NotNull
//在被引用对象上加上@Valid才可以完成级联校验
@Valid
private Grade grade;
7.自定义注解
假设我们现在业务中,有一个falg值来标识,表示我们的业务逻辑,比如说订单状态:1:未分配,2:已分配,3:处理完成,这样的话,显然原有的功能无法满足我们的需求,我们可以使用自定义注解来完成。
1.先自定义注解
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Created with IntelliJ IDEA.
*
* @Author: compass
* @Date: 2021-11-08-17:49
* @Version:1.0
* @Description: 自定义注解:被标注的字段属性值必须是:1,2,3其中一个
*/
@Target({ FIELD })
@Retention(RUNTIME)
@Documented
// 说明当前注解@UserInfoFlag要被谁来完成校验工作
@Constraint(validatedBy = { FlagValidation.class})
public @interface UserInfoFlag {
String message() default "校验不通过,flag不符合要求";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
2.对自定义注解的校验功能实现
/**
* Created with IntelliJ IDEA.
*
* @Author: compass
* @Date: 2021-11-08-17:47
* @Version:1.0
* @Description: 自定义注解
*/
//ConstraintValidator<自定义的注解标识,需要处理的数据类型>
public class FlagValidation implements ConstraintValidator<UserInfoFlag,String> {
@Override
public void initialize(UserInfoFlag constraintAnnotation) {
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
// 新建一个集合,放入1,2,3 如果如果集合中未包含value就校验失败
Set<String> set = new HashSet<>();
set.add("1");
set.add("2");
set.add("3");
return set.contains(value);
}
}
使用:在需要校验的字段上加上 @UserInfoFlag 注解即可
@UserInfoFlag(message = "校验失败,flag必须是 1,2,3中的一个")
private String flag;
8.快速失败校验
/**
* 只要有一个校验失败,立刻返回结果,生效的不予校验
* @param userInfo 校验的对象
* @return 校验失败的信息
*/
public static <c> List<String> validFastFail(UserInfo userInfo, Class<?> group){
// 没有通过,则set里面就哟校验信息 [加上默认组,避免之前的校验规则失效]
Set<ConstraintViolation<UserInfo>> set = failFast.validate(userInfo, Default.class,group);
List<String> list = set.stream().map(v -> "属性:" + v.getPropertyPath()
+ " 属性值:" + v.getInvalidValue()
+ " 提示信息:" + v.getMessage()
+ " 消息模板:"+v.getMessageTemplate()
).collect(Collectors.toList());
list.stream().forEach(System.out::println);
return list;
}
9.非Bean入参校验
修改一下校验方法,使用参数校验的模式
/**
* 非bean校验入参
* @param object 校验的对象
* @param method 校验的方法
* @param parameterValues 校验参数值
* @param groups 使用那个组进行校验
* @param <T>
* @return 校验结果
*/
public static <T> List<String> validNotBean(T object,
Method method,
Object[] parameterValues,
Class<?>... groups){
Set<ConstraintViolation<T>> set = executableValidator.validateParameters(object, method, parameterValues, groups);
List<String> list = set.stream().map(v -> "属性:" + v.getPropertyPath()
+ " 属性值:" + v.getInvalidValue()
+ " 提示信息:" + v.getMessage()
).collect(Collectors.toList());
list.stream().forEach(System.out::println);
return list;
}
测试方法
public class UserInfoService {
public String getByName(@NotNull String name){
String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
Method method =null;
try {
method = this.getClass().getDeclaredMethod(methodName, String.class);
}catch (Exception e){
}
ValidationUtil.validNotBean(this,method,new Object[]{name});
return "admin";
}
}
10spring mvc vaildaction校验
1.使用@Valid校验:@Valid的缺点,就是不能进行分组校验
springMVC之中已经提供了一系列的自动校验,我们只需要在需要校验的地方加上对应的注解即可
@RestController
public class UserController {
@GetMapping("/addUser")
public Map<String, String> addUser(@Valid UserInfo userInfo, BindingResult errorResult){
Map<String, String> map = new HashMap<>();
if (errorResult.hasErrorsJava Bean Validation 最佳实践