【java】实现自定义注解校验——方法一

自定义注解校验的实现步骤:

1.创建注解类,编写校验注解,即类似@NotEmpty注解
2.编写自定义校验的逻辑实体类,编写具体的校验逻辑。(这个类可以实现ConstraintValidator这个接口,让注解用来校验)
3.开启使用自定义注解进行校验。

第一种实现自定义注解的方式:

一、创建注解类:

1、创建类时,选择Annotation类型

在这里插入图片描述

2、编写注解类

编写注解类时,需要用到元注解来规定注解的实现方式等;

package cn.hsa.bis.api.common.utils;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Description 基础校验注解
 * @Author chenzz
 * @create 2020/3/6 19:43
 */
//Target注解是指定当前自定义注解可以使用在哪些地方,这里仅仅让他可以使用在字段上;
@Target(ElementType.FIELD)
//指定当前注解保留到运行时;
@Retention(RetentionPolicy.RUNTIME)
public @interface ValiInfo {

    /**
     * 最小长度
     */
    int minLen() default 0;

    /**
     * 最大长度
     */
    int maxLen() default 2147483647;

    /**
     * 非空校验
     */
    boolean notBlank() default false;

    /**
     * 字典校验
     */
    String codeType() default "";

    /**
     * 非法字符校验
     * 特殊字符:ascii码表中除字母、数字外的所有字符,顿号(、),间隔号(·)
     */
    String illegalCharRegExp() default ".*[\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\x7f\\u3001\\u00b7]+.*";

    /**
     * 正则校验
     */
    String regexp() default "";

    /**
     * 字段含义
     */
    String mean() default "";

    /**
     * 汉字校验
     */
    String regexpChinese() default "";
}

3、元注解 (编写注解类时,必须要明白的)

刚创建出来的注解是不能使用的。因为我们不知道注解应该加在什么地方,在什么时间生效,所以就引出来元注解的概念。元注解就是注解的注解(有点绕口令的感觉)。专门用来注解注解类型。
java的元注解:@Target,@Retention,@Documented,@Inherited

@Target直接指明了该注解生效的位置,该参数没有default值,必填。参数是一个枚举类型
在这里插入图片描述

@Retention指明了注解生效的阶段
在这里插入图片描述
@Documented
当我们用javaDoc生成API文档时,是否将该注解记录到API文档中。
@Inherited
这个注解是说,我们的注解是否需要被子类继承。是发生在子类和父类之间的一种注解。

注意:当我们的注解作用域是Element.TYPE时,我们定义在类上的注解可以被子类继承。但是如果我们注解的作用域是Element.METHOD时,并且父类的该方法被子类重写,那作用在父类的注解不会被子类继承。所以如果我们在接口的方法中定义的注解,永远不会被实现类继承,因为实现类一定会重写接口中的方法。

二、自定义注解校验逻辑的实现:

这里有两种实现方式,
一种是当注解仅仅作用在字段(属性)上生效时:可以在工具类中编写方法进行逻辑校验;
另一种是当注解作用在方法上生效时,可以使用@Constraint注解,指明了校验类,进行校验;

这里只实现第一种。

第一种:当自定义注解仅仅作用在字段上生效时,在工具类中编写方法进行逻辑校验(在工作中用的比较多)

public class ToolUtils {
    /**
     * 对象基础格式校验,针对带有valiInfo注解的属性
     * @param obj
     * @param ignoreFields 忽略校验的字段
     * @return: java.lang.StringBuffer
     * @author: chenzz
     * @date: 2020/4/22 23:36
     */
    public static StringBuffer valiObjStringField(Object obj, String[] ignoreFields) {
        StringBuffer errMsg = new StringBuffer();
        try {
            Set<String> ignoreFieldSet = new HashSet<>();
            ignoreFieldSet.add("class");
            if (null != ignoreFields) {
                for (String field : ignoreFields) {
                    if (StringUtils.isNotBlank(field)) {
                        ignoreFieldSet.add(field);
                    }
                }
            }
            PropertyDescriptor[] propertyDescriptors = BeanUtils.getPropertyDescriptors(obj.getClass());
            for (PropertyDescriptor targetPd : propertyDescriptors) {
                if (ignoreFieldSet.contains(targetPd.getName())) {
                    continue;
                }
                Method readMethod = targetPd.getReadMethod();
                if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
                    readMethod.setAccessible(true);
                }
                Object value = readMethod.invoke(obj);
                ValiInfo valiInfo = obj.getClass().getDeclaredField(targetPd.getName()).getAnnotation(ValiInfo.class);
                if (null == valiInfo) {
                    continue;
                }
                String mean = valiInfo.mean();
                if (StringUtils.isBlank(mean)) {
                    mean = targetPd.getName();
                }
                // 空置校验
                boolean isBlank = null == value || StringUtils.isBlank(value.toString());
                if (valiInfo.notBlank()) {
                    if (isBlank) {
                        errMsg.append(String.format("【%s】不能为空;", mean));
                        continue;
                    }
                } else {
                    if (isBlank) {
                        continue;
                    }
                }
                // 如果是字符串才进行下面的校验
                if (!(value instanceof String)) {
                    continue;
                }
                String strValue = value.toString();
                // 长度校验 最小长度为0
                int len = strValue.length();
                if (len < valiInfo.minLen()) {
                    errMsg.append(String.format("【%s(%s)】长度不能小于%d个字符;", mean, strValue, valiInfo.minLen()));
                    continue;
                }
                // 最大长度为2147483647
                if (len > valiInfo.maxLen()) {
                    errMsg.append(String.format("【%s(%s)】长度不能超过%d个字符;", mean, strValue, valiInfo.maxLen()));
                    Method writeMethod = targetPd.getWriteMethod();
                    if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
                        writeMethod.setAccessible(true);
                    }
                    writeMethod.invoke(obj, strValue.substring(0, valiInfo.maxLen() - 1));
                    continue;
                }
                if (strValue.matches(valiInfo.illegalCharRegExp())) {
                    errMsg.append(String.format("【%s(%s)】中不能包含特殊字符;", mean, strValue));
                    continue;
                }
                if (StringUtils.isNotBlank(valiInfo.regexp()) && !strValue.matches(valiInfo.regexp())) {
                    errMsg.append(String.format("【%s(%s)】格式校验不通过;", mean, strValue));
                    continue;
                }
                // 校验是否存在汉字
                if (StringUtils.isNotBlank(valiInfo.regexpChinese())) {
                    char c[] = strValue.toCharArray();
                    Pattern pattern = Pattern.compile(valiInfo.regexpChinese());
                    boolean flag = false;
                    for (int i = 0; i < c.length; i++) {
                        Matcher matcher = pattern.matcher(String.valueOf(c[i]));
                        if (matcher.matches()) {
                            flag = true;
                        }
                    }
                    if (flag) {
                        errMsg.append(String.format("【%s(%s)】入参存在汉字;", mean, strValue));
                        continue;
                    }
                }
                // 码值校验
                if (StringUtils.isNotBlank(valiInfo.codeType())) {
                    if (DictUtil.isNotDict(valiInfo.codeType().toUpperCase(), strValue)) {
                        errMsg.append(String.format("【%s(%s)】不在代码表中;", mean, strValue));
                    }
                }
            }
            return errMsg;
        } catch (IllegalAccessException e) {
            throw new BisException(BusinessConst.CALL_FAIL_TYPE_JC, "对象数据格式校验失败!");
        } catch (InvocationTargetException e) {
            throw new BisException(BusinessConst.CALL_FAIL_TYPE_JC, "对象数据格式校验失败!");
        } catch (NoSuchFieldException e) {
            throw new BisException(BusinessConst.CALL_FAIL_TYPE_JC, "对象数据格式校验失败!");
        }
    }
}

三、使用自定义注解:

自定义校验注解在代码中的应用

1、在dto中使用:

@Data
public class PsnInsureInfoQueryDTO implements Serializable {
    private static final long serialVersionUID = -3173331123860803536L;

    /**
     * 缴费开始年月
     */
    @ValiInfo(mean = "缴费开始", minLen = 6, maxLen = 6, regexp = RegexpConst.REGEXP_YM)
    private String begnYm;

    /**
     * 单位编号
     */
    @ValiInfo(mean = "单位编号", minLen = 1, maxLen = 40, illegalCharRegExp = RegexpConst.ILLEGAL_CHAR_REGEXP_EMPNO, regexpChinese = RegexpConst.REGEXP_CHINESE)
    private String empNo;

    /**
     * 险种类型
     */
    @ValiInfo(mean = "险种类型", minLen = 1, maxLen = 3, codeType = "INSUTYPE", regexpChinese = RegexpConst.REGEXP_CHINESE)
    private String insutype;

    /**
     * 统筹区编码
     */
    @ValiInfo(mean = "统筹区编码", minLen = 6, maxLen = 6, codeType = "ADMDVS_PLC", regexpChinese = RegexpConst.REGEXP_CHINESE)
    private String poolarea;

    /**
     * 参保状态
     */
    @ValiInfo(mean = "参保状态", minLen = 1, maxLen = 3, codeType = "PSN_INSU_STAS", regexpChinese = RegexpConst.REGEXP_CHINESE)
    private String psnInsuStas;

    /**
     * 人员编号
     */
    @ValiInfo(mean = "人员编号", minLen = 1, maxLen = 36, notBlank = true, regexpChinese = RegexpConst.REGEXP_CHINESE, illegalCharRegExp = RegexpConst.ILLEGAL_CHAR_REGEXP_PSNNO)
    private String psnNo;
}

2、在代码中,通过调用valiObjStringField方法来进行校验:

//control层的方法
public ResultVO insertHmcYcx(@RequestBody HmcinfoDTO hmcinfoDTO){
    //.......其它逻辑
    
    //调用方法,进行自定义注解的校验
    String errorMsg = ToolUtils.valiObjStringField(hmcinfoDTO).toString();
    if (StringUtils.isNotBlank(errorMsg)) {
        log.info(errorMsg);
        return new ResultVO(errorMsg);
    }
    //.......其它逻辑
    ResultVO vo = hmcBPO.insertHmc(hmcinfoDTO);
    return vo;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/119650.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

超级英雄云计算的技术之旅

超级英雄云计算的技术之旅 超级英雄云计算的技术之旅摘要引言可变参数&#xff1a;Java的超级工具可变参数的用途1. 编写通用工具方法2. 构建日志记录工具3. 构建数据验证工具 云计算在智能家居中的应用1. 远程控制智能设备2. 数据分析和智能决策3. 安全和隐私4. 智能家居应用开…

掌动智能性能压力测试优势有哪些

企业通过自动化的测试工具模拟多种正常、峰值以及异常负载条件来对系统的各项性能指标进行测试。本文将介绍性能压力测试的价值及主要优势! 一、性能压力测试的价值 1、评估系统能力&#xff1a;有助于参数的基准测试&#xff0c;可以度量系统的响应时间;还有助于检查系统是否可…

python-opencv写入视频文件无法播放

python-opencv写入视频文件无法播放 在采用Python写OpenCV的视频时&#xff0c;生成的视频总是无法播放&#xff0c;大小只有不到两百k&#xff0c;播放器提示视频已经损坏。网上搜了一些方法&#xff0c;记录下解决办法。 代码如下 fourcc cv2.VideoWriter_fourcc(*MJPG) fp…

idea中配置spring boot单项目多端口启动

参照文章 https://zhuanlan.zhihu.com/p/610767685 项目配置如下 下面为 idea 2023&#xff0c;不同版本的设置有区别&#xff0c;但是没那么大&#xff0c;idea 2023默认使用新布局&#xff0c;切换为经典布局即可。 在项目根目录的.idea/workspace.xml文件里添加如下配置 &l…

装甲工程车3D虚拟云展厅提升企业在市场占有份额

应急通信车的出现&#xff0c;极大适应了防灾救援大数据背景下数字化、网络化、系统化、多维化的发展需求&#xff0c;为了让更多客户了解到应急通信车&#xff0c;提升企业在市场占有份额及领域&#xff0c;借助web3d开发制作的应急通信车3D云展示平台大大丰富了展示形式及内涵…

10年测试经验分享:新手如何找到适合自己的软件测试项目?

每一个测试新手&#xff08;特别是自学测试的人&#xff09;来说&#xff0c;往往不知道到哪里去找项目练手&#xff0c;这应该是最大的困扰了。 实话讲&#xff0c;这个目前没有非常好的、直接的解决办法&#xff0c;不过在这我可以结合我自己之前的一些工作经历&#xff0c;…

Linux实现进度条小程序(包含基础版本和模拟下载过程版本)

Linux实现进度条小程序[包含基础版本和模拟下载过程版本] Linux实现进度条小程序1.预备的两个小知识1.缓冲区1.缓冲区概念的引出2.缓冲区的概念 2.回车与换行1.小例子2.倒计时小程序 2.基础版进度条1.的回车方式的打印2.百分比的打印3.状态提示符的打印 3.升级版进度条1.设计:进…

webgoat-Insecure Deserialization不安全的序列化

A&#xff08;8&#xff09;不安全的反序列化 反序列化是将已序列化的数据还原回对象的过程。然而&#xff0c;如果反序列化是不安全的&#xff0c;那么恶意攻击者可以在序列化的数据中夹带恶意代码&#xff0c;从而在反序列化时执行这些代码。这种攻击被称为反序列化。 什么…

Java 开发常用的 Linux 命令

基本操作 Linux关机,重启 # 关机 shutdown -h now# 重启 shutdown -r now查看系统,CPU信息 # 查看系统内核信息 uname -a# 查看系统内核版本 cat /proc/version# 查看当前用户环境变量 envcat /proc/cpuinfo# 查看有几个逻辑cpu, 包括cpu型号 cat /proc/cpuinfo | grep name …

Linux 进程控制

进程地址空间的收尾 task_struct有一个结构体成员叫mm_struct&#xff0c;也就是进程地址空间。 为什么要有进程地址空间&#xff1a;进程内存地址管理&#xff0c;保护物理内存&#xff0c;进行权限审查&#xff0c;从无序变有序&#xff0c;让我们从统一的视角看待进程代码…

Java开发注意事项和细节说明

&#x1f468;‍&#x1f393;&#x1f468;‍&#x1f393;博主&#xff1a;发量不足 个人简介&#xff1a;耐心&#xff0c;自信来源于你强大的思想和知识基础&#xff01;&#xff01; &#x1f4d1;&#x1f4d1;本期更新内容&#xff1a;Java开发注意事项和细节说明&…

网络安全深入学习第八课——反向代理(工具:frp)

文章目录 一、实验环境二、实验要求三、开始模拟1、攻击机配置frp文件2、攻击拿下跳板机&#xff0c;并且上传frpc.ini、frpc.exe、frpc_full.ini文件3、把frps.ini、、frps.exe、frps_full.ini文件放到VPS主机上4、VPS机开启frp5、跳板机开启frp6、验证 一、实验环境 攻击机&…

6 从物理层到MAC层

1、实现局域网中玩游戏 在早期的80后的大学宿舍中&#xff0c;组件一个宿舍的局域网&#xff0c;以便于宿舍内部可以玩游戏. 第一层&#xff08;物理层&#xff09; 1.首先是实现电脑连接电脑&#xff0c;需要依靠网线&#xff0c;有两个头。 2.一头插在一台电脑的网卡上&am…

【有源码】基于uniapp的农场管理小程序springboot基于微信小程序的农场检测系统(源码 调试 lw 开题报告ppt)

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人七年开发经验&#xff0c;擅长Java、Python、PHP、.NET、微信小程序、爬虫、大数据等&#xff0c;大家有这一块的问题可以一起交流&#xff01; &#x1f495;&…

阿里p8大佬手写web自动化测试框架教程 涵盖框架源码+视频教程以及搭建流程

前言 ​ 测试行业现在70%是以手工测试为主&#xff0c;那么只有20%是自动化测试&#xff0c;剩下的10%是性能测试。 有人可能会说&#xff0c;我现在做手工&#xff0c;我为什么要学自动化呢&#xff1f;我去学性能更好性能的人更少&#xff1f; 其实&#xff0c;性能的要求…

Q-Vision+CANpro Max总线解决方案

智能联网技术在国内的发展势头迅猛&#xff0c;随着汽车智能化、网联化发展大潮的到来&#xff0c;智能网联汽车逐步成为汽车发展的主要趋势。越来越多整车厂诉求&#xff0c;希望可以提供本土的测量软件&#xff0c;特别是关于ADAS测试。而风丘科技推出的Q-Vision软件不仅可支…

大数据毕业设计选题推荐-家具公司运营数据分析平台-Hadoop-Spark-Hive

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

【Java 进阶篇】JSP 内置对象详解

JavaServer Pages&#xff08;JSP&#xff09;是一种用于构建动态 Web 应用程序的 Java 技术。在 JSP 中&#xff0c;有许多内置对象可供开发人员使用&#xff0c;以便更轻松地构建功能丰富的网页。本博客将深入探讨 JSP 的内置对象&#xff0c;从入门到精通&#xff0c;帮助您…

建材行业微信小程序制作全攻略

随着移动互联网的发展&#xff0c;微信小程序成为各行各业推广和服务的新方式。对于建材行业来说&#xff0c;制作一个微信小程序商城能够提供更方便快捷的购买途径&#xff0c;提升用户体验。下面将为大家介绍建材行业微信小程序制作的全攻略。 第一步&#xff1a;注册登录账号…

【electron】【附排查清单】记录一次逆向过程中,fetch无法请求http的疑难杂症(net::ERR_BLOCKED_BY_CLIENT)

▒ 目录 ▒ &#x1f6eb; 导读需求开发环境 1️⃣ Adblock等插件拦截2️⃣ 【失败】Content-Security-Policy启动服务器json-serverhtml中的meta字段 3️⃣ 【失败】https vs httpwebPreferences & allowRunningInsecureContent disable-features 4️⃣ 【失败】检测fetch…