springMvc自定义校验注解

2023-11-04

spring 自定义注解

翻看公司代码,看到了自定义的注解,查了查,再次记录一下,还是太菜
下面是我的实现

1. 自定义注解

package com.test;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;

/**
 * Documented 注解表明这个注解应该被 javadoc工具记录
 */
@Documented
/**
 *注解会被保留到那个阶段 有三个取值
 * SOURCE    只在源代码级别保留,编译时就会被忽略
 * CLASS     编译时被保留,在class文件中存在,但JVM将会忽略
 * RUNTIME   运行时被JVM或其他使用反射机制的代码所读取和使用
 */
@Retention(RetentionPolicy.RUNTIME)
/**
 * 说明了Annotation所修饰的对象范围
 */
@Target({FIELD, ANNOTATION_TYPE, PARAMETER})
/**
 * 表示处理的这个注解的类是哪一个
 * 我这里的是 myValidateINtercepter处理
 */
@Constraint(validatedBy = myValidateINtercepter.class)
@interface Enums{
    String enumList() default ""; //1
    String message() default "值不在字典内"; //2
    String field() default ""; //3

    /**
     * 下面的这俩是必须的。我第一次没加 payload ,就报错了 ,报错为 Enums contains Constraint annotation, but does not contain a payload parameter.
     */
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default { };
}
  • 补充说明
  • groups,payload 是必须添加的,要不然就会报错,我也不知为啥就报错。反正必须要添加,下面贴出我的报错信息
    在这里插入图片描述

上面代码里面,注解里面的 1,2,3 字段是根据自己的业务来的 望知晓

2. 自定义校验类

实现ConstraintValidator接口,一个参数为标注的枚举类型,第二个参数为需要校验的类型

package com.test;

import com.test.Enums;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Arrays;

/**
 * @description:
 * @author: liuchen
 * @date: 2020/7/29
 **/
public class myValidateINtercepter implements ConstraintValidator<Enums,String> {
    private String enumList;
    private String field;
    private Enums constraintAnnotation;

    /**
     * 做初始化工作
     * @param constraintAnnotation   自己定义的注解
     */
    @Override
    public void initialize(Enums constraintAnnotation) {
        this.enumList = constraintAnnotation.enumList();
        this.field = constraintAnnotation.field();
        this.constraintAnnotation = constraintAnnotation;
    }

    /**
     * 做校验
     * @param s                             待校验的值
     * @param constraintValidatorContext    上下文
     * @return
     */
    @Override
    public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
        //检查 代校验的值合法否?
        if (Arrays.asList(enumList.split(",")).contains(s)) {
            //合法,通过
            return true;
        }else{
            /**
             * 禁用默认的消息模板
             */
            constraintValidatorContext.disableDefaultConstraintViolation();
            /**
             * 设置自己的消息模板
             */
            constraintValidatorContext.buildConstraintViolationWithTemplate(String.format("%s 当前值不在字段范围内,字典范围为[%s]",s,enumList))
                    .addConstraintViolation();
            //不合法,不通过
            return false;
        }
    }
}

关于constraintValidatorContext 的解释

  • 这种东西debug一下,看的清清楚楚。下面贴出我的debug的结果
    在这里插入图片描述

3. 使用示例

3.1 实体类

/**
 * 实体类
 */
@Data
class Student{
    //原生注解
    @Min(value = 0,message = "id不能小于0")
    private Integer id;
    @NotBlank(message = "不能为空字符串")
    private String name;
    private Double age;
    /*1*/@Valid
    private List<Address> list;
    @Valid
    private Address address;
    /*3*/
    public interface AGroup{
    }
    public interface BGroup{
    }
}
@Data
class Address{
    @NotBlank()
    /*2*/@Enums(enumList = "1,2",groups = Student.AGroup.class)
    private  String province;
    @Enums(enumList = "1,2,3",groups = Student.BGroup.class)
    private  String city;
}

关于Student的解释说明

  • 注释1 @Valid:表示被标注的属性也是需要校验的。
  • 说一下 @Valid和@Validated的区别
    • @Validated不能作用于字段,这个点开源码看@Target就可以看出来.
    • @Validated里面支持分组校验。@Valid不支持
      • 关于分组校验,请看 3.2 controller 注释1 和 这个例子中 注释2 中的groups 属性,在controller里面指定分组,校验规则就会按照对应的组来,如果不指定,就会校验那些没有指明组的属性
  • 注释3 表示不同的组,这其实就是一个接口,里面啥都不用写。

3.2 controller

package com.test;

import com.alibaba.fastjson.JSONObject;
import com.common.model.ApiResult;
import com.common.model.ResultCode;
import lombok.Data;
import org.springframework.boot.context.properties.bind.BindResult;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;

import javax.validation.Constraint;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;

import static java.lang.annotation.ElementType.*;

/**
 * @description:
 * @author: liuchen
 * @date: 2020/7/29
 **/
@RestController
@RequestMapping("myTest")
public class MyTestcontroller {
        @PostMapping("/test")
    public ApiResult test(@RequestBody /*1*/@Validated(value = Student.BGroup.class) Student student ,/*2*/BindingResult result){
         /*3*/ //方式一  
        if(result.hasErrors()){
            //在绑定参数的时候出错啦
            StringBuffer returnResult = new StringBuffer();
            /*5*/List<ObjectError> allErrors = result.getAllErrors();
            allErrors.stream().forEach(error->returnResult.append(error.getDefaultMessage()));
            return new ApiResult(200,returnResult.toString());
        }
        System.out.println(JSONObject.toJSONString(student));
        return ApiResult.success();
    }
    /*4*/
    //方式二  定义一个统一的异常处理, 可以采用 @ControllerAdvice 的那种全局统一处理
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ApiResult handleException(MethodArgumentNotValidException bindResult){
        StringBuffer stringBuffer = new StringBuffer();
        List<ObjectError> allErrors = bindResult.getBindingResult().getAllErrors();
        allErrors.stream().forEach(error -> {System.out.println(String.format("code:%s,msg:%s",error.getCode(),error.getDefaultMessage()));stringBuffer.append(error.getDefaultMessage());});
        return new ApiResult(200,stringBuffer.toString());
    }
}

关于controller的解释说明

  • 注释1 指定了需要校验的组是 BGroup。属于AGroup的就不会被校验
  • 如果校验不通过,springmvc就会抛出异常MethodArgumentNotValidException,此时就有两种选择
    • 注释4 统一的异常处理,
    • 注释2 将BindingResult 入参,在业务方法里面处理。
  • 注释2 关于BindingResult。至于这个对象是怎么来的,就要你熟悉springmvc 的流程了。 在绑定参数和校验的时候就会有这个对象
  • 注释5 通过bindResult就可以得到所有的错误,还记得在自定义校验的时候设置的模板了吗2. 自定义校验类,从这里就能得到自定义的错误消息

4. 请求示例

{
  "id": 1,
  "name": "fdfdsfdsf",
  "age": 0.0,
  "list": [
    {
      "province": "1434343",
      "city": "1"
    }
  ],
  "address": {
    "province": "2",
    "city": "1"
  }
}

5. Validation.buildDefaultValidatorFactory()

这个东西就是 自己校验,springmvc帮我们封装了校验,这个方法就是 原生的校验

  • 校验代码
     B name = new B(-1, "", 54545454.0);
        Set<ConstraintViolation<Object>> validateSet = Validation.buildDefaultValidatorFactory() //定义验证工厂
                .getValidator() //得到验证器
                .validate(name,a1.class); //验证 (对象,组)//这个组就是上面列子中的组

            String messages = validateSet.stream()
                    .map(ConstraintViolation::getMessage)
                    .reduce((m1, m2) -> m1 + "||      " + m2)
                    .orElse("参数输入有误!");
            throw new IllegalArgumentException(messages);
        }
  • 自己的实体
@Data
class B{
    @Min(value = 0,groups = a1.class,message = "不能小于0")
    private Integer id;
    @NotBlank(message = "不能为空",groups =b1.class )
    private String name;
    @Max(value = 100,message = "不能大于100")
    private Double age;

    public B( Integer id, String name, Double age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
}
interface a1{

}
interface b1{

}

这就是 springmvc帮我们封装好的部分,原生的实现就那样
大体就是这样,以备之后使用

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

springMvc自定义校验注解 的相关文章

随机推荐

  • 6月3号绝地求生服务器维护,绝地求生6月3日维护到几点_2020年6月3日绝地求生更新维护开服时间介绍_咖绿茵手游站...

    绝地求生6月3日维护到几点呢 2020年6月3日绝地求生对正式服进行停机维护 接下来就让咖绿茵小编给大家带来 绝地求生 6月3日更新维护开服时间介绍 绝地求生 6月3日更新维护开服时间介绍 绝地求生在北京时间6月3日 星期三 08点30分开
  • 解决Flutter PageView页面切换时数据刷新问题

    首先补充一下 之前我没有写是在切换pageView页面的主页面写还是展示的子页面写 这里我说一下 一定要在切换的子页面里面使用这个方法 否则不生效 例如使用了PageView组件 每次切换页面时都会走initState 和dispose 方
  • TCP/IP详解 卷1:协议 学习笔记 第二十六章 Telnet和Rlogin:远程登录

    TCP IP网络上 有两种应用提供远程登录功能 1 Telnet 几乎每个TCP IP的实现都提供这个功能 它能够运行在不同操作系统的主机之间 Telnet通过客户进程和服务器进程之间的选项协商机制 从而确定通信双方可以提供的功能特性 2
  • [JAVA数据结构]HashMap

    目录 1 HashMap 1 1Map的常用方法 1 2HashMap的使用案例 1 HashMap 基于哈希表的实现的Map接口 Map底层结构 HashMap 底层结构 哈希桶 插入 删除 查找时间复杂度 O 1 是否有序 无序 线程安
  • 了解 z-index 层叠等级属性的使用

    当对多个元素同时设置定位时 定位元素之间有可能会发生重叠 接下来我会用代码来进行演示和讲解层叠的效果和使用 代码如下
  • provider模式学习——simpledemo

    1 首先建立一个类库项目 Provider Demo 添加如下类 并要添加引用System Configuration 1 1 创建ParentProvider类继承自provider的基类 namespace provider Provi
  • 如何做好项目的需求与业务调研?

    1 调研工作如何组织 很多人认为调研工作极难 水平最高的人才能做好一次调研 软件工程中也强调需求获取是最难的事情 有的人要么认为不过如此 甚至是一个普通技术支持都可以做的工作 现在有很多企业上管理软件之前都希望软件公司派人来了解情况 提出针
  • 搭建游戏环境

    搭建游戏环境 安装docker curl fsSL https get docker com bash s docker mirror Aliyun 安装docker compose curl L https github com dock
  • 标准模板库(STL)

    STL 标准模板库 Standard Template Library STL 是一个基于模板的容器类库 可用STL创建一个类 为任意数据类型定义矢量 链表 队列和栈等操作 STL中的泛型算法 generic algorithm 和函数对象
  • Python——— 面向对象

    一 初识面向对象 Python完全采用了面向对象的思想 是真正面向对象的编程语言 完全支持面向对象的基本功能 例如 继承 多态 封装等 Python 支持面向过程 面向对象 函数式编程等多种编程范 式 Python 中 一切皆对象 我们在前
  • 使用pickle模块序列化数据,优化代码

    使用pickle模块序列化数据 优化代码 pickle是Python标准库中的一个二进制序列化和反序列化库 可以以二进制的形式将数据持久化保存到磁盘文件中 可以将数据和代码分离 提高代码可读性和优雅度 一 pickle模块介绍 pickle
  • lstm神经网络_机器翻译与高级循环神经网络LSTM,GRU

    No 1 机器翻译概述 机器翻译就是将一种语言翻译为另一种语言 所有机器翻译系统本质上都是基于统计的 我们将总尝试使用非常大的语料库 一般称为平行语料库 在语料库中 有许多句子或段落以不同语言表述 No 2 深度学习出现之前的机器翻译模型
  • linux内核之双向链表实现原理

    1 内核中双向链表结构 Linux内核中广泛使用了一种称为循环双链 Circular Doubly Linked 链表的数据结构 即每个节点都有一个向前和向后的链接 而且首尾节点也相互连接 使用这样的链表 你可以很方便地访问任何一个元素的上
  • Android调用手机系统自带录音功能实现语音录制与播放

    首先调用手机系统自带的录音功能需要相关权限以及读写SD卡的权限
  • linux下C程序查看内存剩余大小

    嵌入式linux中很多内存资源都比较小 所以很多程序中在malloc时就需要提前知道内存剩余的大小 下面是一种调用 sysinfo接口来实现 示例代码如下 include
  • java--基础--16.8--IO流--打印流

    java 基础 16 8 IO流 打印流 1 介绍 1 1 分类 字节流打印流 PrintStream 字符打印流 PrintWriter 1 2 特点 只有写数据的 没有读取数据 只能操作目的地 不能操作数据源 可以操作任意类型的数据 如
  • 东北大学acm训练第四周(搜索)

    include
  • 在mac上配置vue开发环境

    1 在mac上安装brew brew 是 Mac 下的一个包管理工具 没有安装brew 检测用 brew v 则执行下面的命令安装 usr bin ruby e curl fsSL https raw githubusercontent c
  • sqli-18

    1 1 updatexml 1 concat 0x5c select group concat table name from information schema tables where table schema security
  • springMvc自定义校验注解

    spring 自定义注解 翻看公司代码 看到了自定义的注解 查了查 再次记录一下 还是太菜 下面是我的实现 1 自定义注解 package com test import javax validation Constraint import