# smart-validate
**Repository Path**: lichaoever/smart-validate
## Basic Information
- **Project Name**: smart-validate
- **Description**: 这是一个服务端参数验证框架,可以对JavaBean中的属性以及方法中参数列表进行验证
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 1
- **Created**: 2021-05-11
- **Last Updated**: 2021-12-24
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 一个非常实用的Java参数验证框架
# 
# 简介
在日常开发中,不论是在REST API还是RPC接口在代码上都会做参数校验,用来验证输入参数的合法性,举个最简单的例子:
(一)验证Spring MVC接口入参
```java
@RequestMapping(value = "helloworld")
@ResponseBody
public Object helloworld(String str) throws Exception {
if(str == null || str.trim().length() == 0) {
throw new IllegalArgumentException("str is required");
}
}
```
> Spring MVC 中也可以使用 @RequestParam(required = true) 注解来约束str参数为必填项,但这个框架层会做拦截,被拦截后的效果一般不是预期想要的
(二)验证RPC接口中的入参
```java
class Request {
String id;
String name;
getter ……
setter ……
}
public Response helloworld(Request request) {
if(StringUtils.isEmpty(request.getId()) || StringUtils.isEmpty(request.getName())) {
throw new IllegalArgumentException("id or name is required");
}
}
```
一个非空判断需要写一行代码、如果需要验证的参数很多或者还需要判断参数长度、取值范围、集合大小等,又或者参数是一个对象,**对象里面循环嵌套了对象**,每个对象中又有很多字段需要验证参数的合法性等等,这个时候如果仍然使用hard code来实现的话,实现、维护成本就太高了,而且代码的可读性也是非常糟糕的,因此给大家分享下Smart-Validate验证框架,用来解决以上的问题。
Smart-Validate,一个非常实用的Java参数验证框架,具有以下特点:
> - 足够轻,整个代码量不足500行
> - 基于注解声明规则,使用成本低
> - 内置常见的验证规则
> - 支持嵌套对象的验证
> - 可自由拓展验证规则
框架内置以下规则列表
| **规则注解** | **说明** | **支持的数据类型** |
| --- | --- | --- |
| MaxLengthValidate | 验证最大长度 | String、Collection、Map、Array |
| MaxValueValidate | 验证最大值 | Integer、Long、Byte、Short、Double、Float |
| MinLengthValidate | 验证最小长度 | String、Collection、Map、Array |
| MinValueValidate | 验证最小值 | Integer、Long、Byte、Short、Double、Float |
| NotNullValidate | 验证非空 | Object、String |
| RangeLengthValidate | 验证长度范围 | String、Collection、Map、Array |
| RangeValueValidate | 验证值范围 | Integer、Long、Byte、Short、Double、Float |
| RegexpValidate | 验证正则规则 | String |
# 使用方法
## 验证对象参数
```java
@ValidateBean
public class Request {
//ID不能为空
@NotNullValidate
private String id;
//name最小长度为5
@MinLengthValidate(length = 5)
private String name;
public Request() {}
getter ……
setter ……
}
public void helloworld(Request request) throws SmartValidateException {
SmartValidate.validate(request);
//code
}
public static void main(String[] args) {
try {
Request req = new Request();
req.setId(null);
req.setName("haha");
new Demo().helloworld(req);
} catch (SmartValidateException e) {
System.err.println(e.getMessage());
}
}
```
```
LOG Print: id为必填项
```
```java
public static void main(String[] args) {
try {
Request req = new Request();
req.setId("1");
req.setName("haha");
new Demo().helloworld(req);
} catch (SmartValidateException e) {
System.err.println(e.getMessage());
}
}
```
```
LOG Print: name的长度不能小于5
```
## 验证嵌套对象参数
```java
@ValidateBean
public class Request {
@NotNullValidate
private InnerRquest param;
getter ……
setter ……
}
@ValidateBean
public class InnerRquest {
@NotNullValidate
private String id;
@MaxValueValidate(value = "99")
private Integer age;
public InnerRquest() {}
getter ……
setter ……
}
public void helloworld(Request request) throws SmartValidateException {
SmartValidate.validate(request);
//code
}
public static void main(String[] args) {
try {
Request req = new Request();
InnerRquest ireq = new InnerRquest();
ireq.setId("1");
ireq.setAge(100);
req.setParam(ireq);
new Demo().helloworld(req);
} catch (SmartValidateException e) {
System.err.println(e.getMessage());
}
}
```
```
LOG Print: age的值不能大于99
```
## 验证集合中的对象
```java
@ValidateBean
public class Request {
@NotNullValidate
private List param;
getter ……
setter ……
}
public void helloworld(Request request) throws SmartValidateException {
SmartValidate.validate(request);
//code
}
public static void main(String[] args) {
try {
Request req = new Request();
InnerRquest ireq = new InnerRquest();
ireq.setId("1");
ireq.setAge(100);
req.setParam(Arrays.asList(ireq));
new Demo().helloworld(req);
} catch (SmartValidateException e) {
System.err.println(e.getMessage());
}
}
```
```
LOG Print: age的值不能大于99
```
## 验证方法中的参数列表
```java
public void helloworld(
@ValidateArgument(
notNull=@NotNullValidate,
maxLength=@MaxLengthValidate(length=1)
)String str) throws Exception {
//code
}
```
配置拦截器
```xml
```
## 拓展自定义验证规则
(一)定义规则注解
```java
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomerValidate {
String message () default "";
String name () default "";
}
```
(二)实现规则
```java
public class MatchCustomerValidate extends AbstractMatchValidate{
@Override
public void validate(CustomerValidate t,
String fieldName,
Object value)
throws SmartValidateException {
//your code
}
}
```
(三)生效规则
```java
ValidateRulePool.mount(CustomerValidate.class, new MatchCustomerValidate());
```
(四)使用 @CustomerValidate 注解来验证参数
## 使用多个验证规则
不论是参数列表还是对象中的字段,都可以同时支持多个验证规则。
(一)对象参数
```java
@NotNullValidate
@RangeValueValidate(min = "1", max = "100")
private Integer age;
```
(二)方法参数
```java
public void helloworld(
@ValidateArgument(
notNull=@NotNullValidate,
rangeValue=@RangeValueValidate(min = "1", max = "100")
)Integer age) throws Exception {}
```
## 自定义提示消息
内置的验证规则均支持自定义message,以NotNullValidate为例,在注解中声明可以声明name或message属性,例如:
### 自定义name属性
```java
//name=“年龄”,在验证不通过时message为 “年龄为必填项”
@NotNullValidate(name = "年龄")
private Integer age;
```
### 自定义message属性
```java
//message=“请输入年龄”,在验证不通过时message为 “请输入年龄”
@NotNullValidate(message = "请输入年龄")
private Integer age;
```
如果name和message都未定义,则message为默认值 “age为必填项”
# 最佳实践
不论是Spring MVC的REST API参数,还是RPC中的对象入参,一般都会有相应的拦截器去处理日志打印、异常等相关的逻辑,因此参数验证也可以在这一层中使用SmartValidate.validate方法来统一接入,框架中也内置了基于Spring的SmartValidateInterceptor拦截器,也可以自己跟实际情况来实现自己的验证策略。
# 源码
[https://github.com/lichao4Java/smart-validate](https://github.com/lichao4Java/smart-validate)