1 Star 0 Fork 23

郭贤龙 / yx-validator

forked from yuxue / yx-validator 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
BSD-3-Clause

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

BSD 3-Clause License Copyright (c) 2020, yuxue All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

简介

spring boot + maven项目,优雅的实现接口参数校验 展开 收起
Java
BSD-3-Clause
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
Java
1
https://gitee.com/guoxianlong/yx-validator.git
git@gitee.com:guoxianlong/yx-validator.git
guoxianlong
yx-validator
yx-validator
master

搜索帮助