Java自定义校验注解实现List、set集合字段唯一性校验
文章目录
- 一: 使用场景
- 二: 定义FieldUniqueValid注解
- 2.1 @FieldUniqueValid
- 2.2 注解说明
- 2.3 @Constraint 注解介绍
- 2.4 @FieldUniqueValid注解使用
- 三:自定义FieldUniqueValidator校验类
- 3.1 实现ConstraintValidator
- 3.2 重写initialize方法
- 3.3 重写isValid方法
- 3.4 获取list集合重复数据的下标
- 3.5 思路
- 3.6 测试
- 3.6.1 前端传递参数,需要进行唯一性校验的字段
- 3.6.2 message提示
一: 使用场景
在开发过程中,前端给后端传递集合,并且需要保证集合的实体类中的某些字段必须是惟一的,不能重复。
传递的集合:
private List<User> userInfoList;
集合对应的实体类:
@Data
public class User {private int id;private String name;private String card;}
如果我们要保证传递的name或者card必须是唯一的,不能重复,应该如何实现呢,此时可以通过自定义注解的方式实现。
二: 定义FieldUniqueValid注解
2.1 @FieldUniqueValid
/*** 该注解用于校验List集合实体类当中的某些字段的唯一性* <p>* 条件表达式支持使用"$parent."获取父节点属性(实体内不能使用除List集合外的其他集合类型,例如Set等)* <ul>* <li>标记在字段上:用于指定单个或多个字段,fields需填写</li>* </ul>* @author ikun* @date 2023.07.27*/
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = FieldUniqueValidator.class)
public @interface FieldUniqueValid {//需要进行唯一校验的字段String[] fieldsCode() default{};String[] fieldsName() default{};String message() default "[fieldName]列[index]行数据重复";//不能有默认值,报错:contains Constraint annotation, but the groups parameter default value is not the empty arrayClass<?>[] groups() default {};//在那种组中使用Class<? extends Payload>[] payload() default {};
}
2.2 注解说明
@Documented
@Document 是 java 在生成文档,是否显示注解的开关。
@Target(ElementType.FIELD)
ElementType.FIELD:该注解只能声明在一个类的字段前。
2.3 @Constraint 注解介绍
@Constraint注解是Java Bean Validation框架中的一个注解,用于自定义约束注解,即自定义校验规则。
通过在自定义注解上添加@Constraint注解,可以将该注解标记为一个自定义约束注解。同时,需要指定一个实现了ConstraintValidator接口的验证器类,用于验证该注解所标记的字段或参数是否符合自定义的校验规则。
@Constraint注解有以下属性:
-
validatedBy:用于指定实现了ConstraintValidator接口的验证器类。该属性的值是一个Class对象数组,可以指定多个验证器类。
-
message:用于指定当校验失败时,所返回的错误信息。可以使用占位符{},在校验器中使用具体的参数替换。
-
groups:用于指定分组,即根据不同的分组应用不同的校验规则。
-
payload:用于指定元数据,即可以通过该属性传递一些额外的验证信息。
使用@Constraint注解,可以通过自定义注解的方式,为字段或参数添加自定义的校验规则,并实现校验逻辑。这样,在进行参数校验时,可以方便地通过注解的方式来调用自定义的校验规则。
2.4 @FieldUniqueValid注解使用
@FieldUniqueValid(fieldsCode = {"name,card"}, fieldsName = {"姓名,身份证号"})
private List<User> userInfoList;
- fieldsCode :需要校验的字段
- fieldsName :校验字段对应的名称
三:自定义FieldUniqueValidator校验类
@Slf4j
public class FieldUniqueValidator implements ConstraintValidator<FieldUniqueValid, Iterable<?>> {private String[] fieldsCode;private String[] fieldsName;/*** 数据有重复的字段名称*/private static final String FIELD_NAME= "[fieldName]";/*** 相同元素下标集合*/private static final String INDEX = "[index]";/*** 初始化参数* @param constraintAnnotation 注解的值*/@Overridepublic void initialize(FieldUniqueValid constraintAnnotation) {fieldsCode = constraintAnnotation.fieldsCode();fieldsName = constraintAnnotation.fieldsName();}@Overridepublic boolean isValid(Iterable<?> value, ConstraintValidatorContext context) {//如果没有配置校验字段信息,则直接通过if(fieldsCode.length == 0 && fieldsName.length == 0){return true;}if(fieldsCode.length != fieldsName.length){throw new RuntimeException("@FieldUniqueValid注解所对应的fieldsCode和fieldsName无法相互映射");}if(value == null){throw new RuntimeException("@FieldUniqueValid注解所在的集合为空,无法判断");}for (int i = 0; i < fieldsCode.length; i++) {List<Object> list = new ArrayList<>();Iterator<?> iterator = value.iterator();long index;for (index = 0; iterator.hasNext(); index++) {Object fieldValue = null;try {//forceAccess = true,属性是私有的,需要设置为true打开权限fieldValue = FieldUtils.readField(iterator.next(),fieldsCode[i],true);} catch (IllegalAccessException e) {log.error(fieldsName[i] + "转化失败,无法进行校验", e);}list.add(fieldValue);}//去重后的总数long count = list.stream().distinct().count();//去重之前和去重以后进行比较if(count < index){//返回重复元素下标集合String sameIndex = getListSameIndex(list);String defaultConstraintViolation = context.getDefaultConstraintMessageTemplate();context.disableDefaultConstraintViolation();String convertedConstraintViolation = defaultConstraintViolation.replace(FIELD_NAME, fieldsName[i]).replace(INDEX, sameIndex);context.buildConstraintViolationWithTemplate(convertedConstraintViolation).addConstraintViolation();return false;}}return true;}}
3.1 实现ConstraintValidator
ConstraintValidator<FieldUniqueValid, Iterable<?>>:
- FieldUniqueValid:需要校验的注解,就是我们自定义的
- Iterable<?>:前端传递list的类型,此时用Iterable是因为数据支持list和set集合
3.2 重写initialize方法
可以从onstraintAnnotation参数中获取fieldsCode、fieldsName里面的参数。主要作用就是将注解的参数进行初始化
3.3 重写isValid方法
Iterable<?> value, ConstraintValidatorContext context
- value:可以获取到传递的集合数据
- context:获取注解上的message信息
3.4 获取list集合重复数据的下标
/*** 集合【List】找出list中重复元素的下标(显示下标所在位置)* @param list*/public static String getListSameIndex(List<?> list){List<Object> same = new ArrayList<>();List<?> collect = list.stream().distinct().collect(Collectors.toList());if(collect.size() == list.size()){return null;}StringBuilder sb = new StringBuilder();for (int i = 0; i <collect.size(); i++) {for (int j = 0; j < list.size(); j++) {if (list.get(j).equals(collect.get(i))){same.add(j+1);}}if (same.size() > 1){sb.append(same).append("、");}same.clear();}return sb.substring(0, sb.toString().lastIndexOf("、"));}
3.5 思路
首先获取到集合的数据,然后通过反射,用循环遍历获取到name字段的list数据,然后去重。将去重前后的list进行比较。如果长度变化了则说明有重复数据。此时返回false。然后我们我们通过getListSameIndex方法获取到list重复数据的下标然后替换[index]。
3.6 测试
3.6.1 前端传递参数,需要进行唯一性校验的字段
3.6.2 message提示
相关文章:

Java自定义校验注解实现List、set集合字段唯一性校验
文章目录 一: 使用场景二: 定义FieldUniqueValid注解2.1 FieldUniqueValid2.2 注解说明2.3 Constraint 注解介绍2.4 FieldUniqueValid注解使用 三:自定义FieldUniqueValidator校验类3.1 实现ConstraintValidator3.2 重写initialize方法3.3 重…...
xiaoweirobot.chat
目录 1 xiaoweirobot.chat 1.1 DetailList 2 HttpData 2.1 doInBackground 2.2 onPostExecute xiaoweirobot.chatpackage com.shrimp.xiaoweirobot.chat; DetailList <...

【无公网IP】本地电脑搭建个人博客网站(并发布公网访问 )和web服务器
【无公网IP】本地电脑搭建个人博客网站(并发布公网访问 )和web服务器 文章目录 【无公网IP】本地电脑搭建个人博客网站(并发布公网访问 )和web服务器前言1. 安装套件软件2. 创建网页运行环境 指定网页输出的端口号3. 让WordPress在…...

SpringCloud(29):Nacos简介
1 什么是配置中心 1.1 什么是配置 应用程序在启动和运行的时候往往需要读取一些配置信息,配置基本上伴随着应用程序的整个生命周期,比如:数据库连接参数、启动参数等。 配置主要有以下几个特点: 配置是独立于程序的只读变量 …...
freeBSD - 笔记
1 介绍 FreeBSD: FreeBSD是由FreeBSD项目团队开发的,最早可以追溯到1993年。它专注于性能、稳定性和可靠性,并在服务器和高性能计算环境中广泛使用。FreeBSD有着强大的网络性能和高度优化的TCP/IP协议栈,因此在网络服务器领域表…...

【Linux】网络基础——宏观认识计算机网络
1 计算机网络背景 网络发展 独立模式: 计算机之间相互独立; 一开始,计算机发明出来之后,一台计算机处理完的数据,数据会保存在软盘(物理),通过人之间的相互通信,把计算机A处理完的数据存储到软…...

数字人现身大运会,怎么以动作捕捉技术助推运动与文博相结合
中国移动动感地带数字人橙络络,作为数智体验官以元宇宙的视角,带领观众沉浸式体验大运会,以极具科技和未来的数字人,对外传递大运青春风采,并且数字人橙络络还对大运会的赛事、活动进行了科普、讲解以及表演当地特色才…...

WSL安装
WSL安装 1.Microsoft store 安装 1.1 启动WSL功能 在【程序和功能 -> 启用或关闭 Windows 功能】中勾选【适用于 Linux 的 Windows 子系统】 1.2 Store中下载安装 在 Microsoft Store 中下载并安装需要的 Linux 发行版 2.不使用Store安装WSL 注:1.1也要…...

MongoDB 入门
1.1 数据库管理系统 在了解MongoDB之前需要先了解先数据库管理系统 1.1.1 什么是数据? 数据(英语:data),是指未经过处理的原始记录。 一般而言,数据缺乏组织及分类,无法明确的表达事物代表的意…...

使用uni-app的uniCloud 云数据库入门:实现一个简单的增删改查
官方云数据库文档 前置步骤使用uni-app新建一个uniCloud项目 [外链图片转存失败,源站可能有防盗官方云数据库文档]!链机制,建议将()https://uniapp.dcloud.net.cn/uniCloud/hellodb.html)] 新建表 这里我加了几个测试字段 createTime、remark、money // 文档教程: https://un…...

【MATLAB第64期】【保姆级教程】基于MATLAB的SOBOL全局敏感性分析模型运用(含无目标函数,考虑代理模型)
【MATLAB第64期】【保姆级教程】基于MATLAB的SOBOL全局敏感性分析模型运用(含无目标函数,考虑代理模型) 版本更新: 2023/8/5: 1.因BP作为代理模型不稳定,经过测试,libsvm比rf /bp 效果稳定且精…...

Python web实战之Django用户认证详解
关键词: Python Web 开发、Django、用户认证、实战案例 概要 今天来探讨一下 Django 的用户认证吧!在这篇文章中,我将为大家带来一些有关 Django 用户认证的最佳实践。 1. Django 用户认证 在开发 Web 应用程序时,用户认证是一个…...

每天五分钟机器学习:梯度下降算法和正规方程的比较
本文重点 梯度下降算法和正规方程是两种常用的机器学习算法,用于求解线性回归问题。它们各自有一些优点和缺点,下面将分别对它们进行详细的讨论。 区别 1. 梯度下降算法是一种迭代的优化算法,通过不断迭代调整参数来逼近最优解。它的基本思想是根据目标函数的梯度方向,沿…...

生信学院|08月18日《基于Flow Simulation的冷链运输产品案例》
课程主题:基于Flow Simulation的冷链运输产品案例 课程时间:2023年08月18日 14:00-14:30 主讲人:江流洋 生信科技 CAE专家 1、达索仿真方案介绍 2、项目介绍 3、案例分析 请安装腾讯会议客户端或APP,微信扫描海报中的二维码…...

不可错过的家装服务预约小程序商城开发指南
在当今社会,家装行业发展迅速,越来越多的人开始寻求专业的家装预约和咨询服务。对于不懂技术的新手来说,创建一个自己的家装预约咨询平台可能听起来很困难,但实际上通过一些第三方制作平台和工具,这个过程可以变得简单…...

任务 13、MidJourney种子激发极致创作,绘制震撼连贯画作
13.1 任务概述 通过本次实验任务,学员将深入了解Midjourney种子的概念和重要性,以及种子对生成图像的影响。他们将学会在Midjourney平台中设置种子值并调整其参数,以达到所需的效果。此外,任务还详细介绍了Midjourney V4.0版本中…...

IAR开发环境的安装、配置和新建STM32工程模板
IAR到环境配置到新建工程模板-以STM32为例 一、 简单介绍一下IAR软件1. IAR的安装(1) 下载IAR集成开发环境安装文件(2) 安装 2. 软件注册授权 二、IAR上手使用(基于STM32标准库新建工程)1、下载标准库文件2、在IAR新建工程&#x…...

FPGA优质开源项目 – PCIE通信
本文介绍一个FPGA开源项目:PCIE通信。该工程围绕Vivado软件中提供的PCIE通信IP核XDMA IP建立。Xilinx提供了XDMA的开源驱动程序,可在Windows系统或者Linux系统下使用,因此采用XDMA IP进行PCIE通信是比较简单直接的。 本文主要介绍一下XDMA I…...

NLP:长文本场景下段落分割(文本分割、Text segmentation)算法实践----一种结合自适应滑窗的文本分割序列模型
NLP专栏简介:数据增强、智能标注、意图识别算法|多分类算法、文本信息抽取、多模态信息抽取、可解释性分析、性能调优、模型压缩算法等 专栏详细介绍:NLP专栏简介:数据增强、智能标注、意图识别算法|多分类算法、文本信息抽取、多模态信息抽取、可解释性分析、性能调优、模型…...
商汤科技2021校招-开发大类B卷
笔试时间:2020.09.18,19:00——21:00 岗位:嵌入式软件工程师 题型:单选4道,不定项选择题2道,填空2道,编程2道。 1、单选 1、在一棵二叉树上第5层的结点数最多是:16 第1层1个 2^0 第2层2个 2^1 第3层4个 2^2 第n层 2^(n-1...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...

边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...