问题场景:
项目前后端对接时,前端调用服务端接口进行入参校验时,服务器和浏览器需要进行双向校验。在统一传参对象时,需要对一些入参字段进行判空,判长度,格式校验
第一种方案可以直接在对象实体的字段上使用相应注解
相关的校验API:
空检查
@NotEmpty:用在集合类上面;不能为null,而且长度必须大于0
@NotBlank: 用在String上面;只能作用在String上,不能为null,而且调用trim()后,长度必须大于0
@NotNull:用在基本类型上;不能为null,但可以为empty。
长度检查
@Size(min=,max=):验证对象(Array,Collection,Map,String)长度是否在给定的范围之内
不要错用了异常类型,比如在int上不可用@size
@Length(min=, max=) : 只适用于String 类型
Booelan检查
@AssertTrue: 验证 Boolean 对象是否为 true
@AssertFalse: 验证 Boolean 对象是否为 false
日期检查
@Past: 验证 Date 和 Calendar 对象是否在当前时间之前
@Future: 验证 Date 和 Calendar 对象是否在当前时间之后
@Pattern: 验证 String 对象是否符合正则表达式的规则
其他验证:
@Vaild 递归验证,用于对象、数组和集合,会对对象的元素、数组的元素进行一一校验
@Email 用于验证一个字符串是否是一个合法的右键地址,空字符串或null算验证通过
@URL(protocol=,host=,port=,regexp=,flags=) 用于校验一个字符串是否是合法URL
第二种方案,如果入参比较少,也可直接取参数进行if else 判断,并对异常参数进行return 异常提示,这种直白的方式,在多代码编写时,费事费力,不推荐
第三种方案,也是比较建议的方式,在服务端接口传参处使用BindingResult
BindingResult是Spring框架中的一个核心接口,用于处理数据校验的结果,确保数据的合法性,BindingResult需要配合校验器Validator一起使用,在传入的对象前使用@Valid
public GraceJSONResult saveOrUpdate(@Valid SaveBO saveBO,BindingResult result) {
// 判断BindingResult是否保存错误的验证信息,如果有,则直接return
if (result.hasErrors()) {
Map<String, String> errorMap = getErrors(result);
return GraceJSONResult.errorMap(errorMap);
}
}
如果入参没有按要求传,就可以统一返回异常,如下
方案优化:
使用BindingResult可以极大省去前后端参数的校验,但像上面每个对接的服务端接口都要判断BindingResult里是否存在错误验证信息并返回,代码还是太冗余,所以进行进一步封装,将该机制放到整个服务端的统一异常拦截器里。
Spring提供了一个方法参数校验的异常类MethodArgumentNotValidException ,它会在所有接口接收前先进行拦截校验,如下
/**
* 统一异常拦截处理
* 可以针对异常的类型进行捕获,然后返回json信息到前端
*/
@ControllerAdvice
public class GraceExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public GraceJSONResult returnException(MethodArgumentNotValidException e) {
BindingResult result = e.getBindingResult();
Map<String, String> errors = getErrors(result);
return GraceJSONResult.errorMap(errors);
}
public Map<String, String> getErrors(BindingResult result) {
Map<String, String> map = new HashMap<>();
List<FieldError> errorList = result.getFieldErrors();
for (FieldError fieldError : errorList) {
String field = fieldError.getField();
String defaultMessage = fieldError.getDefaultMessage();
map.put(field, defaultMessage);
}
return map;
}
}
使用统一的异常拦截后,服务端的接口参数校验就不需要每个接口都配置,依然可以实现验证效果,主打一个实现功能的前提下,能少写代码就少写,能不写就不写。
end