跳到主要内容

JSR303校验

JSR303校验

在实体类上面加注解@NotBlank等等:

@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {
private static final long serialVersionUID = 1L;

/**
* 品牌id
*/
@TableId
private Long brandId;
/**
* 品牌名
*/
@NotBlank(message = "品牌名不能为空")
private String name;
/**
* 品牌logo地址
*/
@NotEmpty
@URL(message = "logo必须是一个合法的url地址")
private String logo;
/**
* 介绍
*/
private String descript;
/**
* 显示状态[0-不显示;1-显示]
*/
private Integer showStatus;
/**
* 检索首字母
*/
@NotEmpty
@Pattern(regexp = "/^[a-zA-Z]$/",message = "检索首字母必须是一个字母")
private String firstLetter;
/**
* 排序
*/
@NotNull
@Min(value = 0,message = "排序必须大于等于0")
private Integer sort;
}

控制器中加注解@Valid

/**
* 保存
*/
@RequestMapping("/save")
//@RequiresPermissions("product:brand:save")
public R save(@Valid @RequestBody BrandEntity brand, BindingResult result) {

if (result.hasErrors()) {
Map<String, String> map = new HashMap<>();
result.getFieldErrors().forEach((item) -> {
//获取到错误提示
String message = item.getDefaultMessage();
//获取错误的属性的名字
String field = item.getField();
map.put(field, message);
});
return R.error(400, "submit data not valid").put("data", map);
}
brandService.save(brand);
return R.ok();
}

BindingResult要紧跟在校验的后面

测试结果:

image-20240121130922720

统一异常校验:

@RestControllerAdvice(basePackages = "com.cxk.gulimall.product.controller")
@Slf4j
public class GulimallExceptionControllerAdvice {

@ExceptionHandler(value = {MethodArgumentNotValidException.class})
public R handleVaildException(MethodArgumentNotValidException e) {
log.error("数据校验出现异常,异常类型:{}", MethodArgumentNotValidException.class);
BindingResult bindingResult = e.getBindingResult();
Map<String, String> map = new HashMap<>();
bindingResult.getFieldErrors().forEach((item) -> {
map.put(item.getField(), item.getDefaultMessage());
});
return R.error(BizCodeEnum.VALID_EXCEPTION.getCode(), BizCodeEnum.VALID_EXCEPTION.getMsg())
.put("data", map);
}

@ExceptionHandler(value = Exception.class)
public R handleException(Exception e) {
return R.error(BizCodeEnum.UNKNOW_EXCEPTION.getCode(), BizCodeEnum.UNKNOW_EXCEPTION.getMsg());
}
}

状态码枚举:

public enum BizCodeEnum {
UNKNOW_EXCEPTION(10000, "系统未知异常"),

VALID_EXCEPTION(10001, "参数格式校验失败");

private Integer code;
private String msg;

BizCodeEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}

public Integer getCode() {
return code;
}

public String getMsg() {
return msg;
}
}

JSR303分组校验

创建两个类,增加和修改分组:

public interface AddGroup {
}
public interface UpdateGroup {
}

给实体类增加组:

@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {
private static final long serialVersionUID = 1L;

/**
* 品牌id
*/
@TableId
@NotNull(message = "品牌id必须提交",groups = {UpdateGroup.class})
@Null(message = "新增不能指定id",groups = {AddGroup.class})
private Long brandId;
/**
* 品牌名
*/
@NotBlank(message = "品牌名不能为空",groups = {UpdateGroup.class,AddGroup.class})
private String name;
/**
* 品牌logo地址
*/
@NotBlank(message = "logo不能为空",groups = {AddGroup.class})
@URL(message = "logo必须是一个合法的url地址",groups = {UpdateGroup.class,AddGroup.class})
private String logo;
/**
* 介绍
*/
private String descript;
/**
* 显示状态[0-不显示;1-显示]
*/
private Integer showStatus;
/**
* 检索首字母
*/
@NotEmpty(groups = {AddGroup.class})
@Pattern(regexp = "/^[a-zA-Z]$/",message = "检索首字母必须是一个字母",groups = {UpdateGroup.class,AddGroup.class})
private String firstLetter;
/**
* 排序
*/
@NotNull(message = "排序不能为空",groups = {AddGroup.class})
@Min(value = 0,message = "排序必须大于等于0",groups = {UpdateGroup.class,AddGroup.class})
private Integer sort;

}

控制器上面添加组:

/**
* 保存
*/
@RequestMapping("/save")
//@RequiresPermissions("product:brand:save")
public R save(@Validated(AddGroup.class) @RequestBody BrandEntity brand) {
brandService.save(brand);
return R.ok();
}

/**
* 修改
*/
@RequestMapping("/update")
//@RequiresPermissions("product:brand:update")
public R update(@Validated(UpdateGroup.class) @RequestBody BrandEntity brand) {
brandService.updateById(brand);

return R.ok();
}

自定义校验规则

创建一个ListValue注解:

@Documented
@Constraint(validatedBy = {ListValueConstraintValidator.class})
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
public @interface ListValue {

String message() default "{com.cxk.common.validator.ListValue.message}";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};

int[] vals() default {};
}

在Resources目录下面创建ValidationMessages.properties

com.cxk.common.validator.ListValue.message = 必须提交给定的值

创建一个ListValueConstraintValidator类,只允许制定的整数

public class ListValueConstraintValidator implements ConstraintValidator<ListValue, Integer> {

private Set<Integer> set = new HashSet<>();

@Override
public void initialize(ListValue constraintAnnotation) {
int[] vals = constraintAnnotation.vals();
for (int val : vals) {
set.add(val);
}
}

@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
return set.contains(value);
}
}

在实体类上面加注解:

/**
* 显示状态[0-不显示;1-显示]
*/
@NotNull(groups = {AddGroup.class, UpdateStatusGroup.class})
@ListValue(vals = {0,1},groups = {AddGroup.class, UpdateStatusGroup.class})
private Integer showStatus;