validation - zhongjiajie/zhongjiajie.github.com GitHub Wiki

Java 参数验证(validator)

是什么

[javax.validation][1]提供了一系列的注解,帮我们更好的完成参数验证的工作,JSR303 是一套JavaBean参数校验的标准,它定义了很多常用的校验注解,可以将注解加在我们JavaBean的属性上面进行参数校验

javax.validation 的 pom 依赖如下

<!--jsr 303-->
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>1.1.0.Final</version>
</dependency>

没有使用validation之前

没有使用validation之前我们验证参数会写在controller里面

@PostMapping("/save/serial")
public Object save(@RequestBody UserVO userVO) {
    String mobile = userVO.getMobile();

    //手动逐个 参数校验~ 写法
    if (StringUtils.isBlank(mobile)) {
        return RspDTO.paramFail("mobile:手机号码不能为空");
    } else if (!Pattern.matches("^[1][3,4,5,6,7,8,9][0-9]{9}$", mobile)) {
        return RspDTO.paramFail("mobile:手机号码格式不对");
    }

    //抛出自定义异常等~写法
    if (StringUtils.isBlank(userVO.getUsername())) {
        throw new BizException(Constant.PARAM_FAIL_CODE, "用户名不能为空");
    }

    // 比如写一个map返回
    if (StringUtils.isBlank(userVO.getSex())) {
        Map<String, Object> result = new HashMap<>(5);
        result.put("code", Constant.PARAM_FAIL_CODE);
        result.put("msg", "性别不能为空");
        return result;
    }
    //.........各种写法 ...
    userService.save(userVO);
    return RspDTO.success();
}

使用javax.validation进行参数检验

    // controller
    // 在控制器层进行注解声明 @Validated
    @PostMapping("/save/valid")
    public RspDTO save(@RequestBody @Validated UserDTO userDTO) {
        userService.save(userDTO);
        return RspDTO.success();
    }

// javaBean
// 对参数的字段进行注解标注
import lombok.Data;
import org.hibernate.validator.constraints.Length;

import javax.validation.constraints.*;
import java.io.Serializable;
import java.util.Date;

@Data
public class UserDTO implements Serializable {
    private static final long serialVersionUID = 1L;

    /*** 用户ID*/
    @NotNull(message = "用户id不能为空")
    private Long userId;

    /** 用户名*/
    @NotBlank(message = "用户名不能为空")
    @Length(max = 20, message = "用户名不能超过20个字符")
    @Pattern(regexp = "^[\\u4E00-\\u9FA5A-Za-z0-9\\*]*$", message = "用户昵称限制:最多20字符,包含文字、字母和数字")
    private String username;

    /** 手机号*/
    @NotBlank(message = "手机号不能为空")
    @Pattern(regexp = "^[1][3,4,5,6,7,8,9][0-9]{9}$", message = "手机号格式有误")
    private String mobile;

    /**性别*/
    private String sex;

    /** 邮箱*/
    @NotBlank(message = "联系邮箱不能为空")
    @Email(message = "邮箱格式不对")
    private String email;

    /** 密码*/
    private String password;

    /*** 创建时间 */
    @Future(message = "时间必须是将来时间")
    private Date createTime;
}

自定义校验规则(以校验身份证号为例)

先定义注解

// 这个注解是作用在Field字段上,运行时生效,触发的是IdentityCardNumber这个验证类。
// message 定制化的提示信息,主要是从ValidationMessages.properties里提取,也可以依据实际情况进行定制
// groups 这里主要进行将validator进行分类,不同的类group中会执行不同的validator操作
// payload 主要是针对bean的,使用不多。
@Documented
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = IdentityCardNumberValidator.class)
public @interface IdentityCardNumber {

    String message() default "身份证号码不合法";

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

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

自定义Validator

// 这个是真正进行验证的逻辑代码
public class IdentityCardNumberValidator implements ConstraintValidator<IdentityCardNumber, Object> {

    @Override
    public void initialize(IdentityCardNumber identityCardNumber) {
    }

    @Override
    public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
        return IdCardValidatorUtils.isValidate18Idcard(o.toString());
    }
}

使用自定义注解

    @NotBlank(message = "身份证号不能为空")
    @IdentityCardNumber(message = "身份证信息有误,请核对后提交")
    private String clientCardNo;

使用groups区分当前状态是否要进行验证

同一个对象要复用,比如UserDTO在更新时候要校验userId,在保存的时候不需要校验userId,在两种情况下都要校验username,groups就是为了这样的情况使用的

定义groups的接口

import javax.validation.groups.Default;

// 在声明分组的时候尽量加上 extend javax.validation.groups.Default 否则没有声明中的bean字段就不会去校验,因为默认的校验组是groups = {Default.class}, 那样下面的 @Email(message = "邮箱格式不对") 因为没有设置 groups 会一直校验
public interface Create extends Default {
}

import javax.validation.groups.Default;

public interface Update extends Default{
}

javaBean中定义对应的groups

@Data
public class UserDTO implements Serializable {

    private static final long serialVersionUID = 1L;

    /*** 用户ID*/
    @NotNull(message = "用户id不能为空", groups = Update.class)
    private Long userId;

    /**
     * 用户名
     */
    @NotBlank(message = "用户名不能为空")
    @Length(max = 20, message = "用户名不能超过20个字符", groups = {Create.class, Update.class})
    @Pattern(regexp = "^[\\u4E00-\\u9FA5A-Za-z0-9\\*]*$", message = "用户昵称限制:最多20字符,包含文字、字母和数字")
    private String username;

    /**
     * 手机号
     */
    @NotBlank(message = "手机号不能为空")
    @Pattern(regexp = "^[1][3,4,5,6,7,8,9][0-9]{9}$", message = "手机号格式有误", groups = {Create.class, Update.class})
    private String mobile;

    /**
     * 性别
     */
    private String sex;

    /**
     * 邮箱
     */
    @NotBlank(message = "联系邮箱不能为空")
    @Email(message = "邮箱格式不对")
    private String email;

    /**
     * 密码
     */
    private String password;

    /*** 创建时间 */
    @Future(message = "时间必须是将来时间", groups = {Create.class})
    private Date createTime;

[1]:

⚠️ **GitHub.com Fallback** ⚠️