利用好javax.validation.groups.Default.class这个默认分组
一、建立不同的分组
注意建立的是接口,继承Default
AddGroup
public interface AddGroup extends Default {
}
UpdateGroup
public interface UpdateGroup extends Default {
}
LogoGroup 测试用
public interface LogoGroup extends Default {
}
二、在Bean上加校验注解
BrandEntity 品牌实体类
@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 品牌id
*/
@Null(message = "新增不能指定品牌id", groups = AddGroup.class)
@NotNull(message = "修改必须指定品牌id", groups = UpdateGroup.class)
@TableId
private Long brandId;
/**
* 品牌名
*/
@NotBlank(message = "品牌名不能为空")
private String name;
/**
* 品牌logo地址
*/
@NotBlank(message = "品牌logo地址不能为空", groups = {UpdateGroup.class, LogoGroup.class})
@URL(message = "logo地址应该是一个网址")
private String logo;
/**
* 介绍
*/
private String descript;
/**
* 显示状态[0-不显示;1-显示]
*/
@NotNull(message = "显示状态不能为空")
@Range(min = 0, max = 1, message = "显示状态的值应该为[0-不显示;1-显示]")
private Integer showStatus;
/**
* 检索首字母
*/
@Pattern(regexp = "^[a-zA-Z]$", message = "检索首字母必须是一个字母")
private String firstLetter;
/**
* 排序
*/
@Min(value = 0, message = "排序字段的值应该为大于等于0的整数")
private Integer sort;
}
三、在Controller的方法参数前加@Validated
注意:如果是要分组校验,那么只能加@Validated,不能加@Valid
/**
* 保存
*/
@RequestMapping("/save")
public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand){
brandService.save(brand);
return R.ok();
}
/**
* 修改
*/
@RequestMapping("/update")
public R update(@Validated({UpdateGroup.class}) @RequestBody BrandEntity brand){
brandService.updateById(brand);
return R.ok();
}
/**
* 修改2
*/
@RequestMapping("/update2")
public R update2(@Validated({LogoGroup.class}) @RequestBody BrandEntity brand){
brandService.updateById(brand);
return R.ok();
}
因为AddGroup继承了Default.class,因此save方法校验BrandEntity里这些信息:
- 配置了分组信息groups,且groups里包含AddGroup的字段;
- 没有配置分组信息groups的字段;
以brandId和logo为例:
brandId:
@Null(message = "新增不能指定品牌id", groups = AddGroup.class)
@NotNull(message = "修改必须指定品牌id", groups = UpdateGroup.class)
- save方法只会校验@Null
- update方法只会校验@NotNull
- update2方法不会校验
logo:
@URL(message = "logo地址应该是一个网址")
@NotBlank(message = "品牌logo地址不能为空", groups = {UpdateGroup.class, LogoGroup.class})
- save方法只会校验@URL
- update方法会校验@URL和@NotBlank
- update2方法会校验@URL和@NotBlank
注:
因为@URL没有配置分组信息groups,默认是Default分组,又因为AddGroup等都继承了Default.class,因此无论Controller里有没有分组,使用的分组是哪一个,@URL每次都会加载到,只有logo有值,都会去校验。
继承了Default.class的好处就体现在这里,只要是无论什么分组都需要校验的字段,不需要去配置分组信息。否则就需要在groups里把所有的分组写上去,非常麻烦,且不美观。
只要字段上配置了分组信息groups,那么只有当Controller里的分组在groups里(Controller里没有分组,那么默认是Default分组)的时候,才会去校验。
四、配置全局异常
ExceptionController
@Slf4j
@RestControllerAdvice(basePackages = {"com.xxx.xxx"})
public class ExceptionController {
// 数据校验异常
@ExceptionHandler(value = {MethodArgumentNotValidException.class})
public R handleValidException(MethodArgumentNotValidException e) {
log.warn("传入参数校验不通过:{},异常类型:{}",e.getMessage(),e.getClass());
Map<String, String> map = new HashMap<>();
BindingResult bindingResult = e.getBindingResult();
bindingResult.getFieldErrors().forEach(fieldError -> {
map.put(fieldError.getField(), fieldError.getDefaultMessage());
});
return R.error(ResultCodeEnum.VALID_EXCEPTION).put("data", map);
}
@ExceptionHandler(Throwable.class)
public R handleException(Throwable throwable){
return R.error(ResultCodeEnum.UNKNOW_EXCEPTION);
}
}
注意:如果是在公共工程里添加统一异常处理类,那么在其它微服务的启动类上要加上注解扫描的路径,比如:
@SpringBootApplication(scanBasePackages = {"com.xxx.xxx"})
五、其它
- 级联校验:entity A里的字段是另一个entity B,如果需要级联校验entity B,那么需要在entity A的字段上加@Valid注解
- 对Controller里的方法的多个参数进行校验(扁平化参数):在Controller类上加注解@Validated
@RestController
@RequestMapping
@Validated
public class HelloController {
@PutMapping("/hello/id/{id}/status/{status}")
public Object helloGet(@Max(5) @PathVariable Integer id, @Min(5) @PathVariable Integer status) {
return "hello world";
}
}
- @Valid和Validated的区别
- 常用的校验注解