详解java参数校验之:顺序校验、自定义校验、分组校验(@Validated @GroupSequence)

简介: 详解java参数校验之:顺序校验、自定义校验、分组校验(@Validated @GroupSequence)

当使用 @Validated、@GroupSequence 和自定义校验规则时,可以实现对实体类属性的分组校验

首先,定义验证分组的接口:

public interface Group1 {}
public interface Group2 {}

@GroupSequence({Group1.class, Group2.class})
public interface MyValidationGroupSequence {}

然后,创建一个实体类,并应用验证分组的约束和自定义校验规则:

public class User {
    @NotBlank(groups = Group1.class)
    private String username;

    @Size(min = 6, max = 20, groups = Group2.class)
    @CustomValidation(groups = Group2.class)
    private String password;

    // 省略构造函数、getter 和 setter 方法
}

在上述示例中,User 类应用了不同分组的约束。username 字段在 Group1 分组中不能为空白(@NotBlank),password 字段在 Group2 分组中必须是长度在 6 到 20 之间的字符串,并通过 @CustomValidation 标记了自定义校验规则。

接下来,定义一个自定义校验注解和校验器:

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = CustomValidator.class)
public @interface CustomValidation {
    String message() default "Invalid value";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

public class CustomValidator implements ConstraintValidator<CustomValidation, String> {
    public boolean isValid(String value, ConstraintValidatorContext context) {
        return value.matches("[A-Za-z0-9]+");
    }
}

在上述示例中,定义了一个名为 CustomValidation 的自定义校验注解,并将它应用在 password 字段上。同时,实现了 CustomValidator 类,对属性值进行自定义校验。

最后,创建一个服务类,并在方法参数上应用 @Validated 和验证分组注解进行校验:

@Service
@Validated
public class UserService {
    public void createUser(@Validated(MyValidationGroupSequence.class) User user) {
        // 创建用户的业务逻辑
    }
}

在上述示例中,createUser 方法使用了 @Validated 注解来启用方法参数校验,并通过 @Validated(MyValidationGroupSequence.class) 指定了要验证的分组。


使用该服务类进行方法调用时,会按照 @GroupSequence 中指定的顺序依次对分组进行校验,并执行自定义校验规则。

注意,为了使自定义校验规则生效,需要在 Spring 配置文件(如配置类)中配置自定义校验器,当然springboot环境已经自动注入了:

@Configuration
public class AppConfig {
    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        return new MethodValidationPostProcessor();
    }
}

以上展示了结合 @Validated、@GroupSequence 和自定义校验规则的用法,以实现分组校验和自定义校验逻辑。具体的验证逻辑和业务约束根据实际需求进行定义和实现。

MethodValidationPostProcessor作用

MethodValidationPostProcessor 是 Spring 提供的一个后置处理器,用于在方法调用时对方法参数进行校验。


当将 MethodValidationPostProcessor 添加到 Spring 容器中时,它会自动拦截标注了 @Validated 注解的方法,并在方法调用之前执行参数校验操作。如果方法参数不满足验证约束,则抛出 MethodArgumentNotValidException 异常或 ConstraintViolationException 异常。


使用 MethodValidationPostProcessor 可以方便地在方法级别上实现参数校验,而无需显式调用 Validator 对象进行验证。

在示例中,通过在配置类中定义 MethodValidationPostProcessor 的 bean,将其添加到 Spring 容器中:

@Configuration
public class AppConfig {
    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        return new MethodValidationPostProcessor();
    }
}


这样,在使用 @Validated 注解标注的方法中,就可以触发方法参数的校验。例如,在 UserService 中的 createUser 方法上使用 @Validated 注解:

@Service
@Validated
public class UserService {
    public void createUser(@Validated(MyValidationGroupSequence.class) User user) {
        // 创建用户的业务逻辑
    }

}

当调用 createUser 方法时,MethodValidationPostProcessor 会拦截该方法的调用,根据 @Validated 注解和指定的验证分组(MyValidationGroupSequence.class),对 User 对象的属性进行校验。如果校验失败,则会抛出相应的异常。


总而言之,MethodValidationPostProcessor 是一个后置处理器,用于实现方法参数的校验。它简化了在方法层面进行验证的操作,提供了方便的验证机制。

显示调用

如果你不想使用 MethodValidationPostProcessor,而是显式调用 Validator 对象进行验证,可以按照以下步骤进行编写:

首先,需要注入一个 Validator 对象到你的类中。可以使用 LocalValidatorFactoryBean 或者 Validator 接口的其他实现类。

@Autowired
private Validator validator;

接下来,在方法中手动调用 validator.validate() 方法进行参数校验。假设你的方法名为 createUser,接收 User 对象作为参数。

public void createUser(User user) {
    Set<ConstraintViolation<User>> violations = validator.validate(user, MyValidationGroupSequence.class);
    if (!violations.isEmpty()) {
        // 处理校验失败的情况
        for (ConstraintViolation<User> violation : violations) {
            System.out.println(violation.getMessage());
        }
    }
    // 创建业务逻辑
}

上述示例中,validator.validate() 方法接受两个参数:要校验的对象 user 和验证分组 MyValidationGroupSequence.class。它会返回一个包含所有校验失败信息的 Set<ConstraintViolation> 集合。


如果集合不为空,说明存在校验失败的情况。可以通过遍历集合中的 ConstraintViolation 对象,获取具体的校验错误信息进行处理。

注意,在使用显式调用 Validator 对象进行验证时,需要自己处理校验失败的情况,并根据实际需求进行后续操作。

最后,确保你已经在 Spring 配置文件(如配置类)中配置了 Validator 的 bean。

@Bean
public Validator validator() {
    LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
    factoryBean.setProviderClass(HibernateValidator.class);
    factoryBean.afterPropertiesSet();
    return factoryBean.getValidator();
}

当然也可以直接使用工厂模式的对象进项校验:

public class Main {
    public static void main(String[] args) {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();

        User user = new User();
        Set<ConstraintViolation<User>> violations = validator.validate(user, MyValidationGroupSequence.class);

        for (ConstraintViolation<User> violation : violations) {
            System.out.println(violation.getMessage());
        }
    }
}

以上就是使用显式调用 Validator 对象进行参数验证的方法。通过手动调用 validator.validate() 方法,可以实现对对象的参数校验,并且可以通过检查 ConstraintViolation 集合来处理校验失败的情况。


相关文章
|
1月前
|
Java 应用服务中间件 Windows
【应用服务 App Service】App Service 中部署Java项目,查看Tomcat配置及上传自定义版本
【应用服务 App Service】App Service 中部署Java项目,查看Tomcat配置及上传自定义版本
|
3天前
|
Java Go PHP
Java分组匹配
Java分组匹配
17 5
|
2天前
|
IDE Java 开发工具
java自定义异常20
java自定义异常20
|
1天前
|
Java 编译器 程序员
Java注解,元注解,自定义注解的使用
本文讲解了Java中注解的概念和作用,包括基本注解的用法(@Override, @Deprecated, @SuppressWarnings, @SafeVarargs, @FunctionalInterface),Java提供的元注解(@Retention, @Target, @Documented, @Inherited),以及如何自定义注解并通过反射获取注解信息。
Java注解,元注解,自定义注解的使用
|
1月前
|
搜索推荐 Java 开发者
Java异常处理新高度:自定义异常,打造个性化的错误管理体系!
Java异常处理新高度:自定义异常,打造个性化的错误管理体系!
37 1
|
1月前
|
前端开发 Java
Java高手都在用的秘籍:自定义异常,让错误信息说话!
Java高手都在用的秘籍:自定义异常,让错误信息说话!
38 1
|
1月前
|
Java 程序员 开发者
我们踩过的Java坑:自定义异常,让你的代码不再“捉急”!
我们踩过的Java坑:自定义异常,让你的代码不再“捉急”!
42 1
|
1月前
|
Java
【Azure 应用服务】如何查看App Service Java堆栈JVM相关的参数默认配置值?
【Azure 应用服务】如何查看App Service Java堆栈JVM相关的参数默认配置值?
【Azure 应用服务】如何查看App Service Java堆栈JVM相关的参数默认配置值?
|
1月前
|
安全 Java 应用服务中间件
【Azure 应用服务】App Service中,为Java应用配置自定义错误页面,禁用DELETE, PUT方法
【Azure 应用服务】App Service中,为Java应用配置自定义错误页面,禁用DELETE, PUT方法
【Azure 应用服务】App Service中,为Java应用配置自定义错误页面,禁用DELETE, PUT方法
|
1月前
|
算法 Java
【Java集合类面试十八】、ConcurrentHashMap是怎么分段分组的?
ConcurrentHashMap通过分段锁(Segment)实现高效并发访问,get操作无需加锁,而put操作首先判断是否需要扩容,然后通过两次hash定位并尝试使用CAS和锁机制安全地添加元素。