编写一个自定义的校验注解

本文档详细介绍了如何创建一个自定义的Java校验注解@ListValue,以及对应的校验器ListValueConstraintValidator。通过@Constraint注解关联校验器,并在properties文件中设置错误信息。此外,还展示了如何在实际应用中使用此自定义注解进行值校验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如何编写自定义的校验注解并生效

1、编写一个自定义的校验注解@ListValue

@ListValue(vals = {0, 1}})

创建一个注解类
在这里插入图片描述

package com.jms.common.valid;

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.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * 自定义的校验注解
 * @author jamison
 * @version 1.0
 * @date 2021/1/24 12:06
 */
@Documented
@Constraint(validatedBy = { ListValueConstraintValidator.class }) //指定校验器
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {

	//com.jms.common.valid.ListValue.message 校验的错误信息(properties文件中定义)
    String message() default "{com.jms.common.valid.ListValue.message}";

    Class<?>[] groups() default { };

    Class<? extends Payload>[] payload() default { };
	//定义一个整数类型的数组,默认为空
    int[] vals() default {};
}

创建一个错误信息的properties文件
在这里插入图片描述
在文件中编写错误信息

com.jms.common.valid.ListValue.message = The specified value must be submitted(必须提交指定的值!)

注意:中文的话可能会乱码,暂时还没解决,待解决。

2、编写一个自定义的校验器

在这里插入图片描述
观察Constraint注解类的源码,我们需要一个类继承ConstraintValidator接口
在这里插入图片描述

ConstraintValidator接口类,参数1:自定义注解类,参数2:改注解支持的类型在这里插入图片描述
那么接下来我们就编写仿照,编写一个我们自己的校验器

package com.jms.common.valid;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.HashSet;
import java.util.Set;

/**
 * @author jamison
 * @version 1.0
 * @date 2021/1/24 12:24
 */
 //public class ListValueConstraintValidator implements ConstraintValidator<注解类, 支持的类型>
public class ListValueConstraintValidator implements ConstraintValidator<ListValue, Integer> {

    private Set<Integer> set = new HashSet<Integer>();

    //初始化方法
    public void initialize(ListValue constraintAnnotation) {
        //获取注解中传递进来的值
        int[] vals = constraintAnnotation.vals();
        for (int val : vals) {
            set.add(val);
        }
    }

    /**
     *判断是否校验成功
     * @param value 需要校验的值
     * @param context
     * @return
     */
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
        //需要校验的值是否包含在set中
        boolean contains = set.contains(value);
        return contains;
    }
}

3、关联自定义的校验注解和自定义的校验器
最后一步就是要关联注解类和校验器了

//在注解类上加上注解
//@Constraint(validatedBy = { 校验器类名.class })	
@Constraint(validatedBy = { ListValueConstraintValidator.class })	

在这里插入图片描述
现在我们的自定义注解就生效了

<think>嗯,用户想知道如何实现实体类的自定义校验注解的分组。首先,我得回忆一下Java Bean Validation的相关知识,特别是分组的使用。记得分组是通过定义接口来标记不同的验证场景,比如新增和更新操作可能需要不同的校验规则。 首先,用户可能需要创建一个自定义校验注解。比如,@Phone这个注解,用来验证电话号码格式。然后,他们需要为这个注解指定验证器类,比如PhoneValidator,这个类需要实现ConstraintValidator接口,并在isValid方法里编写具体的验证逻辑。 接下来是分组的部分。用户需要定义不同的接口作为分组标识,比如CreateGroup和UpdateGroup。然后在实体类的字段上使用groups属性来指定该校验属于哪个分组。例如,在创建时使用@Phone(groups = CreateGroup.class),在更新时可能不需要这个校验,所以不指定这个分组。 然后,在Controller层进行校验的时候,需要通过@Validated注解来指定使用哪个分组。比如,在创建用户的方法参数上使用@Validated(CreateGroup.class),这样只有属于CreateGroup分组的校验规则会被触发。而更新用户的方法可能使用@Validated(UpdateGroup.class)或者其他分组。 可能需要注意的地方是,如果某个校验注解没有指定groups属性,默认属于Default分组。所以如果用户混用了分组和默认分组,需要明确处理。还有,Spring的@Validated和JSR的@Valid在分组支持上的区别,@Valid不支持分组,所以必须用@Validated。 用户可能会遇到的问题包括分组接口的定义是否正确,是否在正确的场景下指定了分组,以及验证器是否正确实现了对应的逻辑。需要提醒他们检查这些点,确保分组配置正确,并且在调用验证时传入了正确的分组参数。 总结下来,步骤应该是:定义分组接口→创建自定义注解并关联验证器→在实体字段上使用分组→在验证时指定分组。这样就能实现不同场景下的校验规则分组应用了。</think>好的,我来逐步解释如何实现实体类的自定义校验注解分组: 1. **定义分组标识接口** ```java // 创建分组标识接口(空接口) public interface CreateGroup {} // 新增操作分组 public interface UpdateGroup {} // 更新操作分组 ``` 2. **创建自定义校验注解** ```java @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = PhoneValidator.class) // 指定校验器 public @interface Phone { String message() default "手机号格式错误"; Class<?>[] groups() default {}; // 必须包含groups参数 Class<? extends Payload>[] payload() default {}; } ``` 3. **实现校验逻辑类** ```java public class PhoneValidator implements ConstraintValidator<Phone, String> { @Override public boolean isValid(String value, ConstraintValidatorContext context) { if (value == null) return true; return value.matches("^1[3-9]\\d{9}$"); } } ``` 4. **在实体类中使用分组** ```java public class User { @NotBlank(groups = {CreateGroup.class}) private String name; @Phone(groups = {CreateGroup.class, UpdateGroup.class}) private String phone; @Min(value = 18, groups = UpdateGroup.class) private int age; } ``` 5. **控制器层分组验证** ```java @RestController public class UserController { // 创建操作使用CreateGroup分组 @PostMapping("/users") public void createUser(@Validated(CreateGroup.class) @RequestBody User user) { // 只会校验name和phone字段 } // 更新操作使用UpdateGroup分组 @PutMapping("/users/{id}") public void updateUser(@Validated(UpdateGroup.class) @RequestBody User user) { // 只会校验phone和age字段 } } ``` **关键点说明:** 1. 分组通过空接口定义,起到标识符作用 2. 每个校验注解的`groups`属性指定适用分组 3. 使用`@Validated`注解激活特定分组的校验(注意这是Spring注解) 4. 未指定`groups`的校验默认属于`Default`分组 5. 同一个字段可以同时属于多个分组 **分组验证流程:** ``` 请求参数 → 根据@Validated指定分组 → 执行对应分组的校验规则 → 校验失败返回错误信息 ``` **扩展能力:** - 可以组合多个分组:`@Validated({CreateGroup.class, SpecialCheck.class})` - 继承关系:分组接口可以继承其他接口形成层级 - 自定义错误消息:通过`message`属性配合国际化配置 **常见问题处理:** 1. 校验未生效:检查`groups`名称是否匹配、是否使用`@Validated` 2. 分组冲突:确保不同分组的校验规则没有矛盾 3. 嵌套校验:需要在关联对象字段添加`@Valid`注解 这种分组机制特别适用于: - 不同操作场景需要不同校验规则(如创建/更新) - 多步骤表单的分步验证 - 不同权限级别的数据校验强度控制 是否需要进一步了解如何实现条件校验或跨字段验证?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值