分享自定义注解实现JSON字符串校验的过程及遇到的问题。
本文基于Java Bean Validation 的核心接口 ConstraintValidator(ConstraintValidator 的实现类可用于检验 Bean Validation 注解所标记的字段是否符合指定的规则)和@Constraint注解(指定的验证器类必须实现ConstraintValidator接口)
1、自定义注解
import tools.utils.JsonStringValidator;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = JsonStringValidator.class)
@Documented
public @interface CheckJsonString {
/**
* 返回消息
*
*/
String message() default "Value is not a valid JSON string";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
2、自定义JsonStringValidator类实现ConstraintValidator接口,并指定了泛型参数,重写该接口的isValid方法,实现字段是否为JSON字符串的校验。这个类实现了ConstraintValidator接口,所以它默认被spring管理成bean。
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hxsoft.product.common.tools.annotation.CheckJsonString;
public class JsonStringValidator implements ConstraintValidator<CheckJsonString, String> {
private static final ObjectMapper objectMapper = new ObjectMapper();
@Override
public void initialize(CheckJsonString jsonString) {
// 初始化工作(如果有的话)
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
// 空值
if (value == null || value.isEmpty()) {
return true; // 空值不做处理
}
try {
JsonNode tree = objectMapper.readTree(value);
return true; // 是有效的JSON字符串
} catch (Exception e) {
return false; // 不是有效的JSON字符串
}
}
}
3、定义类并使用注解。
@Data
@EqualsAndHashCode(callSuper = false)
public class TestDto {
private static final long serialVersionUID = -80645914200242954L;
/**
*表达式
*/
@CheckJsonString
private String expression;
private String showName;
}
4、测试
@RestController
@RequestMapping("test")
public class TestController {
@Resource
private TestService service;
@PostMapping("add")
public Result add(TestDto dto) {
return service.add(dto);
}
}
结果发现注解并未生效,后来查资料发现需要在实体类上使用 @Valid
或 @Validated
注解来触发校验。代码修改后生效
@RestController
@RequestMapping("test")
public class TestController {
@Resource
private TestService service;
@PostMapping("add")
@ApiOperation("新增")
public Result add(@Valid TestDto dto) {
return service.add(dto);
}
}
知识点补充:
1、@Constraint
注解是Java Bean Validation框架中的一个注解,用于自定义约束注解,即自定义校验规则。使用该注解时需要指定实现了ConstraintValidator
接口的验证器类,用于验证该注解所标记的字段或参数是否符合自定义的校验规则。
@Constraint注解有以下属性:
validatedBy:用于指定实现了ConstraintValidator接口的验证器类。该属性的值是一个Class对象数组,可以指定多个验证器类。
message:用于指定当校验失败时,所返回的错误信息。可以使用占位符{},在校验器中使用具体的参数替换。
groups:用于指定分组,即根据不同的分组应用不同的校验规则。
payload:用于指定元数据,即可以通过该属性传递一些额外的验证信息。
2、ConstraintValidator 的实现类可用于检验 Bean Validation 注解所标记的字段是否符合指定的规则。该接口定义了两个泛型:A extends Annotation,T。其中 A 表示要校验的注解类型,T 表示注解所标记的字段的类型。
该接口有两个方法:
initialize(A constraintAnnotation) 方法:该方法用于初始化校验器,在校验之前调用,可以用来获取注解中定义的参数值。
isValid(T var1, ConstraintValidatorContext var2) 方法:该方法用于检验被注解标记的字段是否符合约束规则,返回一个 boolean 值表示校验结果。其中 var1 参数表示要校验的字段值,var2 参数是校验器的上下文环境,用于构建校验失败的提示信息。
ConstraintValidator 仅提供了校验方法的接口,要实现约束校验功能需要自己编写ConstraintValidator 的实现类,并结合具体的注解使用。
参考链接:https://blog.csdn.net/weixin_42338901/article/details/130224185