8 Star 48 Fork 23

yuxue / yx-validator

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
README.md 13.94 KB
一键复制 编辑 原始数据 按行查看 历史
yuxue 提交于 2020-01-19 10:09 . no commit message

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注解标注需要校验的参数; 举个栗子:

@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

  • 在方法体上使用@CheckParam或者@CheckParams注解标注需要校验的参数;

  • 然后使用AOP切入,获取配置的参数校验规则,同时获取对应的入参值

  • 调用CheckUtil工具类,进行判断

  • Check参数校验枚举类;目前实现了下列校验方法,后续会继续补充

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<Object, String, Boolean> fun;

	Check(String msg, BiFunction<Object, String, Boolean> fun) {
		this.msg = msg;
		this.fun = fun;
	}
}

想深入了解的,可以下载源码细看。

集成文档

  • 修改Application,添加 @SpringBootApplication(scanBasePackages = {"com.yuxue"}) 因为项目中使用了很多注解,需要被扫描到才能生效。

  • maven项目添加pom依赖,或者添加jar依赖包即可

<dependency>
	<groupId>com.yuxue</groupId>
	<artifactId>yx-validator</artifactId>
	<version>1.0.0</version>
</dependency>

接口参数校验使用demo

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

Java
1
https://gitee.com/admin_yu/yx-validator.git
git@gitee.com:admin_yu/yx-validator.git
admin_yu
yx-validator
yx-validator
master

搜索帮助