作用
在平常客户端提交表单参数的时候,可以在客户端进行校验参数。但是利用postman也可以模拟表单提交功能。这时候就需要在服务端进行参数校验。这时候就需要用到jsr了。
使用
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
给bean添加校验注解
/**
* logo地址
*/
@NotBlank(message = "logo地址不能为空")
@URL(message = "LOGO地址不合法")
private String logo;
告诉SpringMvc字段需要校验 @Valid
/**
* 保存
*/
@RequestMapping("/save")
public R save(@Valid @RequestBody BrandEntity brand) {
brandService.save(brand);
return R.ok();
}
获取校验结果
BindingResult 实体类包含异常信息
/**
* 保存
*/
@RequestMapping("/save")
public R save(@Valid @RequestBody BrandEntity brand, BindingResult result) {
if (result.hasErrors()) {
Map<String, String> map = new HashMap<>();
//1、获取校验的错误结果
result.getFieldErrors().forEach((item) -> {
//FieldError 获取到错误提示
String message = item.getDefaultMessage();
//获取错误的属性的名字
String field = item.getField();
map.put(field, message);
});
return R.error(400, "提交的数据不合法").put("data", map);
} else {
brandService.save(brand);
}
return R.ok();
}
分组校验的功能(多场景的复杂校验)
实体类上使用groups
/**
* 品牌id
*/
@NotNull(message = "修改必须指定品牌id",groups = {UpdateGroup.class})
@Null(message = "新增不能指定id",groups = {AddGroup.class})
@TableId
private Long brandId;
比如在上述代码中,添加时候不需要ID,修改的时候需要Id ,这时候就需要使用分组校验了。
定义分组标识
/**
* 添加分组
*/
public interface AddGroup {
}
/**
* 修改分组
*/
public interface UpdateGroup {
}
controller使用分组注解
/**
* 保存
*/
@RequestMapping("/save")
public R save(@Validated({ AddGroup.class }) @RequestBody BrandEntity brand) {
brandService.save(brand);
return R.ok();
}
自定义校验
编写一个自定义的校验注解 例 @ListValue
/**
* 显示状态[0-不显示;1-显示]
*/
@NotNull(message = "显示状态不能为空", groups = { AddGroup.class, UpdateGroup.class })
@ListVal(vals = { 0, 1 }, message="显示状态只能是0或者1", groups = { AddGroup.class, UpdateGroup.class })
private Integer showStatus;
编写一个自定义注解类
validatedBy 后面的类是下面需要实现的类
@Documented
@Constraint(validatedBy = { ListValueConstraintValidator.class })
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {
String message() default "{显示状态只能为[0-不显示;1-显示]}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
int[] vals() default { };
}
编写一个自定义的校验器
public class ListValValidator implements ConstraintValidator<ListVal, Integer> {
private Set<Integer> set = new HashSet<Integer>();
/**
* 初始化方法
* @param constraintAnnotation
*/
public void initialize(ListVal constraintAnnotation) {
int[] vals = constraintAnnotation.vals();
for(int val : vals){
set.add(val);
}
}
public boolean isValid(Integer value, ConstraintValidatorContext context) {
return set.contains(value);
}
}
将这个类与上面自定义的注解进行关联
@Constraint(validatedBy = { ListValueConstraintValidator.class })
补充
上面在控制器中获取校验的异常信息时,不需要在每个方法里面写。可以将这个异常单独提出来,写在全局的异常捕获类中。
校验异常是抛出的MethodArgumentNotValidException
/** 集中处理异常
* @Author: wanyong
* @Date: 2020/8/11 18:17
*/
@ControllerAdvice(basePackages = "com.yong.gulimall.product.controller")
@ResponseBody
public class MallExceptionControllerAdvice {
/**
* 捕获校验结果集出现的异常
* @param e
* @return
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public R handlerValidException(MethodArgumentNotValidException e){
BindingResult result = e.getBindingResult();
Map<String,Object> map = new HashMap<>(20);
if(result.hasErrors()){
result.getFieldErrors().forEach(item -> {
String message = item.getDefaultMessage();
String field = item.getField();
map.put(field, message);
});
}
//BizCodeEnum枚举类型
return R.error(BizCodeEnum.VAILD_EXCEPTION.getCode(),BizCodeEnum.VAILD_EXCEPTION.getMsg()).put("data", map);
}
/**
* 捕获其他异常
* @param e
* @return
*/
@ExceptionHandler(Throwable.class)
public R handlerOtherException(Throwable e) {
return R.error(BizCodeEnum.UNKNOW_EXCEPTION.getCode(), BizCodeEnum.UNKNOW_EXCEPTION.getMsg()).put("data", e.getMessage());
}
}
jsr大体的功能就这些!