IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 通过自定义注解+ConstraintValidator完成Pojo参数枚举校验, -> 正文阅读

[Java知识库]通过自定义注解+ConstraintValidator完成Pojo参数枚举校验,

参考文档
系统执行业务逻辑之前,会对输入数据进行校验,检测数据是否有效合法的。所以我们可能会写大量的if else等判断逻辑,特别是在不同方法出现相同的数据时,校验的逻辑代码会反复出现,导致代码冗余,阅读性和可维护性极差。
hibernate-validator就提供了这套标准的实现,我们在用Springboot开发web应用时,会引入spring-boot-starter-web依赖,它默认会引入spring-boot-starter-validation依赖,而spring-boot-starter-validation中就引用了hibernate-validator依赖。
在这里插入图片描述

但是,在比较高版本的spring-boot-starter-web中,默认不再引用spring-boot-starter-validation,自然也就不会默认引入到hibernate-validator依赖,需要我们手动添加依赖。

依赖

<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.1.7.Final</version>
</dependency>

定义一个注解用于字段

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

@Target(ElementType.FIELD) // 设置为使用在字段上
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = CheckParam.class) // 这里匹配的校验规则必须是参数化了当前校验注解并且实现了ConstraintValidator的类
public @interface Check {

    // 字段对应的枚举
    Class<? extends Enum<?>> enumClazz();
    // 需要校验哪个字段属性
    String filed();
    // 校验不通过时的提示
    String message() default "非法参数";
    // 将validator进行分类,不同的类group中会执行不同的validator操作 (必须有这个属性)
    Class<?>[] groups() default {};
    // 主要是针对bean,很少使用(必须有这个属性)
    Class<? extends Payload>[] payload() default {};
}

创建一个校验类

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

@Component
// 这里参数化两个参数,一个是这个校验规则对应的注解,以及校验的参的数类型,不指定的话则下面的实现方法为object
// 这里由于参数可能是数字也可能是string所以我使用了object
public class CheckParam implements ConstraintValidator<Check, Object> {
    // 是否为必须参数
    private boolean required;
    private Class<? extends Enum<?>> enumClass;
    private String filed;

    // 参数校验初始化,默认无操作,这里我们就进行校验数据的初始化,参数为我们实例化的注解
    @Override
    public void initialize(Check constraintAnnotation) {
        this.enumClass = constraintAnnotation.enumClazz();
        this.filed = constraintAnnotation.filed();
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        // 禁用默认响应消息
        context.disableDefaultConstraintViolation();
        if (StringUtils.isBlank(value.toString())) {
            // 自定义响应内容
            context.buildConstraintViolationWithTemplate("你不对劲").addConstraintViolation();
            return false;
        }
        // 这里利用枚举校验攻击对枚举进行了校验。大家可以根基自己情况自行定制
        if (!EnumCheck.valueBelongsToEnum(enumClass, filed, value.toString())) {
            // 自定义响应内容
            context.buildConstraintViolationWithTemplate("参数不在枚举范围").addConstraintViolation();
            return false;
        }
        // 通过校验返回true
        return true;
    }
}

用以校验的bean以及使用

# Pojo
@Data
public class Goods {
    private String goodsName;
    // 指定了需要用哪个枚举规范来对比,对比枚举中的哪个属性
    @Check(enumClazz = GoodsTypeEnum.class,filed = "type")
    private Integer goodsType;
}

# Controller
@RestController
@RequestMapping("/enumCheck")
public class EnumCheckController {
    
    @PostMapping("test")
    public Object test(@RequestBody @Valid Goods goods){
        return goods;
    }
}

枚举校验方法

public class EnumCheck {
    /**
     * 判断参数是否属于某一个枚举clazz的某一个值fieldName
     * @return
     */
    public static boolean valueBelongsToEnum(Class<? extends Enum<?>> clazz, String fieldName,String val){
        final Enum<?>[] enums = clazz.getEnumConstants();
        if (null == enums) {
            return false;
        }
        final List<Object> list = new ArrayList<>(enums.length);
        for (Enum<?> e : enums) {
            list.add(ReflectUtil.getFieldValue(e, fieldName));
        }
        // 这里进行转型后再比对,否则下面判定如果是String和integer进行判断始终为false;
        final List<String> collect = list.stream().map(Object::toString).collect(Collectors.toList());
        boolean contains = collect.contains(val);
        return contains;
    }
}

枚举


public enum GoodsTypeEnum {
    PC("pc",1),
    MOBILE("mobile",2),
    WEB("web",3),
    ;
    private final String info;
    private final Integer type;

    GoodsTypeEnum(String info, Integer type) {
        this.info = info;
        this.type = type;
    }
    public Integer getType() {
        return type;
    }
}

异常处理

方法默认抛出MethodArgumentNotValidException,我们在统一异常处理中捕获他进行处理,统一响应

@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<Object> methodArgumentNotValidException(MethodArgumentNotValidException e){
    log.error("参数校验异常 msg:{}",e.getMessage(),e );
    String msg = e.getMessage();
    String[] split = msg.split(";");
    String temp = split[5].split("\\[")[1];
    return Result.fail(50000,"["+split[0].split("'")[1]+"]"+temp.substring(0, temp.length()-3));
}

测试结果

在这里插入图片描述

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-04 15:22:29  更:2022-03-04 15:24:10 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 10:44:34-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码