热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

SpringBoot实现通用的接口参数校验

本文介绍基于 Spring Boot 和 JDK8 编写一个 AOP ,结合自定义注解实现通用的接口参数校验。 缘由 目前参数校验常用的

本文介绍基于 Spring Boot 和 JDK8 编写一个 AOP ,结合自定义注解实现通用的接口参数校验。

缘由

目前参数校验常用的方法是在实体类上添加注解,但对于不同的方法,所应用的校验规则也是不一样的,例如有一个 AccountVO 实体:

public class AccountVO {
  private String name; // 姓名
  private Integer age; // 年龄
}

假设存在这样一个业务:用户注册时需要填写姓名和年龄,用户登陆时只需要填写姓名就可以了。那么把校验规则加在实体类上显然就不合适了。

所以一直想实现一种方法级别的参数校验,对于同一个实体参数,不同的方法可以应用不同的校验规则,由此便诞生了这个工具,而且在日常工作中使用了很久。

介绍

先来看看使用的方式:

@Service
public class TestImpl implements ITestService {

  @Override
  @Check({"name", "age"})
  public void testValid(AccountVO vo) {
    // ...
  }

}

其中方法上的 @Check 注解指明了参数 AccountVO 中的 name 、 age 属性不能为空。除了非空校验外,还支持大小判断、是否等于等校验:

@Check({"id>=8", "name!=aaa", "title<10"})

默认的错误信息会返回字段,错误原因和调用的方法,例如:

updateUserId must not null while calling testValid
id must >= 8 while calling testValid
name must != aaa while calling testValid

也支持自定义错误返回信息:

@Check({"title<=8:标题字数不超过8个字,含标点符号"})
public void testValid(TestPO po) {
  // ...
}

只需要在校验规则后加上 : ,后面写上自定义信息,就会替换默认的错误信息。

PS: 核心原理是通过反射获取参数实体中的字段的值,然后根据规则进行校验, 所以目前只支持含有一个参数的方法,并且参数不能是基础类型。

使用

spring-boot 中如何使用 AOP 这里不再赘述,主要介绍 AOP 中的核心代码。

Maven 依赖

除了 spring-boot 依赖之外,需要的第三方依赖,不是核心的依赖,可以根据个人习惯取舍:



  org.apache.commons
  commons-lang3
  3.3.2




  org.slf4j
  slf4j-api
  1.7.25


自定义注解

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

import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * 参数校验 注解
 * Created by cipher on 2017/9/20.
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RUNTIME)
public @interface Check {

  // 字段校验规则,格式:字段名+校验规则+冒号+错误信息,例如:id<10:ID必须少于10
  String[] value();

}

核心代码

通过切面拦截加上了 @Check 注解的接口方法,在方法执行前,执行参数校验,如果存在错误信息,则直接返回:

@Around(value = "@com.cipher.checker.Check") // 这里要换成自定义注解的路径
public Object check(ProceedingJoinPoint point) throws Throwable {
  Object obj;
  // 参数校验
  String msg = doCheck(point);
  if (!StringUtils.isEmpty(msg)) {
    // 这里可以返回自己封装的返回类
    throw new IllegalArgumentException(msg);
  }
  obj = point.proceed();
  return obj;
}

核心的校验方法在 doCheck 方法中,主要原理是获取注解上指定的字段名称和校验规则,通过反射获取参数实体中对应的字段的值,再进行校验:

/**
 * 参数校验
 *
 * @param point ProceedingJoinPoint
 * @return 错误信息
 */
private String doCheck(ProceedingJoinPoint point) {
  // 获取方法参数值
  Object[] arguments = point.getArgs();
  // 获取方法
  Method method = getMethod(point);
  String methodInfo = StringUtils.isEmpty(method.getName()) &#63; "" : " while calling " + method.getName();
  String msg = "";
  if (isCheck(method, arguments)) {
    Check annotation = method.getAnnotation(Check.class);
    String[] fields = annotation.value();
    Object vo = arguments[0];
    if (vo == null) {
      msg = "param can not be null";
    } else {
      for (String field : fields) {
        // 解析字段
        FieldInfo info = resolveField(field, methodInfo);
        // 获取字段的值
        Object value = ReflectionUtil.invokeGetter(vo, info.field);
        // 执行校验规则
        Boolean isValid = info.optEnum.fun.apply(value, info.operatorNum);
        msg = isValid &#63; msg : info.innerMsg;
      }
    }
  }
  return msg;
}

可以看到主要的逻辑是:

解析字段 -> 获取字段的值 -> 执行校验规则

内部维护一个枚举类,相关的校验操作都在里面指定:

/**
 * 操作枚举
 */
enum Operator {
  /**
   * 大于
   */
  GREATER_THAN(">", CheckParamAspect::isGreaterThan),
  /**
   * 大于等于
   */
  GREATER_THAN_EQUAL(">=", CheckParamAspect::isGreaterThanEqual),
  /**
   * 小于
   */
  LESS_THAN("<", CheckParamAspect::isLessThan),
  /**
   * 小于等于
   */
  LESS_THAN_EQUAL("<=", CheckParamAspect::isLessThanEqual),
  /**
   * 不等于
   */
  NOT_EQUAL("!=", CheckParamAspect::isNotEqual),
  /**
   * 不为空
   */
  NOT_NULL("not null", CheckParamAspect::isNotNull);

  private String value;
  private BiFunction fun;

  Operator(String value, BiFunction fun) {
    this.value = value;
    this.fun = fun;
  }
}

由于篇幅原因,这里就不一一展开所有的代码,有兴趣的朋友可以到以下地址获取所有的源码: ciphermagic/java-learn/sandbox/checker

TODO

  1. 以Spring Boot Starter的方式封装成独立组件
  2.  支持正则表达式验证

最后

感谢大家的阅读,喜欢的朋友可以在github上点个赞,有任何问题或者建议请在下方留言,期待你的回复。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 20211101CleverTap参与度和分析工具功能平台学习/实践
    1.应用场景主要用于学习CleverTap的使用,该平台主要用于客户保留与参与平台.为客户提供价值.这里接触到的原因,是目前公司用到该平台的服务~2.学习操作 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 安卓select模态框样式改变_微软Office风格的多端(Web、安卓、iOS)组件库——Fabric UI...
    介绍FabricUI是微软开源的一套Office风格的多端组件库,共有三套针对性的组件,分别适用于web、android以及iOS,Fab ... [详细]
  • 使用在线工具jsonschema2pojo根据json生成java对象
    本文介绍了使用在线工具jsonschema2pojo根据json生成java对象的方法。通过该工具,用户只需将json字符串复制到输入框中,即可自动将其转换成java对象。该工具还能解析列表式的json数据,并将嵌套在内层的对象也解析出来。本文以请求github的api为例,展示了使用该工具的步骤和效果。 ... [详细]
  • 关于我们EMQ是一家全球领先的开源物联网基础设施软件供应商,服务新产业周期的IoT&5G、边缘计算与云计算市场,交付全球领先的开源物联网消息服务器和流处理数据 ... [详细]
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
  • 解决Cydia数据库错误:could not open file /var/lib/dpkg/status 的方法
    本文介绍了解决iOS系统中Cydia数据库错误的方法。通过使用苹果电脑上的Impactor工具和NewTerm软件,以及ifunbox工具和终端命令,可以解决该问题。具体步骤包括下载所需工具、连接手机到电脑、安装NewTerm、下载ifunbox并注册Dropbox账号、下载并解压lib.zip文件、将lib文件夹拖入Books文件夹中,并将lib文件夹拷贝到/var/目录下。以上方法适用于已经越狱且出现Cydia数据库错误的iPhone手机。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • 本文介绍了在git中如何对指定的commit id打标签,并解决了忘记打标签的问题。通过查找历史提交的commit id,可以在任意时间点打上标签。同时,还介绍了git中的一些常用命令和操作。 ... [详细]
  • 【MicroServices】【Arduino】装修甲醛检测,ArduinoDart甲醛、PM2.5、温湿度、光照传感器等,数据记录于SD卡,Python数据显示,UI5前台,微服务后台……
    这篇文章介绍了一个基于Arduino的装修甲醛检测项目,使用了ArduinoDart甲醛、PM2.5、温湿度、光照传感器等硬件,并将数据记录于SD卡,使用Python进行数据显示,使用UI5进行前台设计,使用微服务进行后台开发。该项目还在不断更新中,有兴趣的可以关注作者的博客和GitHub。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
author-avatar
315热点关注
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有