发送注册验证码
* 验证码需求:
* 1.后台随机产生4个字符
* 2.1分钟以内只能发送1次验证码
* 3.超过1分钟,但在5分钟以内,发送的验证码依然是第一次产生的验证码字符
* 4.超过了5分钟以后,产生全新的验证码
*
前端使用什么框架先不管
依赖配置
短信依赖包 redis配置,因为验证码和手机号存储在redis中
短信平台使用的建网 sms ,http://www.smschinese.cn/ 可以免费使用5条 测试即可
注意 配置接口的 账户名 和 密钥 每个人是不同的,复制过去记得更改
短信签名必须要设置,不能乱设 会被屏蔽短信发不出来 切记
短信依赖包

<!--短信jar包-->
        <dependency>
            <groupId>commons-httpclient</groupId>
            <artifactId>commons-httpclient</artifactId>
            <version>3.1</version>
        </dependency>

redis jar包

<!--redis jar 包-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

使用redis前,要先配置连接,在application.properties配置,记得开启redis-server

# redis 属性信息
## redis数据库索引(默认为0)
spring.redis.database=0
## redis服务器地址
spring.redis.host=localhost
## redis服务器连接端口
spring.redis.port=6379
## redis服务器连接密码(默认为空)
## spring.redis.password=123456
## 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=8
## 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=8
## 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=-1ms
## 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=0

创建一个工具类 StrUtils.getComplexRandomString ()// 获取随机字符 位数自己输入

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * @author yaohuaipeng
 * @date 2018/10/26-16:16
 */
public class StrUtils {
    /**
     * 把逗号分隔的字符串转换字符串数组
     *
     * @param str
     * @return
     */
    public static String[] splitStr2StrArr(String str,String split) {
        if (str != null && !str.equals("")) {
            return str.split(split);
        }
        return null;
    }


    /**
     * 把逗号分隔字符串转换List的Long
     *
     * @param str
     * @return
     */
    public static List<Long> splitStr2LongArr(String str) {
        String[] strings = splitStr2StrArr(str,",");
        if (strings == null) return null;

        List<Long> result = new ArrayList<>();
        for (String string : strings) {
            result.add(Long.parseLong(string));
        }

        return result;
    }
    /**
     * 把逗号分隔字符串转换List的Long
     *
     * @param str
     * @return
     */
    public static List<Long> splitStr2LongArr(String str,String split) {
        String[] strings = splitStr2StrArr(str,split);
        if (strings == null) return null;

        List<Long> result = new ArrayList<>();
        for (String string : strings) {
            result.add(Long.parseLong(string));
        }

        return result;
    }

    public static String getRandomString(int length) {
        String str = "0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(10);
            sb.append(str.charAt(number));
        }
        return sb.toString();

    }

    public static String getComplexRandomString(int length) {
        String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(62);
            sb.append(str.charAt(number));
        }
        return sb.toString();
    }

    public static String convertPropertiesToHtml(String properties){
        //1:容量:6:32GB_4:样式:12:塑料壳
        StringBuilder sBuilder = new StringBuilder();
        String[] propArr = properties.split("_");
        for (String props : propArr) {
            String[] valueArr = props.split(":");
            sBuilder.append(valueArr[1]).append(":").append(valueArr[3]).append("<br>");
        }
        return sBuilder.toString();
    }

}

创建短信发送类 配置接口,其它类调用这个类的send方法传入手机号和发送内容即可

import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.PostMethod;

import java.io.IOException;

public class SendMsgUtils {
    private static final String UID = "amazingwest";//这是建网SMS 上的登陆账号
    private static final String KEY = "d41d8cd98f00b204e980"; //这是密钥

    /**
     * 手机发送短信
     * @param phone  手机号码
     * @param context  发送短信内容
     */
    public static void send(String phone, String context) {

        PostMethod post = null;
        try {
            //创建Http客户端
            HttpClient client = new HttpClient();
            //创建一个post方法
            post = new PostMethod("http://utf8.api.smschinese.cn");
            //添加请求头信息
            post.addRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf8");//在头文件中设置转码

            NameValuePair[] data = {new NameValuePair("Uid", UID),
                    new NameValuePair("Key", KEY),
                    new NameValuePair("smsMob", phone),
                    new NameValuePair("smsText", context)};
            //设置请求体
            post.setRequestBody(data);
            //执行post方法
            client.executeMethod(post);

            //获取响应头信息
            Header[] headers = post.getResponseHeaders();
            //获取状态码
            int statusCode = post.getStatusCode();
            System.out.println("statusCode:" + statusCode);
            //循环打印头信息
            for (Header h : headers) {
                System.out.println(h.toString());
            }
            //获取相应体
            String result = new String(post.getResponseBodyAsString().getBytes("utf8"));
            System.out.println(result); //打印返回消息状态

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (post != null) {
                //关闭资源
                post.releaseConnection();
            }
        }
    }


}

创建注册常量类,主要用来区分验证码是用来注册还是登陆或者找回密码,

/**
 * 验证码常量
 */
public class VerificationConstant {

    //用户注册常量
    public static final String USER_REG = "user_reg";
}

前台点击发送验证码 首先要考虑多个用户同时注册,key值不能写死

首先根据手机号加注册标识(KEY)判断redis中值value是否存在,不存在就创建一个键,key为手机号+加注册标识,
判断时间,就是创建redis键值对的时候就,value会加上一个当前时间戳,取value第一次创建的时间会分割value 拿当前时间戳减去第一次创建的时间戳就能得出具体的时间
第一次创建键值 设置键的存活时间为5分钟 300秒
发送验证码短信,前端传来手机号码,在这里进行业务逻辑判断 不需要判断手机号是否注册,这是其它类的事情 使用redisTemplate 就必须得 引入redis jar包
StrUtils.getComplexRandomString(4) 这就是上面创建的工具类中的一个方法,创建4位字符的随机数,
StringUtils.isEmpty 是 import org.springframework.util.StringUtils 别弄错了

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

@Service
public class VerificationCodeServiceImpl implements IVerificationCodeService {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 发送注册验证码
     * 验证码需求:
     *      1.后台随机产生4个字符
     *      2.1分钟以内只能发送1次验证码
     *      3.超过1分钟,但在5分钟以内,发送的验证码依然是第一次产生的验证码字符
     *      4.超过了5分钟以后,产生全新的验证码
     * @return
     */
    @Override
    public void sendRegisterVerificationCode(String phone) throws CustomException {
        //随机产生4个字符
        String value = StrUtils.getComplexRandomString(4);
        //在redis中通过key获取对应的值        value:时间戳
        String valueCode = (String) redisTemplate.opsForValue().get(phone + ":" + VerificationConstant.USER_REG);
        //如果不为空,就意味着验证码没有过期,依然是在5分钟以内
        if(!StringUtils.isEmpty(valueCode)){
            //开始时间戳
            String beginTimer = valueCode.split(":")[1];

            if(System.currentTimeMillis()-Long.valueOf(beginTimer)<=60*1000){
               //自定义异常,自己创建一个就可以了
                throw new CustomException("亲!一分钟以内不能发送多次验证码!!");
            }
            //证明是超过了1分钟,但依然在5分钟以内,还是用之前的验证码
            value = valueCode.split(":")[0];
        }
        //存储redis中,设置有效期是5分钟  k=phone:USER_REG  v= value:时间戳
//        RedisUtil.set(phone:USER_REG,  value:System.currentTimeMillis(),  5MIN);
        redisTemplate.opsForValue().set(phone + ":" + VerificationConstant.USER_REG,
                value + ":" + System.currentTimeMillis(), 5, TimeUnit.MINUTES);
        //发送手机验证码
        String context = "尊敬的用户,您的验证码为:" + value + ",请您在5分钟以内完成注册!!";
        //发送短信
//        SendMsgUtils.send(phone, context);
        System.out.println(context);


    }
}

短信发送后返回值 说 明
-1 没有该用户账户
-2 接口密钥不正确 [查看密钥]
不是账户登陆密码
-21 MD5接口密钥加密不正确
-3 短信数量不足
-11 该用户被禁用
-14 短信内容出现非法字符
-4 手机号格式不正确
-41 手机号码为空
-42 短信内容为空
-51 短信签名格式不正确
接口签名格式为:【签名内容】
-52 短信签名太长
建议签名10个字符以内
-6 IP限制
大于0 短信发送数量
大功告成