本文介绍基于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依赖之外,需要的第三方依赖,不是核心的依赖,可以根据个人习惯取舍:

<!-- 用于字符串校验 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.3.2</version>
</dependency>
<!-- 用于日志打印 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>

自定义注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 参数校验 注解
*/
@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()) ? "" : " 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 ? 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<Object, String, Boolean> fun;
Operator(String value, BiFunction<Object, String, Boolean> fun) {
this.value = value;
this.fun = fun;
}
}

TODO

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

以上实践只做参考,可能会有一定的局限性,欢迎留言说出更好的见解!

SpringBoot实现通用的接口参数校验的更多相关文章

  1. Spring Boot实现通用的接口参数校验

    Spring Boot实现通用的接口参数校验 Harries Blog™ 2018-05-10 2418 阅读 http ACE Spring App API https AOP apache IDE ...

  2. Spring Boot 之:接口参数校验

    Spring Boot 之:接口参数校验,学习资料 网址 SpringBoot(八) JSR-303 数据验证(写的比较好) https://qq343509740.gitee.io/2018/07/ ...

  3. springboot 接口参数校验

    前言 在开发接口的时候,参数校验是必不可少的.参数的类型,长度等规则,在开发初期都应该由产品经理或者技术负责人等来约定.如果不对入参做校验,很有可能会因为一些不合法的参数而导致系统出现异常. 上一篇文 ...

  4. 【快学springboot】4.接口参数校验

    前言 在开发接口的时候,参数校验是必不可少的.参数的类型,长度等规则,在开发初期都应该由产品经理或者技术负责人等来约定.如果不对入参做校验,很有可能会因为一些不合法的参数而导致系统出现异常. 上一篇文 ...

  5. SpringBoot Validation优雅的全局参数校验

    前言 我们都知道在平时写controller时候,都需要对请求参数进行后端校验,一般我们可能会这样写 public String add(UserVO userVO) { if(userVO.getA ...

  6. 接口参数校验之@Valid与BindingResult

    接口方法往往需要对入参做一些校验,从而判断入参是否合格,而javax.validation包为我们提供了一些常用的参数校验注解,使用起来很方便. 下面这个示例是检验入参对象中的password是否为空 ...

  7. 接口参数校验(不使用hibernate-validator,规避大量if else)

    引言 编写接口时,常用的参数校验使用hibernate-validator注解+@@Validated注解进行参数校验.当遇到一些特殊场景或需求,需要自己对参数进行手动校验时,会出现以下问题: 不可避 ...

  8. springboot @valid与@validated的参数校验使用总结

    好久没在这平台写博客了,最近整理了这东西,先给出总结 // @Valid只能用在controller,@Validated可以用在其他被spring管理的类上 // @Valid可以加在成员变量上(本 ...

  9. springboot 参数校验详解

    https://www.jianshu.com/p/89a675b7c900 在日常开发写rest接口时,接口参数校验这一部分是必须的,但是如果全部用代码去做,显得十分麻烦,spring也提供了这部分 ...

随机推荐

  1. 联想R720Y空间问题

    由于之前Y空间在启动项中,所以将他关闭,这次想找到他却找不到 备注:因为在解决问题前,没有把图片保存下来,所以下面用一个颜色框挡住,表示之前的效果 第一个问题 在电脑上找到Y空间 百度上很多说在开始中 ...

  2. Cannot load driver class: com.mysql.jdbc.Driver

    mysql-connector-java提供了mysql驱动等类库,此处必须引入此依赖,否则将会提示: Cannot load driver class: com.mysql.jdbc.Driver等 ...

  3. git中一些常见问题的解决

    1. 解决: 先pull,执行git pull origin 分支名称:然后再执行 git push origin 分支名称 2.git报remote HTTP Basic Access denied ...

  4. chemfig化学式转换为pdf

    SMILES 与 chemfig 针对化学分子结构,可以用SMILES (用ASCII字符串明确描述分子结构的规范)来定义. SMILES(Simplified molecular input lin ...

  5. centos7安装es6.4.0

    一.首先进入到opt文件夹cd opt二.然后下载es安装包wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearc ...

  6. Pytorch_Part3_模型模块

    VisualPytorch beta发布了! 功能概述:通过可视化拖拽网络层方式搭建模型,可选择不同数据集.损失函数.优化器生成可运行pytorch代码 扩展功能:1. 模型搭建支持模块的嵌套:2. ...

  7. 克鲁斯卡尔(Kruskal)算法(代码)

    算法代码 C#代码 using System; using System.Linq; namespace Kruskal { class Program { static void Main(stri ...

  8. CSS层叠性

    比较id,类,标签的数量 谁多就谁在上面 255个类的权重等于一个id 当权重一样时,以后设置的为准 通过继承而来的,权重为0 !important (设置权重无限大)可以影响权重,但只能影响选中的, ...

  9. 10.Debug

    1.Debug模式 1.1 什么是Debug模式 是供程序员使用的程序调试工具,它可以用于查看程序的执行流程,也可以用于追踪程序执行过程来调试程序. 1.2 Debug介绍与操作流程 Debug调式, ...

  10. kubernetes 监控(14)

    一.Weave Scope 容器地图 创建 Kubernetes 集群并部署容器化应用只是第一步.一旦集群运行起来,我们需要确保一切正常,所有必要组件就位并各司其职,有足够的资源满足应用的需求.Kub ...