小编给大家分享一下ConstraintValidator类怎么实现自定义注解校验前端传参,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.validation.Constraint; import javax.validation.Payload; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented @Constraint( validatedBy = {IllegalNumberValidator.class} ) public @interface IllegalNumber { /** * 允许前端取的几个值 * */ int[] acceptValues(); /** * 标识此字段是否为必选项 * */ boolean required() default true; /** * 标识此字段是否为必选项 * */ String message() default "数字不合法,不在要求的取值范围之内"; /** * 标识要校验的值所属组,这个后面详细解释 * */ Class<?>[] groups() default {}; /** * 这个字段一般不需要我们关注 * */ Class<? extends Payload>[] payload() default {}; }
注意到刚才注解中的@Constraint注解了吗
validatedBy属性标识这个注解要被哪个类所增强,我们把增强类IllegalNumberValidator定义出来
import com.google.common.collect.Lists; import org.springframework.util.StringUtils; import java.util.List; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; public class IllegalNumberValidator implements ConstraintValidator<IllegalNumber, Integer> { private final List<Integer> valueList = Lists.newArrayList(); private boolean require = false; @Override public void initialize(IllegalNumber constraintAnnotation) { require = constraintAnnotation.required(); int[] ints = constraintAnnotation.acceptValues(); for (int anInt : ints) { valueList.add(anInt); } } @Override public boolean isValid(Integer number, ConstraintValidatorContext constraintValidatorContext) { // 如果是必选的话,假设为我们传递的参数为空那肯定不行 if (require) { if (number == null) { return false; } return valueList.contains(number); } else { // 如果不为必选参数,为空返回true,不为空还是得校验 if (StringUtils.isEmpty(number)) { return true; } else { return valueList.contains(number); } } } }
增强类继承ConstraintValidator类,实现的initialize()方法是初始化方法,啥意思呢,啥目的呢?在你真正执行校验之前,可以做一些准备性工作,发生在要校验的值上面的注解的IllegalNumber 已经给咱们传进来了。我做的初始化工作就是load一下Integer类型的可选值,方便一会执行真正的校验。
然后在isValid()方法中你可以做真正的校验了,很简单,我看下传递的Integer类型的值是不是acceptValues里面的可选值就行了。
定义一个前端传递的类,方便调试注解
import lombok.Data; import org.hibernate.validator.constraints.Length; import javax.validation.constraints.NotNull; @Data public class TestVO { @NotNull @IllegalNumber(acceptValues = {0, 1,2},required = true,message = "请正确取值") private Integer number; @NotNull @Length(min = 1) private String password; }
定义接口,用来接收前端传递的json数据并parse为TestVO类
/** * 测试自定义注解 * * @param vo json将会映射的实体 * @return 默认信息 */ @PostMapping(value = "/v1.0/test2", name = "测试自定义注解") public String test2(@Valid @RequestBody TestVO vo) { log.info("get vo success , detail message is:{}", vo); return RETURN_MESSAGE; }
注意,如果说前端传递数据不符合注解的校验,其实是会抛出异常的来自@Constraint注解实现的注解都有此特点,例如@Length、@Max等。咱们需要在异常抛出的时候给出拦截 这里咱们做一个通用拦截:
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.http.HttpStatus; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import java.util.Objects; import javax.validation.ConstraintViolationException; @ControllerAdvice public class RestResponseEntityExceptionHandler { private static final Logger LOG = LoggerFactory.getLogger(RestResponseEntityExceptionHandler.class); @Autowired private ApplicationContext applicationContext; @ExceptionHandler({ConstraintViolationException.class}) @ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseBody public String handleConstraintViolationException(ConstraintViolationException e) { LOG.info("ConstraintViolationException intercept success:{}", e.getMessage()); return e.getMessage(); } @ExceptionHandler({MethodArgumentNotValidException.class}) @ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseBody public String handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { LOG.info("MethodArgumentNotValidException intercept success:{}", e.getMessage()); return Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage(); } }
下面测试一下。打开postman。直接干!取值的限定是0、1、2。咱们先试下错误的
ok,再试下正确的
groups参数,代表所属组的意思。演示下怎么用,大家也就知道这个参数啥意思了。 建立Group1接口
public interface Group1 { }
建立Group2接口
public interface Group2 { }
给TestVO增加一个参数,方便一会进行比较
@Data public class TestVO { @NotNull @IllegalNumber(acceptValues = {0, 1,2},required = true,message = "请正确取值",groups = Group1.class) private Integer number; @NotNull @IllegalNumber(acceptValues = {0, 1,2},required = true,message = "请正确取值ha",groups = Group2.class) private Integer number2; @NotNull @Length(min = 1) private String password; }
使用注解的时候标明所属组:
接口处也进行标识:
现在咱们分别测试下两个接口,看groups参数是否能生效
test2接口
test3接口
ok,相信大家对此参数已经掌握了,这里不再多余赘述。
以上是“ConstraintValidator类怎么实现自定义注解校验前端传参”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。