我们有这样一个需求,想要校验一个int类型的变量,校验它的值必须为我们所指定的值,且在修改状态分组时生效。
@ListValue(vals = {0, 1}, groups = {UpdateStatusGroup.class})
1. 导入依赖
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
2. 自定义注解类
@Documented
@Constraint(
//可以指定多个不同的校验器,适配不同类型的数据校验
validatedBy = {ListValueConstraintValidator.class}
)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ListValue {
String message() default "{com.yfy.study.common.valid.ListValue.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
int[] vals() default {};
}
3. 自定义校验器
public class ListValueConstraintValidator implements ConstraintValidator<ListValue, Integer> {
private Set<Integer> set = new HashSet<Integer>();
/**
* 初始化方法
*
* @param constraintAnnotation
*/
public void initialize(ListValue constraintAnnotation) {
int[] vals = constraintAnnotation.vals();
for (int val : vals) {
set.add(val);
}
}
/**
* 判断是否校验成功
*
* @param value 需要校验的值
* @param constraintValidatorContext
* @return
*/
public boolean isValid(Integer value, ConstraintValidatorContext constraintValidatorContext) {
return set.contains(value);
}
}
4. 配置默认提示
创建ValidationMessages.properties
com.yfy.study.common.valid.ListValue.message=必须提交指定的值
5. 创建分组接口
我们的实体类有三种校验场景,新增、修改和修改状态
public interface AddGroup {
}
public interface UpdateGroup {
}
public interface UpdateStatusGroup {
}
6.测试
我们的实体类如下
@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 品牌id
*/
@TableId
@Null(message = "新增不能指定品牌id", groups = {AddGroup.class})
@NotNull(message = "修改必须指定品牌id", groups = {UpdateGroup.class})
private Long brandId;
/**
* 品牌名
*/
@NotBlank(message = "品牌名不能为空", groups = {AddGroup.class, UpdateGroup.class})
private String name;
/**
* 品牌logo地址
*/
@URL(message = "logo必须是一个合法的url地址", groups = {AddGroup.class, UpdateGroup.class})
@NotEmpty(message = "url不能为空", groups = {AddGroup.class})
private String logo;
/**
* 介绍
*/
private String descript;
/**
* 显示状态[0-不显示;1-显示]
*/
@ListValue(vals = {0, 1}, groups = {UpdateStatusGroup.class})
@NotNull(message = "状态不能为空",groups = {UpdateStatusGroup.class})
private Integer showStatus;
/**
* 检索首字母
*/
@Pattern(regexp = "^[a-zA-Z]$",message = "检索首字母必须是一个字母",groups = {AddGroup.class,UpdateGroup.class})
@NotEmpty(message = "检索首字母不能为空", groups = {AddGroup.class})
private String firstLetter;
/**
* 排序
*/
@Min(value = 0, message = "排序字段最小为0", groups = {AddGroup.class, UpdateGroup.class})
@NotNull(message = "排序字段不能为空", groups = {AddGroup.class, UpdateGroup.class})
private Integer sort;
}
我们在Controller层指定分组,触发对应的校验
/**
* 保存
*/
@RequestMapping("/save")
public R save(@RequestBody @Validated(value = AddGroup.class) BrandEntity brand) {
brandService.save(brand);
return R.ok();
}
/**
* 修改
*/
@RequestMapping("/update")
public R update(@Validated(value = UpdateGroup.class) @RequestBody BrandEntity brand) {
brandService.updateById(brand);
return R.ok();
}
/**
* 修改状态
*/
@RequestMapping("/update/status")
public R updateStatus(@Validated(value = UpdateStatusGroup.class) @RequestBody BrandEntity brand) {
brandService.updateById(brand);
return R.ok();
}
我们测试一个接口
http://localhost:88/api/product/brand/save
发送请求:
{
"brandId":1,
"sort":1,
"firstLetter":"VA",
"showStatus":3
}
返回:
{
"msg": "参数格式校验失败",
"code": 10001,
"data": {
"brandId": "新增不能指定品牌id",
"name": "品牌名不能为空",
"logo": "url不能为空",
"showStatus": "必须提交指定的值",
"firstLetter": "检索首字母必须是一个字母"
}
}
这里异常我们使用@ControllerAdvice统一处理了,返回了自定义的格式数据
@Slf4j
@RestControllerAdvice(basePackages = "com.yfy.study.product.controller")
public class GuliMallExceptionControllerAdvice {
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public R handleValidException(MethodArgumentNotValidException e) {
log.error("数据校验出现问题{},异常类型:{}", e.getMessage(), e.getClass());
BindingResult bindingResult = e.getBindingResult();
Map<String, String> errorMap = new HashMap<>();
bindingResult.getFieldErrors().forEach(fieldError -> {
errorMap.put(fieldError.getField(), fieldError.getDefaultMessage());
});
return R.error(BizCodeEnume.VALID_EXCEPTION.getCode(), BizCodeEnume.VALID_EXCEPTION.getMsg()).put("data", errorMap);
}
7. 注意
-
controller指定校验分组 @Validated(value = AddGroup.class)
-
controller不指定校验分组 @Valid
-
默认没有指定分组的校验注解,在分组校验下@Validated(value = AddGroup.class)不会生效,只会在@Valid生效
比如:
@NotNull(message = "姓名不能为空")
private String name;
我们如果指定了某一个分组,则不会触发该字段的校验
本文介绍了如何使用Java的JSR303/JSR349规范进行自定义注解和分组校验,包括创建自定义注解、校验器、配置提示信息、定义校验分组接口以及在Controller中应用分组校验。通过示例展示了在保存、更新和修改状态等不同场景下,如何针对int类型的变量进行指定值校验。
412

被折叠的 条评论
为什么被折叠?



