0%

spring项目中的后端表单验证

解决Spring项目中后端表单数据验证功能

JSR303

采用JSR303库中提供的效验注解

image-20220125232949284

流程

在bean的字段添加对应的校验注解(@Valid)

1
2
3
4
5
6
7
@RequestMapping("/save")
public R save(
@Valid // 添加注解确定该对象需要校验
@RequestBody BrandEntity brand){
brandService.save(brand);
return R.ok();
}

返回数据

当再次进行非法请求时就会返回如下

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
{
"timestamp": "2022-01-25T15:36:50.377+0000",
"status": 400,
"error": "Bad Request",
"errors": [
{
"codes": [
"NotBlank.brandEntity.name",
"NotBlank.name",
"NotBlank.java.lang.String",
"NotBlank"
],
"arguments": [
{
"codes": [
"brandEntity.name",
"name"
],
"arguments": null,
"defaultMessage": "name",
"code": "name"
}
],
"defaultMessage": "不能为空",
"objectName": "brandEntity",
"field": "name",
"rejectedValue": "",
"bindingFailure": false,
"code": "NotBlank"
}
],
"message": "Validation failed for object='brandEntity'. Error count: 1",
"path": "/product/brand/save"
}

自定义响应

jsr默认响应不符合业务规范,将接口改为以下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@RequestMapping("/save")
public R save(
@Valid // 添加注解确定该对象需要校验
@RequestBody BrandEntity brand,
BindingResult result // 紧跟校验对象
){
// 校验时是否出错
if(result.hasErrors()){
Map<String, String> errMap = new HashMap<>();
// 获取全部校验错误,取出放入返回值内进行响应
result.getFieldErrors().forEach(error->{
String field = error.getField();
String message = error.getDefaultMessage();
errMap.put(field,message);
});
return R.error(400,"非法参数请求").put("data",errMap);
}
brandService.save(brand);
return R.ok();
}

其中BindingResult必须紧跟需要校验的对象

此时非法请求响应如下:

1
2
3
4
5
6
7
{
"msg": "非法参数请求",
"code": 400,
"data": {
"name": "品牌名不能为空"
}
}

自定义正则校验

在需要正则效验的字段上使用**@Pattern**注解

1
2
3
4
5
public class BrandEntity implements Serializable {
// other field.....
@Pattern(regexp = "/[a-zA-Z]$", message = "检索首字母必须是一个字母")
private String firstLetter;
}

隐藏问题

单个注解下,在不添加非空校验时,只有提交才会进行校验

所以若要保证字段安全校验,必须配合使用非空校验

1
2
3
4
@NotBlank(message = "检索首字母不能为空")
@Pattern(regexp = "/[a-zA-Z]$", message = "检索首字母必须是一个字母")
// other...
private String firstLetter;

分组校验

应对不同业务下的校验规则

比如当新增时,需要输入全部数据,但是当修改时,只需要提交对应修改后的字段

此时就需要进行分组校验

流程

修改注解

采用 JSR303 注解的的 groups 属性进行分组校验,

groups要求传入Class对象,

如下,其中AddGroup和UpdateGroup为空接口即可;

1
2
3
@NotBlank(message = "品牌名不能为空",groups = {AddGroup.class,UpdateGroup.class})
private String name;

1
2
3
4
public interface AddGroup {
}
public interface UpdateGroup {
}

不同group表示在不同情况下需要校验

注意:当使用group校验后,其他未添加分组的校验将会失效;为保证所有校验正常运行,确保其添加正确分组;

不同注解和分组可以组合使用,如下

1
2
3
@NotBlank(groups = {AddGroup.class})
@Pattern(regexp = "/[a-zA-Z]$", message = "检索首字母必须是一个字母",groups = {AddGroup.class,UpdateGroup.class})
private String firstLetter;

当在AddGroup新增模式下时同时触发@NotBlank和@Pattern校验,但在UpdateGroup更新模式下时只会触发@Pattern校验

修改controller

将此前的 @Valid 注解修改为 @Validated 注解,并填入触发的校验组 AddGroup

1
2
3
4
5
6
7
8
@RequestMapping("/save")
public R save(
@Validated(AddGroup.class)
@RequestBody BrandEntity brand
){
brandService.save(brand);
return R.ok();
}
Donate comment here.