解决Spring项目中后端表单数据验证功能
JSR303
采用JSR303库中提供的效验注解

流程
在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 { @Pattern(regexp = "/[a-zA-Z]$", message = "检索首字母必须是一个字母") private String firstLetter; }
|
隐藏问题
单个注解下,在不添加非空校验时,只有提交才会进行校验
所以若要保证字段安全校验,必须配合使用非空校验
1 2 3 4
| @NotBlank(message = "检索首字母不能为空") @Pattern(regexp = "/[a-zA-Z]$", message = "检索首字母必须是一个字母")
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(); }
|