超详细!利用SpringBoot+SpringCloud做一个问答项目(四)

目录

基于SpringMVC框架统一处理异常【续】

补:不允许注册相同的手机号码

一、调整R类以增加代码的可读性

二、通过Spring Validation检查数据的有效性

三、搭建Eureka注册中心

四、Eureka客户端注册

附:常用的正则表达式

1. 用户名正则

2. 密码强度正则

3. 整数正则

4. 数字正则

5. Email正则

6. 手机号码正则

7. 身份证号正则

8. URL正则

9. IPv4地址正则

10. 十六进制颜色正则

12. QQ号码正则

13. 微信号正则

14. 车牌号正则

15. 包含中文正则


基于SpringMVC框架统一处理异常【续】

统一处理异常的方法需要添加@ExceptionHandler注解,该注解的源代码:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExceptionHandler {

	/**
	 * Exceptions handled by the annotated method. If empty, will default to any
	 * exceptions listed in the method argument list.
	 */
	Class<? extends Throwable>[] value() default {};

}

通过以上源代码可以看到:

  • 该注释中存在名为value的属性;
  • 在所有注解中,value是默认的属性,如果需要配置该属性的值,当需要配置1个属性的值时,是不需要显式的写出value=的;
  • value属性的值的类型是Class<? extends Throwable>[],即“异常类的数组”;
  • 在配置任何注解属性时,如果注解的属性值是数组格式的,当前配置值时数组元素只有1个值时,不需要使用数组,直接使用元素值即可;
  • default {}表示默认值是一个空数组。

假设,使用RuntimeException类作为以上属性的值,则以下几种配置是完全等效的:

@ExceptionHandler(value={RuntimeException.class})
@ExceptionHandler(value=RuntimeException.class)
@ExceptionHandler({RuntimeException.class})
@ExceptionHandler(RuntimeException.class)

关于该属性的作用:

Exceptions handled by the annotated method. If empty, will default to any exceptions listed in the method argument list.

意思是:

被添加了注解的方法处理的异常。如果该属性的值为空,默认表示处理方法的参数列表中的所有异常。

所以,该属性的作用是“当前处理异常的方法到底需要处理哪些异常,如果没有配置属性值,以方法的参数中声明的异常类型为准”!

例如,处理异常的方法是:

@ExceptionHandler
public R handleException(Throwable e) {
}

显然,@ExceptionHandler没有配置value属性,当前方法处理的异常的种类就是方法的参数Throwable类型的,也就是“所有类型的异常都将由当前方法进行处理”!

如果将以上代码调整为:

@ExceptionHandler(ServiceException.class)
public R handleException(Throwable e) {
}

则以上方法只处理ServiceException类型的异常!

通常,在统一处理异常时,建议显式的指定需要处理的异常种类!


补:不允许注册相同的手机号码

如果需要判断手机号码是否已经被注册,并且抛出对应的异常,需要完成的开发任务大致有:

  • 在业务层必须能够判断得出某手机号码是否已经被注册;
  • 必须创建对应的异常类,当手机号码已经被注册时,将抛出该异常的对象;
  • 在统一处理异常的代码区域,添加对“手机号码已经被注册”的异常的处理。

正常来看,在当前项目中已经根据用户名查询了用户信息,来检验用户名是否已经被注册,但是,这项检查与手机号码是否已经被注册是没有任何关系的!所以,关于手机号码是否已经被注册,需要重新检查!则应该在持久层接口UserMapper.java中添加新的查询方法:  

/**
 * 根据手机号码查询用户数据
 *
 * @param phone 手机号码
 * @return 匹配的用户数据,如果没有匹配的数据则返回null
 */
User findByPhone(String phone);

然后,在UserMapper.xml中配置以上查询映射的SQL语句:

<select id="findByPhone" resultMap="BaseResultMap">
    SELECT * FROM user WHERE phone=#{phone}
</select>

完成后,应该及时测试功能是否正确,所以,在UserMapperTests中编写并执行单元测试:

@Test
void findByPhone() {
    String phone = "13000130000";
    User user = mapper.findByPhone(phone);
    System.out.println("user=" + user);
}

接下来,需要创建新的异常类,表示“手机号码已经被注册”,则在cn.tedu.straw.api.user.ex包中创建PhoneDuplicateException异常类,继承自ServiceException类:

/**
 * 手机号码已经被注册
 */
public class PhoneDuplicateException extends ServiceException {

    // 构造方法
    
}

并且,在UserServiceImpl类中,在处理“注册”时,添加判断:先调用持久层新增的findByPhone()来查询用户数据,如果查询结果不为null,则表示手机号码已经被注册,则抛出异常:

完成后,应该再次调用UserServiceTests中原有的单元测试,检查修改后的方法是否可以正常运行!

最后,在统一处理异常的过程中,添加对PhoneDuplicateException的处理:


一、调整R类以增加代码的可读性

为了增加代码的可读性,应该将所使用到的“状态码”都使用一些常量来表示!同时,为了便于管理这些量,可以在R类中使用内部接口进行封装:

public interface State {

    /**
     * 错误:用户名已经被注册
     */
    Integer ERR_USERNAME_DUPLICATE = 4000;
    /**
     * 错误:手机号码已经被注册
     */
    Integer ERR_PHONE_DUPLICATE = 4001;
    /**
     * 错误:邀请码错误
     */
    Integer ERR_INVITE_CODE = 4002;
    /**
     * 错误:班级已经被禁用
     */
    Integer ERR_CLASS_DISABLED = 4003;
    /**
     * 错误:插入数据失败
     */
    Integer ERR_INSERT = 4004;
    /**
     * 错误:未知错误
     */
    Integer ERR_UNKNOWN = 9000;

}

为了更加快捷的创建R类的对象,还可以添加一些方法:

public R() {
    super();
}

public R(Integer state) {
    this.state = state;
}

public static R ok() {
    return new R(1);
}

public static R failure(Integer state, Throwable e) {
    R r = new R();
    r.setState(state);
    r.setMessage(e.getMessage());
    return r;
}

最后,R类的完整代码:

package cn.tedu.straw.api.user.util;

import lombok.Data;

import java.io.Serializable;

@Data
public class R implements Serializable {

    /**
     * 响应时的状态码
     */
    private Integer state;
    /**
     * 操作失败时的提示信息
     */
    private String message;

    public R() {
        super();
    }

    public R(Integer state) {
        this.state = state;
    }

    public static R ok() {
        return new R(1);
    }

    public static R failure(Integer state, Throwable e) {
        R r = new R();
        r.setState(state);
        r.setMessage(e.getMessage());
        return r;
    }

    public interface State {

        /**
         * 错误:用户名已经被注册
         */
        Integer ERR_USERNAME_DUPLICATE = 4000;
        /**
         * 错误:手机号码已经被注册
         */
        Integer ERR_PHONE_DUPLICATE = 4001;
        /**
         * 错误:邀请码错误
         */
        Integer ERR_INVITE_CODE = 4002;
        /**
         * 错误:班级已经被禁用
         */
        Integer ERR_CLASS_DISABLED = 4003;
        /**
         * 错误:插入数据失败
         */
        Integer ERR_INSERT = 4004;
        /**
         * 错误:未知错误
         */
        Integer ERR_UNKNOWN = 9000;

    }

}

同时,GlobalExceptionHandler中处理异常的代码调整为:

package cn.tedu.straw.api.user.controller;

import cn.tedu.straw.api.user.ex.*;
import cn.tedu.straw.api.user.util.R;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 全局处理异常的类
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ServiceException.class)
    public R handleException(Throwable e) {
        if (e instanceof UsernameDuplicateException) {
            return R.failure(R.State.ERR_USERNAME_DUPLICATE, e);
        } else if (e instanceof InviteCodeException) {
            return R.failure(R.State.ERR_INVITE_CODE, e);
        } else if (e instanceof ClassDisabledException) {
            return R.failure(R.State.ERR_CLASS_DISABLED, e);
        } else if (e instanceof InsertException) {
            return R.failure(R.State.ERR_INSERT, e);
        } else if (e instanceof PhoneDuplicateException) {
            return R.failure(R.State.ERR_PHONE_DUPLICATE, e);
        } else {
            return R.failure(R.State.ERR_UNKNOWN, e);
        }
    }

}

二、通过Spring Validation检查数据的有效性

在任何软件中,都应该将用户填写/选择并提交的数据视为“不可靠的数据”,以“用户名”为例,字符串的长度太短或太长的都应该是不允许的,其它的各种数据都应该存在相应一些规则,用于约定数据的基本有效性(格式是否正确、是否存在明确的错误)!

约定:在服务器端,当控制器接收到客户端的请求参数后,第一时间就应该检查这些请求参数的基本有效性,如果不符合所设定的数据格式或简易规则,应该直接响应错误,不予进一步处理!

对于这些数据的处理,通常可以结合Java中的原有的API或判断语句来实现,例如通过数值大小的判断来验证“年龄”属性的值是否合规,也可以通过String的API来判断用户名的长度、密码的长度等,如果数据规则较复杂,通过API不易于实现,还可以通过正则表达式来进行验证,例如用户名的格式、电子邮箱的格式等。

Spring Validation框架是专门用于检验数据有效性的框架,该框架的依赖的参考代码:

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-validation -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
    <version>2.3.3.RELEASE</version>
</dependency>

关于Spring Validation的用法:

  • 在需要验证的对象的属性之前添加验证注解,并通过注解配置验证规则和错误提示信息;
  • 在控制器的处理请求的方法的参数列表中,在被验证的参数之前添加@Valid / @Validated注解,表示该参数将被Spring Validation进行验证;
  • 在控制器的处理请求的方法的参数列表中,紧随被验证的参数之后,使用BindingResult接收验证失败的结果。

以本次执行的“注册”为例,在控制器的处理请求的方法中,是使用RegisterStudentDTO接收客户端提交的请求参数的,所以,需要在RegisterStudentDTO的属性之前添加注解,以配置验证规则和错误提示信息,例如:  

然后,在处理注册的控制器方法中,为接收请求参数的方法参数添加注解:

并且,在这个参数之后,添加BindingResult类型的参数,用于接收验证失败的结果:

最后,在方法中,判断验证是否失败,并简单的处理结果:

完成后,即可尝试测试运行,在测试时,可以故意不填写username属性的值,例如请求URL为 http://localhost:8080/v1/users/reg?username=&password=1234&phone=13400134000&inviteCode=JSD2005-666666,提交访问后,控制台会输出显示:

由于出错时并没有阻止程序运行,所以,即使请求参数有误,程序仍会继续向后执行,甚至可能成功注册!

关于配置验证规则的注解:

  • @NotNull:不允许为null值,当服务器端要求提供某参数,客户端完全没有提交这个值时,则验证失败,例如在控制器的参数列表中添加了String username,但是,客户端提交的请求参数中根本没有名为username的参数;
  • @NotEmpty:不允许为空值,例如""即为空值,则验证失败;
  • @NotBlank:不允许为空白,仅能添加在String类型的属性之前,要求字符串调用trim()之后仍不为""空值,否则,验证失败,例如" "的验证将是失败的;
  • @Pattern:通过正则表达式验证,使用该注解时,必须配置regexp属性,用于配置正则表达式;

另外,还有其它注解:

在当前项目中,由于“注册”时只需要填写邀请码、昵称、手机号码、密码即可,则只需要对这几个属性配置验证规则:

 

注意:由于软件的“注册”页面中并没有要求填写用户名,在处理注册的业务中,可以直接将手机号作为用户名:

在控制器的处理请求的方法中,被验证的参数需要添加@Valid注解,或者添加@Validated也是可以的,在Spring的官网的演示案例中,使用的是@Valid注解。

注意:Spring Validation推荐对整个对象进行验证,而不是对某1个参数的值进行验证,所以,一般会将客户端提交的请求参数进行封装,使用封装的类型作为控制器处理请求的方法的参数!

当需要获取验证失败的结果时(验证成功时代码是可以顺利执行,不需要判断或处理),需要使用BindingResult接口类型的对象,注意:该对象应该作为处理请求的方法的参数,且必须添加在被验证数据之后!也就是说,被验证对象和BingdingResult对象都必须在处理请求的方法的参数列表中,且这2个参数是连在一起声明的,中间不会有其它参数!

正例(BindingResult紧随被验证的参数之后):

public R reg(@Valid RegisterStudentDTO registerStudentDTO, BingdingResult bingResult, HttpServletRequest request) {}

反例(BingdingResult与被验证的参数之间有其它参数):

public R reg(@Valid RegisterStudentDTO registerStudentDTO, HttpServletRequest request, BingdingResult bingResult) {}

在通过BindingResult判断错误并获取错误信息后,必须阻止程序继续向后执行!可以继续创建异常类,用于表示“非法请求参数”的错误,并且,在验证失败时,抛出该异常的对象,后续,在统一处理异常的代码中,对这种异常进行处理即可!

先在cn.tedu.straw.api.user.ex包下创建IllegalParameterException类,继承自ServiceException类:

/**
 * 非法的请求参数
 */
public class IllegalParameterException extends ServiceException {
	// 构造方法
}

然后,在控制器中,如果验证失败,则抛出异常:

在处理异常之前,还应该在R.State中声明新的常量:

最后,在GlobalExceptionHandler中处理异常的方法中,补充处理IllegalParameterException

全部完成后,重启项目,在浏览器中通过 http://localhost:8080/v1/users/reg?inviteCode=&phone=&nickname=&password= 进行测试访问。


三、搭建Eureka注册中心

当使用分布式集群后,在整个集群中将存在若干个服务器,每个服务器的任务可能都是不同的,并且,服务器之间可能需要彼此访问,在访问之前就必须明确目标服务器的位置,为了更好的统一管理服务器的相关参数(例如服务器的IP地址、端口号、应用程序名称等),就需要使用“发现”框架!

所有的“发现”框架的实现原理大致是:各功能服务器启动后,会在“发现”服务器中进行“注册”,将自身的参数(例如IP地址、端口号、应用程序名称等)提交给“发现”服务器,“发现”服务器会将所有功能服务器的注册信息进行汇总,得到“注册表”,并将注册表发给所有功能服务器,则各功能服务器得到“注册表”之后,就知道其它服务器的参数了!

Eureka是Spring Cloud家族中的1个“发现”框架,用于搭建注册中心!

关于Eureka注册中心的搭建,首先,在当前父项目中创建新的子模块项目straw-eureka-server

创建好的项目中,在pom.xml中已经添加了Spring Cloud家族的依赖的管理:

其版本是:

实际依赖的只是Spring Cloud家族中的eureka-server

首先,应该将Spring Cloud家族的依赖管理移动到父项目中(版本暂时使用Hoxton.SR3):

然后,在straw-eureka-serverpom.xml中,设置父级项目,设置应用spring-boot-starter-webeureka-server依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>cn.tedu</groupId>
        <artifactId>straw</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>cn.tedu</groupId>
    <artifactId>straw-eureka-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>straw-eureka-server</name>

    <dependencies>
        <!-- Eureka Server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!-- web:允许项目启动在Tomcat -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

</project>

然后,删除项目中的test文件夹!(因为SpringBoot项目默认在test中有测试类,而当前项目已经删了单元测试相关的依赖,所以,如果不删除test文件夹中的文件,就会报错,当前项目也并不需要编写Java代码,所以,不需要使用单元测试)

作为一个Eureka注册中心项目,需要在配置类(启动类就是配置类)的声明之前添加@EnableEurekaServer注解:

然后,在application.properties中添加配置信息:

# 指定当前项目部署到服务器的哪个端口号上运行
# Eureka Server的默认端口号是8761
server.port=8761

# 当前项目不要从Eureka Server抓取注册表
eureka.client.fetch-registry=false
# 当前项目不要在Eureka Server中注册
eureka.client.register-with-eureka=false

因为每一个Eureka Server也是一个Eureka Client,默认都会自动连接Eureka Server进行注册并抓取注册,以上2个属性的作用就是分别设置“不要注册”和“不要抓取注册表”。

到此,Eureka Server项目就已经搭建好,启动项目,在浏览器中通过 http://localhost:8761 即可访问到Eureka的状态页面:

在运行一段时间后,Eureka状态页面会显示红色的警告,可以无视:


四、Eureka客户端注册

在集群中,需要到Eureka Server注册的其它服务器的项目都称之为Eureka Client(客户端),每个Eureka Client都需要在pom.xml中添加eureka-client的依赖!

所以,在straw-api-userpom.xml中添加eureka-client的依赖:

关于eureka-client的依赖,可以先将straw-eureka-server中关于eureka-server的依赖复制过去,然后将server改为client即可。

由于Eureka Client是可以自动配置的(该自动配置是SpringBoot完成的,只要添加了依赖,就会自动配置),所以,当添加依赖后,可以不做进一步的配置,直接运行straw-api-user项目,在Eureka状态列表中可以看到

则表示straw-api-user在Eureka Server上已经注册!

注意:每个Eureka Client在启动时都会自动尝试找Eureka Server执行注册,在后续的使用中,应该最先启动straw-eureka-server项目,再启动其它项目,否则,如果其它Eureka Client项目是先启动的,而Eureka Server尚未启动,则在控制台会提示错误信息,例如:

注意:即使出现以上错误,也不影响该项目单机运行(如果某些功能需要与集群中的其它服务器交互,由于没法从Eureka Server中获取注册表,就不知道其它服务器的信息,则无法连接)。

关于在Eureka状态页面显示的信息,由于没有进行详细配置,所以,显示的信息可能不统一,甚至后续的相互调用也存在不确定因素,所以,应该在straw-api-userapplication.properties中添加配置:

# 显式的配置当前项目部署到服务器时运行在哪个端口号
server.port=8080

# 应用程序名称
spring.application.name=api-user

# 是否使用IP地址来注册,如果是,则注册IP地址,如果否,则注册主机名
eureka.instance.prefer-ip-address=true
# 当前项目在Eureka Server中注册的主机名,仅当prefer-ip-address设置为false时有效
eureka.instance.hostname=localhost
# 当前项目在Eureka Server中注册的IP地址,当prefer-ip-address设置为true时有效
eureka.instance.ip-address=127.0.0.1
# 当前项目在Eureka状态页显示的信息
eureka.instance.instance-id=${spring.application.name}@${eureka.instance.ip-address}:${server.port}

另外,在早期的版本中,Eureka Client项目还需要在配置类的声明之前添加@EnableEurekaClient注解,目前已经不需要了!


 

附:常用的正则表达式

以JavaScript中应用正则表达式为例(原文地址:https://www.cnblogs.com/raphael1982/p/8012634.html):

1. 用户名正则

//用户名正则,4到16位(字母,数字,下划线,减号)
var uPattern = /^[a-zA-Z0-9_-]{4,16}$/;
//输出 true
console.log(uPattern.test("iFat3"));

2. 密码强度正则

// 密码强度正则,最少6位,包括至少1个大写字母,1个小写字母,1个数字,1个特殊字符
var pPattern = /^.*(?=.{6,})(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]).*$/;
// 输出 true
console.log("=="+pPattern.test("iFat3#"));

3. 整数正则

//正整数正则
var posPattern = /^\d+$/;
//负整数正则
var negPattern = /^-\d+$/;
//整数正则
var intPattern = /^-?\d+$/;
//输出 true
console.log(posPattern.test("42"));
//输出 true
console.log(negPattern.test("-42"));
//输出 true
console.log(intPattern.test("-42"));

4. 数字正则

可以是整数也可以是浮点数

//正数正则
var posPattern = /^\d*\.?\d+$/;
//负数正则
var negPattern = /^-\d*\.?\d+$/;
//数字正则
var numPattern = /^-?\d*\.?\d+$/;
console.log(posPattern.test("42.2"));
console.log(negPattern.test("-42.2"));
console.log(numPattern.test("-42.2"));

5. Email正则

//Email正则
var ePattern = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
//输出 true
console.log(ePattern.test(<a href="mailto:65974040@qq.com">65974040@qq.com</a>));

6. 手机号码正则

//手机号正则
var mPattern = /^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\d{8}$/;
//输出 true
console.log(mPattern.test("18600000000"));

7. 身份证号正则

//身份证号(18位)正则
var cP = /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/;
//输出 true
console.log(cP.test("11010519880605371X"));

8. URL正则

((http|ftp|https)://)(([a-zA-Z0-9\._-]+\.[a-zA-Z]{2,6})|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,4})*(/[a-zA-Z0-9\&%_\./-~-]*)?
赤:协议
橙:字母host,前半部分(+号及以前)host、二级域名,后半部分表示一定有类似.cn、.com、.net的跟在后面
黄:域名
绿:IP host,可以进一步简化([0-9]{1,3}(\.[0-9]{1,3}){3})
橙、绿组合成hostname
青:端口
蓝:/path及后面内容,第一个/匹配host后紧跟的斜杠,host后可能有 / ,/ 后可能还有n多字符,当然,也可能没有了。最后四个字符/-~-有些问题,/的ASCII码为47,~的为126,(ASCII码表)这之间包括了数字、大小写字母(与前面的重复),还有些如<>=?{},这些在正常的url中也会被编码的,不会出现在url中,中括号中的 - 如果不成组就表示 - 字符(一般放在中括号两边或加转义)
容易理解,可以满足大部分需求,不能匹配url+锚点、ftp有user:pass@host的情况

9. IPv4地址正则

//ipv4地址正则
var ipP = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
//输出 true
console.log(ipP.test("115.28.47.26"));

10. 十六进制颜色正则

//RGB Hex颜色正则
var cPattern = /^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/;
//输出 true
console.log(cPattern.test("#b8b8b8"));

11. 日期正则

//日期正则,简单判定,未做月份及日期的判定
var dP1 = /^\d{4}(\-)\d{1,2}\1\d{1,2}$/;
//输出 true
console.log(dP1.test("2017-05-11"));
//输出 true
console.log(dP1.test("2017-15-11"));
//日期正则,复杂判定
var dP2 = /^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$/;
//输出 true
console.log(dP2.test("2017-02-11"));
//输出 false
console.log(dP2.test("2017-15-11"));
//输出 false
console.log(dP2.test("2017-02-29"));

12. QQ号码正则

//QQ号正则,5至11位
var qqPattern = /^[1-9][0-9]{4,10}$/;
//输出 true
console.log(qqPattern.test("65974040"));

13. 微信号正则

//微信号正则,6至20位,以字母开头,字母,数字,减号,下划线
var wxPattern = /^[a-zA-Z]([-_a-zA-Z0-9]{5,19})+$/;
//输出 true
console.log(wxPattern.test("RuilongMao"));

14. 车牌号正则

//车牌号正则
var cPattern = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$/;
//输出 true
console.log(cPattern.test("京K39006"));

15. 包含中文正则

//包含中文正则
var cnPattern = /[\u4E00-\u9FA5]/;
//输出 true
console.log(cnPattern.test("42度"));

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值