Java Web 学习笔记之十七:参数校验工具封装

简介

在Web开发过程中,接口传参往往需要进行参数校验。最普通的方式是手动编码,对接口传参一个一个地进行手动校验,代码臃肿编写费时费力。
Javax.validation包则对参数校验规定了一批通用的API,通过接入实现以及编写一套代码及规定参数的格式范围取值等,就能够摆脱编写臃肿的代码,解放生产力。
本文接下去的内容则介绍一种简单的参数校验工具封装。

使用

引入依赖

新建maven工程,引入必要依赖项,如下:

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.17.Final</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>3.0.1-b09</version>
</dependency>

这里引入的是 javax.validationhibernate-validator 实现。

核心代码

获取 Validator

1
javax.validation.Validator validator = javax.validation.Validation.byProvider(org.hibernate.validator.HibernateValidator.class).configure().failFast(false).buildValidatorFactory().getValidator();

进行参数校验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static <T> ValidateResult<T> validate(T source) {
if (validator == null) {
logger.warn("No validator available!");
return null;
}
Set<ConstraintViolation<Object>> errors = validator.validate(source);
ValidateResult<T> validateResult = new ValidateResult<>();
validateResult.source(source);
if (errors != null && !errors.isEmpty()) {
List<PropertyError> propertyErrors = new ArrayList<>();
for (ConstraintViolation<Object> error : errors) {
propertyErrors.add(new PropertyError()
.property(error.getPropertyPath().toString())
.message(error.getMessage())
.invalidValue(error.getInvalidValue()));
}
validateResult.success(false);
validateResult.propertyErrors(propertyErrors);
} else {
validateResult.success(true);
}
return validateResult;
}

其中,ValidateResult 定义如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class ValidateResult<T> {
/**
* The source object tobe validated.
*/
private T source;
/**
* Validate result, true: success, false: failed.
*/
private Boolean success;
/**
* Detail information if validate failed.
*/
private List<PropertyError> propertyErrors;

public T getSource() {
return source;
}

public ValidateResult source(T source) {
this.source = source;
return this;
}

public Boolean getSuccess() {
return success;
}

public ValidateResult success(Boolean success) {
this.success = success;
return this;
}

public List<PropertyError> getPropertyErrors() {
return propertyErrors;
}

public ValidateResult propertyErrors(List<PropertyError> propertyErrors) {
this.propertyErrors = propertyErrors;
return this;
}
}

其中,PropertyError 定义如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class PropertyError {
/**
* Property where validate failed.
*/
private String property;
/**
* Error message.
*/
private String message;
/**
* Invalid value for this property.
*/
private Object invalidValue;

public String getProperty() {
return property;
}

public PropertyError property(String property) {
this.property = property;
return this;
}

public String getMessage() {
return message;
}

public PropertyError message(String message) {
this.message = message;
return this;
}

public Object getInvalidValue() {
return invalidValue;
}

public PropertyError invalidValue(Object invalidValue) {
this.invalidValue = invalidValue;
return this;
}
}

测试结果

编写测试代码,定义参数类型TestModel并规定参数约束条件,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

@Valid
public class TestModel {
@NotNull(message = "ID is null!")
private String id;

@NotNull(message = "name is null!")
@NotEmpty(message = "name is empty!")
private String name;

@Size(max = 1000, message = "max length is 1000!")
private String description;

@Size(max = 10)
private String color;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public String getColor() {
return color;
}

public void setColor(String color) {
this.color = color;
}
}

其中,@NotNull@NotEmpty@Size 等注解为 javax.validation 定义的参数约束条件。

编写测试代码,创建参数实例并进行校验,打印结果,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
@Test
public void test() {
List<TestModel> testModels = new ArrayList<>();
int type = 0;
for (int i = 0; i < 9; i++) {
TestModel model = new TestModel();
switch (type) {
case 0:
model.setId(UUID.randomUUID().toString().replaceAll("-", ""));
model.setName("name_" + i);
model.setDescription("desc_" + i);
model.setColor("RED");
break;
case 1:
model.setId(UUID.randomUUID().toString().replaceAll("-", ""));
model.setName("");
model.setDescription("desc_" + i);
model.setColor("RED");
break;
case 2:
model.setId(null);
model.setName("name_" + i);
model.setDescription("");
model.setColor("ABCDEFGHIJKLMN");
break;
default:
model.setId(UUID.randomUUID().toString().replaceAll("-", ""));
model.setName("name_" + i);
model.setDescription("desc_" + i);
break;
}
testModels.add(model);
type++;
if (type == 3) {
type = 0;
}
}

List<ValidateResult<TestModel>> results = new ArrayList<>();
testModels.forEach(testModel -> results.add(ValidateUtils.validate(testModel)));


results.forEach(System.out::println);
}

运行结果:

1
2
3
4
5
6
7
8
9
10
11
十月 28, 2019 10:23:41 上午 org.hibernate.validator.internal.util.Version <clinit>
INFO: HV000001: Hibernate Validator 6.0.17.Final
ValidateResult{source=TestModel{id='6ced48a15c9e42e7971b9e9cc65d86db', name='name_0', description='desc_0', color='RED'}, success=true, propertyErrors=null}
ValidateResult{source=TestModel{id='8321e78e3de44916bc8997f17aada9a4', name='', description='desc_1', color='RED'}, success=false, propertyErrors=[PropertyError{property='name', message='name is empty!', invalidValue=}]}
ValidateResult{source=TestModel{id='null', name='name_2', description='', color='ABCDEFGHIJKLMN'}, success=false, propertyErrors=[PropertyError{property='color', message='个数必须在0和10之间', invalidValue=ABCDEFGHIJKLMN}, PropertyError{property='id', message='ID is null!', invalidValue=null}]}
ValidateResult{source=TestModel{id='39088ecb7d8e40ca855121a87fce0dd5', name='name_3', description='desc_3', color='RED'}, success=true, propertyErrors=null}
ValidateResult{source=TestModel{id='c4d0829a30f3481f856dd483eac91448', name='', description='desc_4', color='RED'}, success=false, propertyErrors=[PropertyError{property='name', message='name is empty!', invalidValue=}]}
ValidateResult{source=TestModel{id='null', name='name_5', description='', color='ABCDEFGHIJKLMN'}, success=false, propertyErrors=[PropertyError{property='color', message='个数必须在0和10之间', invalidValue=ABCDEFGHIJKLMN}, PropertyError{property='id', message='ID is null!', invalidValue=null}]}
ValidateResult{source=TestModel{id='b13601c5a4d24905b1b73527217a8852', name='name_6', description='desc_6', color='RED'}, success=true, propertyErrors=null}
ValidateResult{source=TestModel{id='9df4ecd18dcf421a957d956d18f3c28b', name='', description='desc_7', color='RED'}, success=false, propertyErrors=[PropertyError{property='name', message='name is empty!', invalidValue=}]}
ValidateResult{source=TestModel{id='null', name='name_8', description='', color='ABCDEFGHIJKLMN'}, success=false, propertyErrors=[PropertyError{property='color', message='个数必须在0和10之间', invalidValue=ABCDEFGHIJKLMN}, PropertyError{property='id', message='ID is null!', invalidValue=null}]}

代码仓库

https://github.com/johnsonmoon/parameter-validator.git