自定义注解判断参数为空

简介: 使用Spring的 @Valid和@Validated不好嘛,干嘛要自己造轮子呢.......

最近在项目中遇到了一个小小的问题,和大家分享一下,简单的接口但是在不同的业务场景下需要有不同的校验逻辑,有的参数在特定的场景下需要校验,有的参数在另外的场景下则不需要校验。解决方案有很多种加上我当时是刚刚入职为了偷懒贪图省事,所以就写了一大堆的if/else。如下展示(由于业务原因,敏感字段已转换):

public void checkParams(DTO dto) {
    if (ObjectUtils.isEmpty(dto.getParam())) {
        throw new ServiceException("Please fill in the param number");
    }
    if (ObjectUtils.isEmpty(dto.getParam())) {
        throw new ServiceException("Please fill in the param number");
    }
    if (ObjectUtils.isEmpty(dto.getParam())) {
        throw new ServiceException("Please fill in the param number");
    }
    if (ObjectUtils.isEmpty(dto.getParam())) {
        throw new ServiceException("Please fill in the param number");
    }
    if (ObjectUtils.isEmpty(dto.getParam())) {
        throw new ServiceException("Please fill in the param number");
    }
    if (ObjectUtils.isEmpty(dto.getParam())) {
        throw new ServiceException("Please fill in the param number");
    }
    if (ObjectUtils.isEmpty(dto.getParam())) {
        throw new ServiceException("Please fill in the param number");
    }

    ..............
}

为了方法的可读性吧,我还特意将检验参数的方法抽离出checkParams单独的方法。当时想这样应该也就可以了吧。万万没想到啊,我在编写完代码的时候在pull代码前的编译的时候,PMD检查没有过这个是把我给恶心到了当时报了一个错叫做什么 Avoid really long methods 和 GodClass这就让我很尴尬了,临门一脚给我拦住了很是郁闷。当时想我一个新来的需要抓紧把代码提上去不能拖延时间啊,接着我又开始了一系列的骚操作是你们不可能想到的。如下:
image.png
相比各位童鞋们看到参数的命名很无语吧,当时我也很无语其实我下意识是不想这么做的。但是没有办法,当时着急熟悉代码。以及完成工作没办法我还是硬着头皮把这个代码给改掉了。想着以后有时间改掉吧。天不遂人愿啊真的是。隔天我就经历了code review,各位你们可知道那种场合,我写的代码被斩首示众,我当时简直脚趾抠出来三室一厅的尴尬,好在是我leader明白我当时的困境理解我(此时我还是很庆幸的),说没事有时间改过来就好。cw一完事,我忙完自己手里的活,果断的偷偷的把这个低级错误给办了。利用了自定义注解的方式。废话不多说给大家看一下核心代码。

  • 首先我建立了一个注解类
package com.mb.rks.cases.common.annotation;

import java.lang.annotation.*;

/**
 * @author
 * <p>自定义注解校验参数<p>
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MetadataValidation {

    /**
     * 错误信息
     * @return
     */
    String message() default "参数不能为空";

    /**
     * 正则表达式
     * @return
     */
    String pattern() default "";

}
  • 然后利用反射写了一个验证器
package com.mb.rks.cases.common.utils;

import com.mb.rks.cases.common.annotation.MetadataValidation;
import com.mb.rks.cases.common.exception.TipsValidationException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * @author
 * <p>Validation验证器<p>
 * <p>
 * 对有自定义注解@Validation的参数进行校验
 */
@Slf4j
public final class ValidationCheckUtils {

    /**
     * 因为是工具类,所以不可以通过new的方式去创建,顾将其构造方法写成如下方式
     */
    protected ValidationCheckUtils(){}

    /**
     * 检验方法:
     * <p>扫描对象的属性,查看是否有@Validation注解,有注解的进行校验
     *
     * @param o 要校验的对象,入参对象
     */
    public static void check(Object o) {
        if (null == o) {
            return;
        }
        Class<?> clazz = o.getClass();
        List<Field> fieldList = new ArrayList<>();
        while (clazz != null) {
            fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
            clazz = clazz.getSuperclass();
        }

        // 对象的所有属性
        fieldList.forEach(field -> {
            ReflectionUtils.makeAccessible(field);

            try {
                // 获取属性值
                MetadataValidation annotation = field.getAnnotation(MetadataValidation.class);
                // 没有注解则不做处理
                if (null == annotation) {
                    return;
                }
                // 获取指定对象o上此 Field 表示的字段的值
                Object value = field.get(o);
                checkNotNull(value, annotation);
                checkPattern(value, annotation);
            } catch (IllegalAccessException e) {
                log.error("Validation验证起数据解析失败:{}", e.getMessage());
            }
        });
    }


    /**
     * 非空判断
     *
     * @param value      属性值
     * @param annotation 注解信息
     */
    private static void checkNotNull(Object value, MetadataValidation annotation) {
        log.info("开始非空校验");
        if (annotation != null && ObjectUtils.isEmpty(value)) {
            throw new RuntimeException(annotation.message());
        }
    }

    /**
     * 正则校验
     *
     * @param value      属性值
     * @param annotation 注解信息
     */
    private static void checkPattern(Object value, MetadataValidation annotation) {
        // 存在正则表达式
        if (null != annotation.pattern() && annotation.pattern().length() > 0) {
            Pattern pattern = Pattern.compile(annotation.pattern());
            // 以pattern的规则匹配value的值
            Matcher matcher = pattern.matcher(value.toString());
            // 属性值不符合正则表达式所制定的格式,抛出异常
            if (!matcher.matches()) {
                throw new RuntimeException(annotation.message());
            }
        }
    }


}
  • 在需要调用校验参数的地方可以加上这样一串代码
// 点击发送之前的参数校验
ValidationCheckUtils.check(dto);

好了上面所有的核心代码快已经贴出来了,希望能够帮助到小伙伴们。
其实看到这里的小伙伴们免不了会说上一句使用Spring的 @Valid和@Validated不好嘛,干嘛要自己造轮子呢,多次一举,其实不是这样的这种想法我在编写代码的时候就想到了。但是在我们的业务场景中多个参数接口使用的参数类是同一个,所以使用Spring的@Valid和@Validated自然是不行了。其实换种想法也不是不可以那就是检验参数的再新建一个类,我觉得完全没必要,因为这样很容易就造成类爆炸。不知你是怎么样呢。欢迎评论。

整理不易,欢迎微信搜索【码上遇见你】获取更多精彩内容。

相关实践学习
基于Hologres轻量实时的高性能OLAP分析
本教程基于GitHub Archive公开数据集,通过DataWorks将GitHub中的项⽬、行为等20多种事件类型数据实时采集至Hologres进行分析,同时使用DataV内置模板,快速搭建实时可视化数据大屏,从开发者、项⽬、编程语⾔等多个维度了解GitHub实时数据变化情况。
阿里云实时数仓实战 - 用户行为数仓搭建
课程简介 1)学习搭建一个数据仓库的过程,理解数据在整个数仓架构的从采集、存储、计算、输出、展示的整个业务流程。 2)整个数仓体系完全搭建在阿里云架构上,理解并学会运用各个服务组件,了解各个组件之间如何配合联动。 3&nbsp;)前置知识要求:熟练掌握 SQL 语法熟悉 Linux 命令,对 Hadoop 大数据体系有一定的了解 &nbsp; 课程大纲 第一章&nbsp;了解数据仓库概念 初步了解数据仓库是干什么的 第二章&nbsp;按照企业开发的标准去搭建一个数据仓库 数据仓库的需求是什么 架构 怎么选型怎么购买服务器 第三章&nbsp;数据生成模块 用户形成数据的一个准备 按照企业的标准,准备了十一张用户行为表 方便使用 第四章&nbsp;采集模块的搭建 购买阿里云服务器 安装 JDK 安装 Flume 第五章&nbsp;用户行为数据仓库 严格按照企业的标准开发 第六章&nbsp;搭建业务数仓理论基础和对表的分类同步 第七章&nbsp;业务数仓的搭建&nbsp; 业务行为数仓效果图&nbsp;&nbsp;
相关文章
|
Shell Linux API
【Shell 命令集合 备份压缩 】Linux 解压缩文件 unzip命令 使用指南
【Shell 命令集合 备份压缩 】Linux 解压缩文件 unzip命令 使用指南
586 0
|
数据可视化 物联网 vr&ar
THREE.JS 实现看房自由(VR 看房)
目前随着元宇宙概念的爆火,THREE技术已经深入到了物联网、VR、游戏、数据可视化等多个平台,今天我们主要基于THREE实现一个三维的VR看房小项目
2403 4
|
消息中间件 JSON 数据格式
查看rabbitmq日志,Rabbitmq Trace日志
查看rabbitmq日志,Rabbitmq Trace日志
1279 2
|
安全 Java 数据安全/隐私保护
解析Spring Security中的权限控制策略
解析Spring Security中的权限控制策略
|
Java
【Java异常】Error:(30, 62) java: 程序包com.sun.org.apache.xerces.internal.impl.dv.util不存在
【Java异常】Error:(30, 62) java: 程序包com.sun.org.apache.xerces.internal.impl.dv.util不存在
1828 0
ThreeJs手动控制动画播放与暂停
这篇文章介绍了如何在Three.js中手动控制动画的播放与暂停,包括设置动画混合器、监听按键事件以调整动画状态和速度的方法。
427 0
ThreeJs手动控制动画播放与暂停
|
分布式计算 自然语言处理 大数据
【大数据】MapReduce JAVA API编程实践及适用场景介绍
【大数据】MapReduce JAVA API编程实践及适用场景介绍
407 1
|
存储 监控 测试技术
如果做好一位需求分析师
如果做好一位需求分析师
360 0
【分享】下拉选项,远程获取数据,根据条件设置颜色,并按颜色排序
有时候需要用下拉选项来只管展示数据的(库存)剩余情况,我拿宜搭下拉选择组件的颜色属性来做展示(大家可以举一反三)
607 1
第10章 经典智能算法——10.2 遗传算法的MATLAB实现(1)
第10章 经典智能算法——10.2 遗传算法的MATLAB实现(1)