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

2022-03-19  本文已影响0人  AC编程

一、Spring中的校验注解

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

二、自定义注解

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();
    }
}
上一篇 下一篇

猜你喜欢

热点阅读