手机号码,格式校验:@MobilePhone(自定义注解)

需求

新增接口修改接口 中,手机号码的格式校验是普遍需要的。

在每个手机号码字段上添加正则表达式校验注解来实现校验,重复书写,容易出错;
在不同的手机号码字段上,可能使用了不同的校验规则,无法有效统一校验规则。

目标

自定义一个用于校验手机号码格式的注解@MobilePhone,能够和现有的 Validation 兼容,使用方式和其他校验注解保持一致。

在这里插入图片描述

校验逻辑

有效格式

  1. 不能包含空格;
  2. 应为11位数字;

不校验非空

手机号码,校验的是格式;不校验是否为空(null 或 空字符串)。如果手机号码为空,直接通过校验;

这样设计是为了,将手机号码是否允许为空,交给接口(业务逻辑)来决定;因为在不同的业务逻辑中,有时手机号码字段可以为空,有时不能为空。

但是,无论手机号码字段是否可以为空,只要客户端传递了手机号码,就应该保证格式是正确的。

Validation本身提供的@Email注解,也是这样的处理逻辑。

注:手机号码,使用字符串类型(Integer类型装不下11位的数值)。

核心代码

需要定义的内容包含两个部分:注解@MobilePhone和 校验器PhoneValidator

注解:@MobilePhone

package com.example.core.validation.phone.strict;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * 字符串必须是格式正确的手机号码。正确格式为:11位数字。
 * <p>
 * {@code null} 或 空字符串,是有效的(能够通过校验)。
 * <p>
 * 支持的类型:字符串
 *
 * @author songguanxun
 * @since 1.0
 */
@Target({FIELD})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = MobilePhoneValidator.class)
public @interface MobilePhone {

    /**
     * @return the error message template
     */
    String message() default "手机号码,格式错误";

    /**
     * @return the groups the constraint belongs to
     */
    Class<?>[] groups() default {};

    /**
     * @return the payload associated to the constraint
     */
    Class<? extends Payload>[] payload() default {};

    /**
     * 手机号码的详细描述。
     * <p>
     * 用于用户提示中,当页面中存在多个手机号码时,帮助用户更好的区分是哪个手机号码填错了。
     */
    String description() default "手机号码";
}

校验器:PhoneValidator

package com.example.core.validation.phone.strict;

import com.example.core.constant.RegexConstant;
import com.example.core.validation.ResetMessageUtil;
import org.springframework.util.ObjectUtils;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.regex.Pattern;

/**
 * 手机号码格式校验器
 */
public class MobilePhoneValidator implements ConstraintValidator<MobilePhone, String> {

    // 手机号码的详细描述。
    private String description;


    @Override
    public void initialize(MobilePhone constraintAnnotation) {
        ConstraintValidator.super.initialize(constraintAnnotation);
        description = constraintAnnotation.description();
    }


    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (ObjectUtils.isEmpty(value)) {
            return true;
        }

        if (value.contains(" ")) {
            String message = String.format("%s,格式错误:不能包含空格", description);
            ResetMessageUtil.reset(context, message);
            return false;
        }

        if (!isMobilePhone(value)) {
            String message = String.format("%s,格式错误", description);
            ResetMessageUtil.reset(context, message);
            return false;
        }

        return true;
    }


    private static final Pattern PATTERN = Pattern.compile(RegexConstant.MOBILE_PHONE);


    /**
     * 是手机号码
     */
    private boolean isMobilePhone(CharSequence input) {
        return PATTERN.matcher(input).matches();
    }

}

使用

@MobilePhone 放在需要校验格式的 手机号码 字段上。

新增用户Param

package com.example.web.response.model.param;

import com.example.core.constant.RegexConstant;
import com.example.core.validation.idcard.IdCard;
import com.example.core.validation.phone.strict.MobilePhone;
import com.example.core.validation.zipcode.ZipCode;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import java.util.Date;

@Data
@Schema(name = "新增用户Param")
public class UserAddParam {

    // 其他字段 ...

    @NotEmpty(message = "手机号码,不能为空")
    @MobilePhone
    @Schema(description = "手机号码", example = "18612345678", pattern = RegexConstant.MOBILE_PHONE)
    private String mobilePhone;

}

编辑用户Param

package com.example.web.response.model.param;

import com.example.core.constant.RegexConstant;
import com.example.core.validation.phone.strict.MobilePhone;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import java.util.Date;

@Data
@Schema(name = "编辑用户Param")
public class UserEditParam {

    // 其他字段 ...

    @NotEmpty(message = "手机号码,不能为空")
    @MobilePhone(description = "编辑用户-手机号码")
    @Schema(description = "手机号码", example = "18612345678", pattern = RegexConstant.MOBILE_PHONE)
    private String mobilePhone;
}

补充代码

ResetMessageUtil:重置提示信息工具类

package com.example.core.validation;

import javax.validation.ConstraintValidatorContext;

/**
 * 参数校验 - 重置提示信息工具类
 */
public class ResetMessageUtil {

    /**
     * 重置提示信息
     */
    public static void reset(ConstraintValidatorContext context, String message) {
        context.disableDefaultConstraintViolation();
        context.buildConstraintViolationWithTemplate(message).addConstraintViolation();
    }

}


RegexConstant:正则表达式-常量

package com.example.core.constant;

/**
 * 正则表达式-常量
 */
public class RegexConstant {

    /**
     * 全部为数字
     */
    public static final String NUMBERS = "^\\d*$";


    /**
     * 邮政编码:6位数字
     */
    public static final String ZIP_CODE = "^\\d{6}$";


    /**
     * 手机号码:11位数字
     */
    public static final String MOBILE_PHONE = "1[3-9]\\d{9}$";

}

校验效果

输入包含空格

在这里插入图片描述

输入非数字

在这里插入图片描述

输入超过11位

在这里插入图片描述

指定 手机号码的详细描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宋冠巡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值