Java 自定义注解校验字段唯一性
业务场景
在项目中,某些情景下我们需要验证编码是否重复,账号是否重复,身份证号是否重复等...
那么有没有办法可以解决这类似的重复代码量呢?
我们可以通过自定义注解校验的方式去实现,在实体类上面加上自定义的注解即可
@FieldRepeat(fields = {"account"}, message = "账号已存在!")
实现步骤
1.引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.3.11.RELEASE</version>
</dependency>
2.新增自定义注解
// 注意:实体类必须继承Model,且需要标明表名@TableName("t_test"),校验字段需要加上注解 @TableField("name")
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = FieldRepeatValidator.class)
public @interface FieldRepeat {
/**
* 需要检验的字段
* @return
*/
String[] field() default {};
String message() default "您输入的内容已存在";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
3.新增@FieldRepeat注解接口实现类
public class FieldRepeatValidator implements ConstraintValidator<FieldRepeat, Object> {
@Autowired
private FieldRepeatUtils fieldRepeatUtils;
private String[] fields;
private String message;
@Override
public void initialize(FieldRepeat fieldRepeat) {
this.fields = fieldRepeat.fields();
this.message = fieldRepeat.message();
}
@Override
public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
return fieldRepeatUtils.fieldRepeat(fields, o, message);
}
}
4.新增字段内容重复判断处理工具类
@Component
@Slf4j
public class FieldRepeatUtils {
/**
* 实体类中的id字段
*/
private String idColumnName;
/**
* 实体类中的id的值
*/
private Object idColumnValue;
/**
*
* @param fields 验证的字段数组
* @param message 如果不满足返回的消息
* @param o 实体类
* @return
*/
public boolean fieldRepeat(String [] fields,String message,Object o) throws ValidationException,IllegalAccessException {
try {
// 没有校验的值返回true
if(fields != null && fields.length == 0){
return true;
}
checkUpdateOrSave(o);
checkRepeat(fields,o,message);
return true;
}catch (ValidationException ed){
throw new ValidationException(message);
}catch (IllegalAccessException e){
throw new IllegalAccessException(e.getMessage());
}
}
/**
* 通过传入的实体类中 @TableId 注解的值是否为空,来判断是更新还是保存
* 将值id值和id列名赋值
* id的值不为空 是更新 否则是插入
* @param o 被注解修饰过的实体类
* @return
*/
public void checkUpdateOrSave(Object o) throws IllegalAccessException{
Field[] fields = getAllFields(o.getClass());
for (Field f:fields) {
// 设置私有属性可读
f.setAccessible(true);
if(f.isAnnotationPresent(TableId.class)){
TableId tableId = f.getAnnotation(TableId.class);
idColumnName = tableId.value();
idColumnValue = f.get(o);
}
}
}
/**
* 获取本类及其父类的属性的方法
* @param clazz 当前类对象
* @return 字段数组
*/
private static Field[] getAllFields(Class<?> clazz) {
List<Field> fieldList = new ArrayList<>();
while (clazz != null){
fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
clazz = clazz.getSuperclass();
}
Field[] fields = new Field[fieldList.size()];
return fieldList.toArray(fields);
}
/**
* 通过传入的字段值获取数据是否重复
* @param fields
* @param o
* @param message
* @return
*/
public void checkRepeat(String [] fields,Object o,String message) throws ValidationException, IllegalAccessException {
Model model = (Model) o;
//Mybatis-plus 3.0以下用EntityWrapper
QueryWrapper<Object> qw = new QueryWrapper<>();
Map<String,Object> queryMap = getColumns(fields,o);
for (Map.Entry<String, Object> entry : queryMap.entrySet()) {
qw.eq(entry.getKey(), entry.getValue());
}
if(idColumnValue != null){
//更新的话,那条件就要排除自身
qw.ne(idColumnName,idColumnValue);
}
List list = model.selectList(qw);
if(list != null && list.size()>0){
throw new ValidationException(message);
}
}
/**
* 多条件判断唯一性,将我们的属性和值组装在map中,方便后续拼接条件
* @param fields
* @param o
* @return
*/
public Map<String,Object> getColumns(String [] fields,Object o) throws IllegalAccessException {
Field[] fieldList = getAllFields(o.getClass());
Map<String,Object> map = new HashMap<>();
for (Field f : fieldList) {
// ② 设置对象中成员 属性private为可读
f.setAccessible(true);
// 判断字段是否包含在数组中,如果存在,则将它对应的列字段放入map中
if(ArrayUtils.contains(fields,f.getName())){
getMapData(map,f,o);
}
}
return map;
}
/**
* 得到查询条件
* @param map 列字段
* @param f 字段
* @param o 传入的对象
*/
private void getMapData( Map<String,Object> map,Field f,Object o) throws IllegalAccessException {
try {
if(f.isAnnotationPresent(TableField.class)){
TableField tableField = f.getAnnotation(TableField.class);
Object val = f.get(o);
map.put(tableField.value(),val);
}
}catch (IllegalAccessException i){
throw new IllegalAccessException("获取字段的值错误");
}
}
}
测试类
@Data
@TableName("t_test")
@FieldRepeat(fields = {"name"},message = "名称不能重复,请重新输入",groups = {Base.Save.class,Base.Update.class})
public class Test extends Model<Test>{
@TableId(value = "id", type = IdType.AUTO)
@NotNull(message = "id不能为空",groups = {Base.Update.class,Base.Delete.class,Base.Detail.class})
private Long id;
@TableField("name")
@NotNull(message = "名称不能为空",groups = {Base.Update.class,Base.Save.class})
private String name;
}
Java 自定义注解校验字段唯一性的更多相关文章
- Java自定义注解源码+原理解释(使用Java自定义注解校验bean传入参数合法性)
Java自定义注解源码+原理解释(使用Java自定义注解校验bean传入参数合法性) 前言:由于前段时间忙于写接口,在接口中需要做很多的参数校验,本着简洁.高效的原则,便写了这个小工具供自己使用(内容 ...
- Java 自定义注解 校验指定字段对应数据库内容重复
一.前言 在项目中,某些情景下我们需要验证编码是否重复,账号是否重复,身份证号是否重复等... 而像验证这类代码如下: 那么有没有办法可以解决这类似的重复代码量呢? 我们可以通过自定义注解校验的方式去 ...
- java自定义注解实现前后台参数校验
2016.07.26 qq:992591601,欢迎交流 首先介绍些基本概念: Annotations(also known as metadata)provide a formalized way ...
- java自定义注解类
一.前言 今天阅读帆哥代码的时候,看到了之前没有见过的新东西, 比如java自定义注解类,如何获取注解,如何反射内部类,this$0是什么意思? 于是乎,学习并整理了一下. 二.代码示例 import ...
- java自定义注解注解方法、类、属性等等【转】
http://anole1982.iteye.com/blog/1450421 http://www.open-open.com/doc/view/51fe76de67214563b20b385320 ...
- JAVA自定义注解 ------ Annotation
日常开发工作中,合理的使用注解,可以简化代码编写以及使代码结构更加简单,下面记录下,JAVA自定义注解的开发过程. 定义注解声明类. 编写注解处理器(主要起作用部分). 使用注解. 相关知识点介绍, ...
- Java自定义注解和运行时靠反射获取注解
转载:http://blog.csdn.net/bao19901210/article/details/17201173/ java自定义注解 Java注解是附加在代码中的一些元信息,用于一些工具在编 ...
- java自定义注解知识实例及SSH框架下,拦截器中无法获得java注解属性值的问题
一.java自定义注解相关知识 注解这东西是java语言本身就带有的功能特点,于struts,hibernate,spring这三个框架无关.使用得当特别方便.基于注解的xml文件配置方式也受到人们的 ...
- Java自定义注解的实现
Java自定义注解的实现,总共三步(eg.@RandomlyThrowsException): 1.首先编写一个自定义注解@RandomlyThrowsException package com.gi ...
- Java自定义注解开发
一.背景 最近在自己搞一个项目时,遇到可需要开发自定义注解的需求,对于没有怎么关注这些java新特性的来说,比较尴尬,索性就拿出一些时间,来进行研究下自定义注解开发的步骤以及使用方式.今天在这里记下, ...
随机推荐
- AI 编译器CINN中的OpLowering优化Pass
一.Lower 主逻辑 在 OpLower::Lower() 接口中,主要分为两大类: Elementwise类,主要涉及的 OpPattern 包括:kElementwise .kBroadcast ...
- 支持4k的远程桌面软件有哪些
在当今的数字时代,在全球向灵活工作安排和分布式团队转变的推动下,对远程工作解决方案的需求猛增.远程桌面软件已成为寻求让员工能够在任何地方工作的企业的重要工具.在用户在此类软件中寻求的众多功能中,对 4 ...
- 通过ref返回解决C# struct结构体链式调用的问题
通常结构体不能进行链式调用,因为返回值是一个新的值,需要赋回原值.但现在通过ref关键字配合扩展方法,也能进行链式调用了. 结构体: public struct Foo { public int a; ...
- 网络拓扑—WEB-IIS服务搭建
目录 WEB-IIS服务搭建 网络拓扑 配置网络 IIS PC 安装IIS服务 配置IIS服务(默认站点) PC机访问网页 配置IIS服务(新建站点) PC机访问网页 WEB-IIS服务搭建 网络拓扑 ...
- 带你阅读Naive Ui Admin后台管理源码,并手撸JS版本
Naive Ui Admin 是一个基于 Vue3.0.Vite. Naive UI.TypeScript 的中后台解决方案,它使用了最新的前端技术栈,并提炼了典型的业务模型,页面,包括二次封装组件. ...
- NOIP模拟89(多校22)
T1 谜之阶乘 解题思路 二分答案,发现 \(a-b\) 至多为 19,毕竟 \(20!\) 已经大于 \(10^{18}\) 了. 对于每一种可能的差值,每一次二分 \(b+1\) 直接枚举乘积进行 ...
- itest(爱测试) 开源接口测试,敏捷测试管理平台10.0.1
一:itest work 简介 itest work 开源敏捷测试管理,包含极简的任务管理,测试管理,缺陷管理,测试环境管理,接口测试,接口Mock,还有压测 ,又有丰富的统计分析,8合1工作站.可按 ...
- Redisson 限流器源码分析
Redisson 限流器源码分析 对上篇文章网友评论给出问题进行解答:redis 的key 是否会过期 可以先阅读上篇文章: redis + AOP + 自定义注解实现接口限流 - 古渡蓝按 - 博客 ...
- python-一种去掉前后缀获取子串的方法
假设有一个字符串,其数据组成方式为:"mode_id1_str_id2",其中id1和id2为任意个数的数字,若存在mode,则id1必然也存在,否则都不存在:id2可有可没有. ...
- 剑指Offer-67.剪绳子(C++/Java)
题目: 给你一根长度为n的绳子,请把绳子剪成整数长的m段(m.n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],...,k[m].请问k[0]xk[1]x...xk[m ...