# yx-validator **Repository Path**: caobinbin_git/yx-validator ## Basic Information - **Project Name**: yx-validator - **Description**: spring boot + maven项目,优雅的实现接口参数校验 - **Primary Language**: Java - **License**: BSD-3-Clause - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 24 - **Created**: 2021-12-04 - **Last Updated**: 2021-12-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # yx-validator 2020-01-16 19:03:05 星期四 开发环境版本 `jdk1.8` `maven3.5.0` `spring boot 2.0.2.RELEASE` # Spring Boot项目如何优雅的实现接口参数校验? 在java后端项目开发过程中,其实有很多大一部分项目,后端都没有做接口参数校验,或者做了参数校验,但是实现方式都是简单的使用if判断;主要原因在于:API的参数校验目前流行的方案较少、现有方案不适用与自己的项目、项目部署在内网要求不高、或者干脆参数校验这种事情丢给前端来实现 ## AOP + 注解 实现方法级的参数校验 hibernate-validator是Hibernate项目中的一个数据校验框架,是Bean Validation 的参考实现,也算是当前比较流行的框架了;在实体类上添加注解;但对于不同的方法,所应用的校验规则也是不一样的,这样子可能就会需要创建多个实体类或者组,甚至于一些接口根本就没实体类参数;所以**hibernate-validator实际应用过程中还是有一定的困难**;
**基于此,我花费了一点业余时间,借鉴了hibernate-validator的思路,实现了一套基于 `注解 + AOP` 的方式实现接口参数校验框架**
**在方法体上使用`@CheckParam`或者`@CheckParams`注解标注需要校验的参数;** 举个栗子: ```java @RestController @RequestMapping("/paramCheck") public class ParamCheckController { @CheckParam(value = Check.NotEmpty, argName = "userName", msg = "你大爷的,这个是必填参数!") @PostMapping("/singleCheckNotEmpty") public Object singleCheckNotNull(String userName) { return 1; } @CheckParam(value = Check.DateTime, argName = "dateTime", msg = "msg可以不写,有默认提示") @PostMapping("/singleCheckDateTime") public Object singleCheckDateTime(String dateTime) { return 1; } @CheckParams({ @CheckParam(value = Check.NotNull, argName = "userId", msg = "你大爷的,这个是必填参数!"), @CheckParam(value = Check.NotEmpty, argName = "userName"), @CheckParam(value = Check.NotEmpty, argName = "dept.deptName", msg = "实体属性判断"), @CheckParam(value = Check.Past, argName = "dept.createTime"), @CheckParam(value = Check.lt, argName = "dept.employees", express = "2") // 对集合的size判断 }) @PostMapping("/entityMultiCheck") public Object entityMultiCheck(Integer userId, String userName, @RequestBody DeptEntity dept) { return 1; } } ``` ## 具体方案实现 ![2020011619130680.png](./pic/2020011619130680.png) - 在方法体上使用`@CheckParam`或者`@CheckParams`注解标注需要校验的参数; - 然后使用AOP切入,获取配置的参数校验规则,同时获取对应的入参值 - 调用CheckUtil工具类,进行判断 - Check参数校验枚举类;目前实现了下列校验方法,后续会继续补充 ```java public enum Check { Null("参数必须为 null", CheckUtil::isNull), NotNull("参数必须不为 null", CheckUtil::isNotNull), Empty("参数的必须为空", CheckUtil::isEmpty), NotEmpty("参数必须非空", CheckUtil::isNotEmpty), True("参数必须为 true", CheckUtil::isTrue), False("参数必须为 false", CheckUtil::isFalse), Date("参数必须是一个日期 yyyy-MM-dd", CheckUtil::isDate), DateTime("参数必须是一个日期时间 yyyy-MM-dd HH:mm:ss", CheckUtil::isDateTime), Past("参数必须是一个过去的日期 ", CheckUtil::isPast), Future("参数必须是一个将来的日期 ", CheckUtil::isFuture), Today("参数必须今天的日期 ", CheckUtil::isToday), Enum("参数必须在枚举中 ", CheckUtil::inEnum), Email("参数必须是Email地址", CheckUtil::isEmail), Range("参数必须在合适的范围内", CheckUtil::inRange), NotIn("参数必须不在指定的范围内 ", CheckUtil::outRange), Length("参数长度必须在指定范围内", CheckUtil::inLength), gt("参数必须大于指定值", CheckUtil::isGreaterThan), lt("参数必须小于指定值", CheckUtil::isLessThan), ge("参数必须大于等于指定值", CheckUtil::isGreaterThanEqual), le("参数必须小于等于指定值", CheckUtil::isLessThanEqual), ne("参数必须不等于指定值", CheckUtil::isNotEqual), Equal("参数必须不等于指定值", CheckUtil::isEqual), Pattern("参数必须符合指定的正则表达式", CheckUtil::isPattern) ; public String msg; public BiFunction fun; Check(String msg, BiFunction fun) { this.msg = msg; this.fun = fun; } } ``` 想深入了解的,可以下载源码细看。 ## 集成文档 - 修改Application,添加 `@SpringBootApplication(scanBasePackages = {"com.yuxue"})` 因为项目中使用了很多注解,需要被扫描到才能生效。 - maven项目添加pom依赖,或者添加jar依赖包即可 ```xml com.yuxue yx-validator 1.0.0 ``` ## 接口参数校验使用demo ```java import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.yuxue.entity.DeptEntity; import com.yuxue.entity.EmployeeEntity; import com.yuxue.validator.annotation.CheckParam; import com.yuxue.validator.annotation.CheckParams; import com.yuxue.validator.enumtype.Check; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; @Api(tags = {"check"}, description = "参数校验") @RestController @RequestMapping("/paramCheck") public class ParamCheckController { @ApiImplicitParam(name = "userId", value = "", dataType = "Integer", paramType="query") @CheckParam(value = Check.NotNull, argName = "userId") @PostMapping("/singleCheckNotNull") public Object singleCheckNotNull(Integer userId) { System.err.println(userId); return 1; } @ApiImplicitParam(name = "userName", value = "", dataType = "String", paramType="query") @CheckParam(value = Check.NotEmpty, argName = "userName", msg = "你大爷的,这个是必填参数!") @PostMapping("/singleCheckNotEmpty") public Object singleCheckNotNull(String userName) { System.err.println(userName); return 1; } @ApiImplicitParam(name = "bl", value = "", dataType = "Boolean", paramType="query") @CheckParam(value = Check.True, argName = "bl") @PostMapping("/singleCheckTrue") public Object singleCheckTrue(Boolean bl) { System.err.println(bl); return 1; } @ApiImplicitParam(name = "date", value = "", dataType = "String", paramType="query") @CheckParam(value = Check.Date, argName = "date") @PostMapping("/singleCheckDate") public Object singleCheckDate(String date) { System.err.println(date); return 1; } @ApiImplicitParam(name = "dateTime", value = "", dataType = "String", paramType="query") @CheckParam(value = Check.DateTime, argName = "dateTime") @PostMapping("/singleCheckDateTime") public Object singleCheckDateTime(String dateTime) { System.err.println(dateTime); return 1; } @ApiImplicitParam(name = "date", value = "", dataType = "String", paramType="query") @CheckParam(value = Check.Past, argName = "date") @PostMapping("/singleCheckPast") public Object singleCheckPast(String date) { System.err.println(date); return 1; } @ApiImplicitParam(name = "dateTime", value = "", dataType = "String", paramType="query") @CheckParam(value = Check.Future, argName = "dateTime", msg = "参数必须是一个将来的日期或者时间,并且满足 yyyy-MM-dd HH:mm:ss格式") @PostMapping("/singleCheckFuture") public Object singleCheckFuture(String dateTime) { System.err.println(dateTime); return 1; } @ApiImplicitParam(name = "date", value = "", dataType = "String", paramType="query") @CheckParam(value = Check.Today, argName = "date") @PostMapping("/singleCheckToday") public Object singleCheckToday(String date) { System.err.println(date); return 1; } @ApiImplicitParam(name = "gender", value = "", dataType = "String", paramType="query") @CheckParam(value = Check.Enum, argName = "gender", express="男,女,太监") @PostMapping("/singleCheckStringEnum") public Object singleCheckStringEnum(String gender) { System.err.println(gender); return 1; } @ApiImplicitParam(name = "gender", value = "", dataType = "Integer", paramType="query") @CheckParam(value = Check.Enum, argName = "gender", express="0,1") @PostMapping("/singleCheckIntegerEnum") public Object singleCheckIntegerEnum(Integer gender) { System.err.println(gender); return 1; } @ApiImplicitParam(name = "password", value = "", dataType = "String", paramType="query") @CheckParam(value = Check.Length, argName = "password", express="6,18", msg="密码length必须在6-18位之间!") @PostMapping("/singleCheckStringLength") public Object singleCheckStringLength(String password) { System.err.println(password); return 1; } @ApiImplicitParam(name = "password", value = "", dataType = "String", paramType="query") @CheckParams({ @CheckParam(value = Check.ge, argName = "password", express = "6"), @CheckParam(value = Check.le, argName = "password", express = "18") }) @PostMapping("/singleCheckStringLength1") public Object singleCheckStringLength1(String password) { System.err.println(password); return 1; } @ApiImplicitParam(name = "age", value = "", dataType = "Integer", paramType="query") @CheckParam(value = Check.Range, argName = "age", express="18,50") @PostMapping("/singleCheckIntegerRange") public Object singleCheckIntegerRange(Integer age) { System.err.println(age); return 1; } @ApiImplicitParam(name = "age", value = "", dataType = "Integer", paramType="query") @CheckParams({ @CheckParam(value = Check.ge, argName = "age", express="18"), @CheckParam(value = Check.le, argName = "age", express="50") }) @PostMapping("/singleCheckIntegerRange1") public Object singleCheckIntegerRange1(Integer age) { System.err.println(age); return 1; } @ApiImplicitParam(name = "age", value = "", dataType = "Integer", paramType="query") @CheckParam(value = Check.NotIn, argName = "age", express="18,50") @PostMapping("/singleCheckIntegerNotIn") public Object singleCheckIntegerNotIn(Integer age) { System.err.println(age); return 1; } @ApiImplicitParam(name = "age", value = "", dataType = "Integer", paramType="query") @CheckParams({ @CheckParam(value = Check.lt, argName = "age", express="18"), @CheckParam(value = Check.gt, argName = "age", express="50") }) @PostMapping("/singleCheckIntegerNotIn1") public Object singleCheckIntegerNotIn1(Integer age) { System.err.println(age); return 1; } @ApiImplicitParam(name = "email", value = "", dataType = "String", paramType="query") @CheckParam(value = Check.Email, argName = "email", msg="你大爷的,输入个邮箱啊!") @PostMapping("/singleCheckEmail") public Object singleCheckEmail(String email) { System.err.println(email); return 1; } @ApiImplicitParam(name = "age", value = "", dataType = "Integer", paramType="query") @CheckParam(value = Check.ge, argName = "age", express="18", msg = "必须大于等于18岁") // gt、lt、le、ne、Equal不再举例; 具体看注释 @PostMapping("/singleCheckIntegerGe") public Object singleCheckIntegerGe(Integer age) { System.err.println(age); return 1; } @ApiImplicitParam(name = "pattern", value = "", dataType = "String", paramType="query") @CheckParam(value = Check.Pattern, argName = "pattern", express="^[\u0021-\u007E]{4,16}$") @PostMapping("/singleCheckPattern") public Object singleCheckPattern(String pattern) { System.err.println(pattern); return 1; } @ApiImplicitParams({ @ApiImplicitParam(name = "userId", dataType = "Integer", paramType="query"), @ApiImplicitParam(name = "userName", dataType = "String", paramType="query") }) @CheckParams({ @CheckParam(value = Check.NotNull, argName = "userId", msg = "你大爷的,这个是必填参数!"), @CheckParam(value = Check.NotNull, argName = "userName") }) @PostMapping("/multiCheckNotNull") public Object multiCheckNotNull(Integer userId, String userName) { System.err.println(userId); System.err.println(userName); return 1; } @ApiImplicitParams({ @ApiImplicitParam(name = "userId", dataType = "Integer", paramType="query"), @ApiImplicitParam(name = "userName", dataType = "String", paramType="query"), @ApiImplicitParam(name = "employee", dataType = "entity", paramType="body") }) @CheckParams({ @CheckParam(value = Check.NotNull, argName = "userId", msg = "你大爷的,这个是必填参数!"), @CheckParam(value = Check.NotEmpty, argName = "userName"), @CheckParam(value = Check.NotEmpty, argName = "employee.name") }) @PostMapping("/entityCheckNotNull") public Object entityCheckNotNull(Integer userId, String userName, @RequestBody EmployeeEntity employee) { System.err.println(userId); System.err.println(userName); System.err.println(employee.getName()); return 1; } @ApiImplicitParams({ @ApiImplicitParam(name = "userId", dataType = "Integer", paramType="query"), @ApiImplicitParam(name = "userName", dataType = "String", paramType="query"), @ApiImplicitParam(name = "dept", dataType = "entity", paramType="body") }) @CheckParams({ @CheckParam(value = Check.NotNull, argName = "userId", msg = "你大爷的,这个是必填参数!"), @CheckParam(value = Check.NotEmpty, argName = "userName"), @CheckParam(value = Check.NotEmpty, argName = "dept.deptName"), @CheckParam(value = Check.Past, argName = "dept.createTime"), @CheckParam(value = Check.lt, argName = "dept.employees", express = "2") // 对集合的size判断 }) @PostMapping("/entityMultiCheck") public Object entityMultiCheck(Integer userId, String userName, @RequestBody DeptEntity dept) { System.err.println(userId); System.err.println(userName); System.err.println(dept.getDeptName()); return 1; } } ``` ## CSDN博客地址 https://blog.csdn.net/weixin_42686388 https://blog.csdn.net/weixin_42686388/article/details/104009771 ## 联系我 https://gitee.com/admin_yu yuxue1687@qq.com