利用好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的差別
- 常用的校驗注解