springboot自定义字段校验器(满足业务特殊校验)

https://blog.youkuaiyun.com/qq_21187515/article/details/109673109

背景

项目中需要根据业务,校验导入excel的每个字段。

javax.validation 中注解是比较强大的,可是不满足业务需求。比如针对几个字段进行业务校验或者针对大量的字段,自定义校验器就派上用场。

于是需要自定义校验器。

解决 & 实现

1.校验annotation(注解)

@Target({ElementType.FIELD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = Validator.class)//指定校验器
public @interface ValidxxxImport {

  ValidxxxEnum type();

  String message() default "";

  //groups 和 payload两个必填项
  Class<?>[] groups() default {};

  Class<? extends Payload>[] payload() default {};
}

2.类型枚举

@Getter
@AllArgsConstructor
public enum ValidxxxImportEnum {

    NAME,
    AGE,
    PHONE,
}

对于不同类型有不同校验方法

3.校验器(关键)

@Slf4j
@Component
public class xxxImportValidator implements ConstraintValidator<ValidxxxImport, String> {

    private ValidxxxImport validxxxImport;
    private ValidxxxImportEnum validxxxImportEnum;

    @Override
    public void initialize(ValidxxxImport constraintAnnotation) {
        this.validxxxImport = constraintAnnotation;
        this.validxxxImportEnum = constraintAnnotation.type();
    }

    @Override
    public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
        if (ValidxxxImportEnum.NAME.equals(validxxxImportEnum)) {
            //业务校验方法1
        } else if (ValidxxxImportEnum.PHONE.equals(validxxxImportEnum)) {
            //业务校验方法2
        }
        return false;
    }
}

4.需校验req

@Data
@ApiModel(value = "导入dto")
public class ExcelDto implements Serializable {

    private static final long serialVersionUID = 1L;

    @ValidPlanRuleImport(type = ValidPlanRuleImportEnum.NAME)
    private String field1;

    @ValidPlanRuleImport(type = ValidPlanRuleImportEnum.PHONE)
    private String field2;
  
    @ValidPlanRuleImport(type = ValidPlanRuleImportEnum.AGE)
    private String field3;
}

5.业务服务实现类

import javax.validation.Validator;
import javax.validation.groups.Default;

@Service
public class xxxService{

    @Autowired
    private Validator validator;
  	
  	for (int i = 0; i < list.size(); i++) {
        ExcelDto dto = list.get(i);
      	//这里默认使用javax.validation.groups.Default分组
        Set<ConstraintViolation<ExcelDto>> set = validator.validate(dto, Default.class);
      
        if (!CollectionUtils.isEmpty(set)) {
          	//说明有违反校验规则信息
          	//校验没通过,可以打印错误信息,以及相关字段等
            for (ConstraintViolation<PlanRuleExcelDto> result : set) {
                log.info("校验失败: property[{}] value[{}]", result.getPropertyPath(), result.getInvalidValue());
            }
        }
  
}

输出日志

校验失败: property[no1] value[elit]
校验失败: property[no2] value[dolore aliquip]
校验失败: property[no3] value[pariatur commodo]
### 实现 Spring Boot 自定义注解验证并处理级联属性 在 Spring Boot 应用程序中,通过自定义注解来增强数据验证功能是一种常见做法。这不仅提高了代码的可读性和维护性,还使得业务逻辑更加清晰。 #### 定义自定义注解 为了创建一个新的约束注解 `@ValidEmail` 来验证电子邮件地址的有效性: ```java import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Constraint(validatedBy = EmailValidator.class) @Target({ ElementType.FIELD }) @Retention(RetentionPolicy.RUNTIME) public @interface ValidEmail { String message() default "Invalid email address"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; } ``` 此部分描述了如何声明一个名为 `@ValidEmail` 的新注解[^2]。 #### 创建对应的验证器类 接着需要编写具体的验证逻辑,在这里是一个简单的正则表达式匹配: ```java import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; public class EmailValidator implements ConstraintValidator<ValidEmail, String> { private static final String EMAIL_PATTERN = "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$"; @Override public void initialize(final ValidEmail constraintAnnotation) {} @Override public boolean isValid(String value, ConstraintValidatorContext context){ return value != null && value.matches(EMAIL_PATTERN); } } ``` 这段代码实现了针对上述自定义注解的具体检验行为。 #### 处理嵌套对象中的字段验证(即级联属性) 当涉及到复杂的数据结构时,比如包含其他实体的对象列表或集合,则可以通过启用级联验证机制来进行更深层次的检查。只需简单地标记父级 Bean 上的相关成员变量为 `@Valid` 或者 `@Validated` 即可激活这一特性。 假设有一个用户注册表单模型 UserForm.java 如下所示: ```java import org.hibernate.validator.constraints.Length; import javax.validation.Valid; import java.util.List; public class UserForm { @Length(min=3,max=50,message="Username must be between 3 and 50 characters long.") private String username; @ValidEmail(message = "Please provide valid e-mail") private String emailAddress; @Valid private Address shippingAddress; // 嵌入另一个带有自己验证规则的bean @Valid List<ContactInfo> contactInfos; // 对象列表同样适用 // getters & setters... } ``` 这里的 `shippingAddress` 和 `contactInfos` 字段都标记有 `@Valid` 注释,这意味着它们内部所含有的任何受支持类型的子组件都将被递归地加以验证[^1]。 #### 配置全局异常处理器 为了让应用程序能够优雅地响应违反约束的情况,通常会配置一个统一的错误消息返回接口。可以利用 `@ControllerAdvice` 结合 `@ExceptionHandler(MethodArgumentNotValidException.class)` 方法捕获所有来自控制器层面上发生的参数绑定失败事件,并将其转换成友好的 JSON 格式的反馈信息给前端调用方。 ```java @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) protected ResponseEntity<Object> handleMethodArgumentNotValid( MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) { Map<String,Object> body=new HashMap<>(); body.put("timestamp",new Date()); body.put("status",HttpStatus.BAD_REQUEST.value()); List<String> errors = ex.getBindingResult() .getFieldErrors() .stream() .map(DefaultMessageSourceResolvable::getDefaultMessage) .collect(Collectors.toList()); body.put("errors",errors); return new ResponseEntity<>(body,status); } } ``` 以上就是关于如何在 Spring Boot 中实现自定义注解进行校验以及处理级联属性的一个完整示例教程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值