自定义注解判断参数为空

本文涉及的产品
可视分析地图(DataV-Atlas),3 个项目,100M 存储空间
简介: 使用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自然是不行了。其实换种想法也不是不可以那就是检验参数的再新建一个类,我觉得完全没必要,因为这样很容易就造成类爆炸。不知你是怎么样呢。欢迎评论。

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

相关实践学习
DataV Board用户界面概览
本实验带领用户熟悉DataV Board这款可视化产品的用户界面
阿里云实时数仓实战 - 项目介绍及架构设计
课程简介 1)学习搭建一个数据仓库的过程,理解数据在整个数仓架构的从采集、存储、计算、输出、展示的整个业务流程。 2)整个数仓体系完全搭建在阿里云架构上,理解并学会运用各个服务组件,了解各个组件之间如何配合联动。 3&nbsp;)前置知识要求 &nbsp; 课程大纲 第一章&nbsp;了解数据仓库概念 初步了解数据仓库是干什么的 第二章&nbsp;按照企业开发的标准去搭建一个数据仓库 数据仓库的需求是什么 架构 怎么选型怎么购买服务器 第三章&nbsp;数据生成模块 用户形成数据的一个准备 按照企业的标准,准备了十一张用户行为表 方便使用 第四章&nbsp;采集模块的搭建 购买阿里云服务器 安装 JDK 安装 Flume 第五章&nbsp;用户行为数据仓库 严格按照企业的标准开发 第六章&nbsp;搭建业务数仓理论基础和对表的分类同步 第七章&nbsp;业务数仓的搭建&nbsp; 业务行为数仓效果图&nbsp;&nbsp;
相关文章
|
JSON 小程序 JavaScript
小程序根据返回值是否为空判断标签是否显示
小程序根据返回值是否为空判断标签是否显示
102 0
mybatis-plus 判断参数是否为空并作为查询条件
mybatis-plus 判断参数是否为空并作为查询条件
1624 0
|
SQL Java 数据库连接
mybatis @Select注解中当参数为空则不添加该参数的判断
public interface OrderMapper extends SqlMapper{ @Select("select * from tbl_order where room like #{room} and mydate like #{my...
4658 0
|
2月前
|
前端开发 JavaScript
判断数组为空的方法有哪些?
本文介绍了多种判断数组是否为空的方法,包括使用 `length` 属性、隐式类型转换、`toString()`、`join()`、`every()`、`reduce()`、`filter()`、`some()` 方法以及循环。每种方法都有其适用场景,其中使用 `length` 属性和隐式类型转换最为常见和简单。文章首发于微信公众号“前端徐徐”。
245 2
判断数组为空的方法有哪些?
|
3月前
|
JavaScript
判断一个对象为空对象的方法
判断一个对象为空对象的方法
44 4
|
7月前
|
算法 前端开发 索引
判断对象是否为空
判断对象是否为空
72 0
|
7月前
|
小程序 区块链
血常规常见判断参数
血常规常见判断参数
60 0
|
7月前
非空注解@NonNull与@NotNull使用错误导致传参为空时报NPE
非空注解@NonNull与@NotNull使用错误导致传参为空时报NPE
94 0
|
数据库
你还在使用if来判断是否实体类或者某个属性为空吗?教你使用Assert.notNull()[断言]
你还在使用if来判断是否实体类或者某个属性为空吗?教你使用Assert.notNull()[断言]
325 1
你还在使用if来判断是否实体类或者某个属性为空吗?教你使用Assert.notNull()[断言]

热门文章

最新文章