美文网首页
通过实现ConstraintValidator完成自定义校验注解

通过实现ConstraintValidator完成自定义校验注解

作者: AC编程 | 来源:发表于2022-03-19 15:57 被阅读0次

一、Spring中的校验注解

在Spring的使用过程中,有一些现成的注解可以使用

  • @AssertFalse:该值必须为False
  • @AssertTrue:该值必须为True
  • @DecimalMax(value,inclusive):被注释的元素必须是一个数字,其值必须小于等于指定的最大值 ,inclusive表示是否包含该值
  • @DecimalMin(value,inclusive):被注释的元素必须是一个数字,其值必须大于等于指定的最小值 ,inclusive表示是否包含该值
  • @Digits:限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
  • @Email:该值必须为邮箱格式
  • @Future:被注释的元素必须是一个将来的日期
  • @FutureOrPresent:被注释的元素必须是一个现在或将来的日期
  • @Max(value):被注释的元素必须是一个数字,其值必须小于等于指定的最大值
  • @Min(value):被注释的元素必须是一个数字,其值必须大于等于指定的最小值
  • @Negative:该值必须小于0
  • @NegativeOrZero:该值必须小于等于0
  • @NotBlank:该值不为空字符串,例如“ ”
  • @NotEmpty:该值不为空字符串,例如”“
  • @NotNull:该值不为Null
  • @Null:该值必须为Null
  • @Past:被注释的元素必须是一个过去的日期
  • @PastOrPresent:被注释的元素必须是一个过去或现在的日期
  • @Pattern(regexp):匹配正则
  • @Positive:该值必须大于0
  • @PositiveOrZero:该值必须大于等于0
  • @Size(min,max):数组大小必须在[min,max]这个区间

二、自定义注解

2.1 自定义注解类
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {IsMobileValidator.class})
public @interface IsMobile {

    boolean required() default true;

    String message() default "参数不正确";

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

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

该自定义注解类中用到了四种元注解,最后一个注解@Constraint表示校验此注解的校验器类,可以多个。值得一提的是除了自定义的message、require属性外,下面的groups和payload也是必须添加的。

2.2 注解校验类
import org.apache.commons.lang3.StringUtils;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class IsMobileValidator implements ConstraintValidator<IsMobile,String> {

    private boolean require = false;

    @Override
    public void initialize(IsMobile constraintAnnotation) {
        require = constraintAnnotation.required();
    }

    @Override
    public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
        if(require){
            return ValidatorUtil.isMobile(s);
        }else {
            if (StringUtils.isEmpty(s)) {
                return true;
            }else {
                return ValidatorUtil.isMobile(s);
            }
        }
    }
}

校验类需要实现ConstraintValidator接口。接口使用了泛型,需要指定两个参数,第一个自定义注解类,第二个为需要校验的数据类型。实现接口后要override两个方法,分别为initialize方法和isValid方法。其中initialize为初始化方法,可以在里面做一些初始化操作,isValid方法就是我们最终需要的校验方法了。可以在该方法中实现具体的校验步骤。

2.3 校验工具类
import org.apache.commons.lang3.StringUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ValidatorUtil {

    private static final Pattern mobile_pattern = Pattern.compile("1\\d{10}");

    public static boolean isMobile(String src) {
        if (StringUtils.isEmpty(src)) {
            return false;
        }
        Matcher m = mobile_pattern.matcher(src);
        return m.matches();
    }
}
2.4 group分组接口实现类

我们可能会将UserVO对象用在不同的接口中接收参数,比如在新增和修改接口中。在新增接口中,需要校验mobile,在修改接口中不需要校验mobile。那注解中的groups字段就派上用场了。groups和@Validated配合能控制哪些注解需不需要开启校验。

我们首先定义2个groups分组接口Update和Create,并且继承Default接口。当然也可以不继承Default接口,因为使用注解时不显示指定groups的值,则默认为groups = {Default.class}。所以继承了Default接口,在用@Validated(Create.class)时,也会校验groups = {Default.class}的注解。

import javax.validation.groups.Default;

public interface Create extends Default {
    
}
import javax.validation.groups.Default;

public interface Update extends Default {
    
}
2.5 普通实体类
import lombok.Data;
import javax.validation.constraints.NotNull;

@Data
public class UserVO {

    @NotNull
    @IsMobile(message = "手机号格式不正确",groups = Create.class)
    private String mobile;

    private String password;
}
2.6 controller接口
import com.qimiao.qm.message.board.temp.Create;
import com.qimiao.qm.message.board.temp.UserVO;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;

@Slf4j
@Api(tags = "自定义校验注解")
@RestController
@RequestMapping("user")
public class UserTestController {

    @PostMapping
    public String add(@RequestBody @Validated(Create.class) UserVO userVO) {
        log.info("add userVO,{}", userVO);
        return "SUCCESS";
    }

    @PutMapping
    public String update(@RequestBody @Valid UserVO userVO) {
        log.info("update userVO,{}", userVO);
        return "SUCCESS";
    }
}

三、测试

1 2

四、扩展

如果参数校验不通过,会抛出MethodArgumentNotValidException异常,我们全局处理下然后返回给接口。

import javax.servlet.http.HttpServletRequest;
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 lombok.extern.slf4j.Slf4j;

@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    // 处理接口参数数据格式错误异常
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public Object errorHandler(HttpServletRequest request, MethodArgumentNotValidException e) {
        return e.getBindingResult().getAllErrors();
    }
}

相关文章

网友评论

      本文标题:通过实现ConstraintValidator完成自定义校验注解

      本文链接:https://www.haomeiwen.com/subject/ngppdrtx.html