目录
前言
导包
测试
自定义
优化
参数校验在日常开发时是很常用的操作。为了避免null指针、非法数据存入数据库,我们通常要进行参数校验。我们来看一个参数校验的例子:
@PostMapping("/save")
public Object save(@RequestBody UserVO userVO) {
String mobile = userVO.getMobile();
//手动逐个 参数校验~ 写法
if (StringUtils.isBlank(mobile)) {
return R.bulid(ResultEnum.PARAM_FAIL_CODE,"mobile:手机号码不能为空");
} else if (!Pattern.matches("^[1][3,4,5,6,7,8,9][0-9]{9}$", mobile)) {
return R.bulid(ResultEnum.PARAM_FAIL_CODE,"mobile:手机号码格式不对");
}
//抛出自定义异常等~写法
if (StringUtils.isBlank(userVO.getUsername())) {
throw new ParamException(ResultEnum.PARAM_FAIL_CODE, "用户名不能为空");
}
// 比如写一个map返回
if (StringUtils.isBlank(userVO.getSex())) {
Map result = new HashMap<>(5);
result.put("code", Constant.PARAM_FAIL_CODE);
result.put("msg", "性别不能为空");
return result;
}
//.........各种写法 ...
userService.save(userVO);
return R.success();
}
都0202年了,还这么写参数校验?
validation相信大家都听说过,Spring又怎么会放过这个好东西。传统的validation用起来还挺费劲,但是Springboot他来了~轻松几步搞定参数校验。
先上步骤
只需要spring-boot-starter-validation和web即可
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.1.13.RELEASE
com.example
validation-demo
0.0.1-SNAPSHOT
validation-demo
Demo project for Spring Boot
1.8
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-validation
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-maven-plugin
写测试DTO
public class TestDTO {
@NotNull(message = "姓名不能为空")
private String name;
@NotNull(message = "年龄不能为空")
@Max(value = 120, message = "最大值不能大于120")
@Min(value = 0, message = "最小值不能低于0")
private Integer age;
//get set省略
}
这里给你们一份说明
@RestController
@RequestMapping("/test")
public class TestController {
/**
* 测试
* `@Valid` 表示对这个对象校验
* `BindingResult` 获取的是校验的结果,这个对象有许多方法获取校验信息,可以自定义返回信息
*
*
* @param dto
* @param bindingResult
* @return
*/
@PostMapping("/post")
public Map
好了,结束。测试一下,这里使用IDEA插件RestfulToolkit测试。
所有强大的东西在于可以自定义,接下来我们看看如何自定义校验注解。
这里我们用比较常见的标志位校验需求来做示例
1.创建自定义注解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.PARAMETER})
@Constraint(validatedBy = FlagValidatorClass.class) // 绑定对应校验器
public @interface FlagValidator {
String[] value() default {};
String message() default "flag is not found";
Class>[] groups() default {};
Class extends Payload>[] payload() default {};
}
2.编写对应校验器
/**
* 标志位校验器
*/
public class FlagValidatorClass implements ConstraintValidator {
private String[] values;
/**
* 初始化
*
* @param flagValidator 注解上设置的值
*/
@Override
public void initialize(FlagValidator flagValidator) {
this.values = flagValidator.value();
}
/**
* 校验
*
* @param value 被校验的值,即输入
* @param constraintValidatorContext 校验上下文
* @return 返回true证明校验通过,false校验失败
*/
@Override
public boolean isValid(Integer value, ConstraintValidatorContext constraintValidatorContext) {
boolean isValid = false;
// 当value为null,校验失败
if (value == null) {
return false;
}
//遍历校验
for (int i = 0; i < values.length; i++) {
if (values[i].equals(String.valueOf(value))) {
isValid = true;
break;
}
}
return isValid;
}
}
这样子就完成了自定义参数校验。当然了,我们可以在isValid方法中添加更加复杂的校验逻辑,如正则匹配等方法,这里就不展开了。
测试一下,先在DTO中添加flag属性,标上注解。
@NotNull(message = "标识位不能为空")
@FlagValidator(value = {"0", "1"}, message = "标志位有误")
private Integer flag;
效果:
接着我们来看看BindResult有什么内容。
我们输出一下这个对象
System.out.println(bindingResult);
// 成功时,这没什么好说的
org.springframework.validation.BeanPropertyBindingResult: 0 errors
// 失败时
org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'testDTO' on field 'flag': rejected value [12];
codes [FlagValidator.testDTO.flag,FlagValidator.flag,FlagValidator.java.lang.Integer,FlagValidator];
arguments
[org.springframework.context.support.DefaultMessageSourceResolvable: codes [testDTO.flag,flag];
arguments [];
default message [flag],[Ljava.lang.String;@1017351];
default message [标志位有误]
我们可以看到一些属性,Field、Default message、Rejected value。
我们可以通过他的方法获取对应的值。
获取Error,getFieldError默认返回第一个错误。getAllErrors返回错误列表。
获取对应的属性。
构造我们自己的校验返回内容。
通过Java8的stream方法我们可以简单的获取到报错信息并返回前端;
Object[] objects = bindingResult.getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).toArray();
每次都要写bindingResult以及判断方法其实也挺烦人的,所以再写一个工具类,constraintViolations是一个Set集合,里面包含了错误的信息,我们可以自定义一个异常抛出,并定义全局异常处理器处理请求返回。
public class ValidatorUtils {
private static Validator validator;
static {
validator = Validation.buildDefaultValidatorFactory().getValidator();
}
/**
* 校验对象
*
* @param object 待校验对象
* @param groups 待校验的组
* @throws ApiException 校验不通过,则报ApiException异常
*/
public static void validateEntity(Object object, Class>... groups) {
Set> constraintViolations = validator.validate(object, groups);
if (!constraintViolations.isEmpty()) {
constraintViolations.forEach(o -> {
throw new ApiException(400, o.getMessage());
});
}
}
}
修改TestController,可以看到简洁了许多。效果是一样的,就不演示了。
@RestController
@RequestMapping("/test")
public class TestController {
/**
* 测试
* @param dto
* @param bindingResult
* @return
*/
@PostMapping("/post")
public Map test(@RequestBody TestDTO dto) {
ValidatorUtils.validateEntity(dto);
Map res = new HashMap<>();
res.put("status", 200);
res.put("msg", "ok");
res.put("data", dto);
return res;
}
}
这次Springboot+validation整合就讲到这里。
代码比较简单,源码就不奉上来,有需要的可以私信我。
有什么问题可以评论或者私信我,每日在线解(LIAO)疑(SAO)。
我是大誌,一位准备996的卑微码农,觉得好用记得点赞收藏!!!