短信微服务+springboot+redis整合,动态获取短信验证码

现在基本上好多前端网页都可以通过短信验证码来动态登录页面,那接下来就说一说这个业务流程,用到的技术包括springboot、redis等

那接下来就开始吧!

一、SpringBoot项目搭建

        首先在IDEA中创建一个空项目,类似于Eclipse中的工作空间,然后在这个空项目中创建module项目,

        

        然后傻瓜式下一步

        

        然后下一步

        

        继续下一步,勾选出需要的依赖:

        

        继续下一步,finish完成项目搭建

        

二、确保Linux中的redis中是开启状态

        开启虚拟机中的redis,然后安装redis的时候,记得把redis.conf中的bind改为0.0.0.0,不然可能会有拒绝客户端访问的情况

        然后启动redis,启动的时候,找到安装redis的bin目录,启动指令:./redis-server redis.conf

        开启后的状态是如图所示:

        如果是后台开启redis,则可以通过下面质量来查看redis是否是已启动状态:ps -aux | grep redis 

        redis准备就绪,然后开始写相关代码!

三、配置springboot的pom.xml和application.properties相关配置文件

    1.配置pom.xml文件中的依赖和插件

            楼主用到的依赖如下,其实用来生成mapper和dao层的逆向工程的mybatis的generator可以不用配置,楼主是为了以后和数据库做联系而准备的,可加可不加

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-core</artifactId>
            <version>4.0.6</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
            <version>1.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.5</version>
                <configuration>
                    <verbose>true</verbose>
                    <overwrite>true</overwrite>
                </configuration>
            </plugin>
        </plugins>
    </build>

     2.配置application.properties配置文件

            数据库驱动和扫描映射文件的配置可以选择忽略,因为本文中并没有和数据库关联,主要是redis的host和port,保证本机和redis之间是可以ping通的:

#数据库驱动配置
spring.datasource.url=jdbc:mysql://localhost:3306/sms?characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=123456

#扫描映射文件
mybatis.mapper-locations=classpath:mapper/*Mapper.xml

#redis配置
spring.redis.host=192.168.43.233
spring.redis.port=6379

  三、Redis的接口和相关实现类

           1.redis接口

           话不多说,直接上代码

public interface MyRedis {

    public void set(String key,String value);

    public void set(String key,String value,int timeout);

    public String get(String key);

    public void del(String key);

    public Long incr(String key);

    public Long decr(String key);

    public void setExp(String key,int seconds);

    public Long getExp(String key);

    public void lpush(String key,Object value);

    public Object rpop(String key);

    public void hset(String key,String item,String value);

    public String hget(String key,String item);

    public void hdel(String key,String item);
}

相关实现类:

@Service
public class MyRedisImpl implements MyRedis {

    @Autowired
    private StringRedisTemplate template;

    @Override
    public void set(String key, String value) {
        ValueOperations<String, String> operations = template.opsForValue();
        operations.set(key,value);
    }

    @Override
    public void set(String key, String value, int timeout) {
        ValueOperations<String, String> operations = template.opsForValue();
        operations.set(key,value,timeout,TimeUnit.SECONDS);
    }

    @Override
    public String get(String key) {
        ValueOperations<String, String> operations = template.opsForValue();
        return operations.get(key);
    }

    @Override
    public void del(String key) {
        template.delete(key);
    }

    @Override
    public Long incr(String key) {
        ValueOperations<String, String> operations = template.opsForValue();
        Long increment = operations.increment(key,1);
        return increment;
    }

    @Override
    public Long decr(String key) {
        ValueOperations<String, String> operations = template.opsForValue();
        Long increment = operations.increment(key,-1);
        return increment;
    }

    @Override
    public void setExp(String key, int seconds) {
        template.expire(key,seconds,TimeUnit.SECONDS);
    }

    @Override
    public Long getExp(String key) {
        Long expire = template.getExpire(key);
        return expire;
    }

    @Override
    public void lpush(String key, Object value) {
        ListOperations list = template.opsForList();
        list.leftPush(key,value);
    }

    @Override
    public Object rpop(String key) {
        ListOperations opsForList = template.opsForList();
        return opsForList.rightPop(key);
    }

    @Override
    public void hset(String key, String item, String value) {
        HashOperations<String, Object, Object> opsForHash = template.opsForHash();
        opsForHash.put(key,item,value);
    }

    @Override
    public String hget(String key, String item) {
        HashOperations opsForHash = template.opsForHash();
        return (String) opsForHash.get(key,item);
    }

    @Override
    public void hdel(String key, String item) {
        HashOperations opsForHash = template.opsForHash();
        opsForHash.delete(key,item);
    }
}

四、控制层实现业务逻辑

我借用的是美团的首页,仅仅做学习使用,侵权立删

首先把相关的静态资源配置在resources下的static和templates中

然后根据前端对应的点击触发事件写出相应的控制层业务逻辑

    1.获取手机动态验证码的controller层

            这里会用到阿里提供的短信接口,同时需要配置相关的ID和密匙

            还有验证码的工具类(当然你也可以选择自己手写):

         一切准备就绪,然后开始写相关的action,首先先来写ajax中的url:"ajaxNum",导包的时候注意别导错包,一般都是aliyun的包

@Controller
public class SmsAction {
    //注入redis服务
    @Autowired
    private MyRedis myRedis;

    //登录页面
    @RequestMapping("/mt")
    public String shouUI(){
        return "mtlogin";
    }

    @ResponseBody
    @RequestMapping("/ajaxNum")
    public String sendMsg(String phoneNum) throws Exception{
        //设置超时时间-可自行调整
        System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
        System.setProperty("sun.net.client.defaultReadTimeout", "10000");
//初始化ascClient需要的几个参数
        final String product = "Dysmsapi";//短信API产品名称(短信产品名固定,无需修改)
        final String domain = "dysmsapi.aliyuncs.com";//短信API产品域名(接口地址固定,无需修改)
//替换成你的AK
        final String accessKeyId = AliAccessKey.accessKeyId;//你的accessKeyId,参考本文档步骤2
        final String accessKeySecret = AliAccessKey.accessKeySecret;//你的accessKeySecret,参考本文档步骤2
//初始化ascClient,暂时不支持多region(请勿修改)
        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId,
                accessKeySecret);
        DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
        IAcsClient acsClient = new DefaultAcsClient(profile);
        //组装请求对象
        SendSmsRequest request = new SendSmsRequest();
        //使用post提交
        request.setMethod(MethodType.POST);
        //必填:待发送手机号。支持以逗号分隔的形式进行批量调用,批量上限为1000个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式;发送国际/港澳台消息时,接收号码格式为国际区号+号码,如“85200000000”
        request.setPhoneNumbers(phoneNum);
        //必填:短信签名-可在短信控制台中找到
        request.setSignName("xxx");
        //必填:短信模板-可在短信控制台中找到,发送国际/港澳台消息时,请使用国际/港澳台短信模版
        request.setTemplateCode("xxxxxxxxxx");
        //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
        //友情提示:如果JSON中需要带换行符,请参照标准的JSON协议对换行符的要求,比如短信内容中包含\r\n的情况在JSON中需要表示成\\r\\n,否则会导致JSON在服务端解析失败
        //生成6位的动态验证码
        String numeric = RandomStringTLUtils.randomNumeric(6);
        request.setTemplateParam("{\"code\":\""+numeric+"\"}");
        //可选-上行短信扩展码(扩展码字段控制在7位或以下,无特殊需求用户请忽略此字段)
        //request.setSmsUpExtendCode("90997");
        //可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
        request.setOutId("yourOutId");

//        //请求失败这里会抛ClientException异常
//        SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
//        if(sendSmsResponse.getCode() != null && sendSmsResponse.getCode().equals("OK")) {
//            //请求成功
//            myRedis.set("sms_"+phoneNum,numeric,120);
//             return numeric;
//        }else {
//            System.out.println("失败状态"+sendSmsResponse.getCode());
//            System.out.println("失败原因"+sendSmsResponse.getMessage());
//            return "error";
//        }
//
//        //发送成功,存储到缓存

        myRedis.set("sms_"+phoneNum,numeric,120);

        return numeric;
    }


}

上图中有一部分注掉的,楼主为了省钱做测试用注掉了:

这中间可以打几个断点自己跑一下debug看一下每一步的数据是否有误,然后运行结束后,可以看到相关的验证码出现在网页前端,然后可以点解登录,这时候,开始写登录触发的action,我这里是给用户三次错误的机会,三次机会之前都可以重新输入验证码重新登录,你可以在将验证码存储到redis的时候设置该验证码的过期时间,过期以后会自动清除该验证码。我设置的是1分钟。三次错误以后将会清除与该用户相关的所有缓存,并给用户提示,我只是做的测试用,所以并没有把错误页面做的有多好,仅供参考:

@Controller
public class VerfiyAction {
    //注入redis服务
    @Autowired
    private MyRedis redis;

    @RequestMapping("/verfiy")
    public ModelAndView login(HttpServletRequest request){

        ModelAndView modelAndView = new ModelAndView();
        //获取用户输入的手机号和验证码
        String phoneNum = request.getParameter("mobile"); //客户端用户输入的手机号
        String code = request.getParameter("code"); //客户端用户输入的验证码

        //获取redis中存放的验证码
        String redisCode = redis.get("sms_"+phoneNum);

        if(code!=null && !"".equals(code)){
            //如果用户输入的验证码和生成的验证码保持一致
            if(code.equals(redisCode)){
                //删除redis中存放的验证码缓存
                redis.del("sms_"+phoneNum);
                //同时删除redis中存放的用户输入验证码的错误次数
                redis.del("error_"+phoneNum);
                modelAndView.setViewName("index");
            }else {
                //如果验证失败  给该用户总共三次输入机会,大于三次重新获取验证码
                //如果是第一次错误,则第一次给用户创建错误次数并存放于redis中,每次错误都会在原有的键上对其值+1
                Long incr = redis.incr("error_"+phoneNum);
                if (incr > 3){  //如果用户错误的次数大于三次
                    //清除旧的验证码
                    redis.del("sms_"+phoneNum);
                    //清除redis中存放的用户输入验证码的错误次数
                    redis.del("error_"+phoneNum);
                    modelAndView.addObject("error","超过验证码错误次数,请重新获取验证码!");
                    modelAndView.setViewName("error");
                }else { //如果用户输入错误且错误小于3次 则刷新一次页面用户继续输入
                    modelAndView.setViewName("mtlogin");
                }

            }
        }


        return modelAndView;

    }
}

以上就是单个redis服务器的短信微服务,仅供参考,若有不足之处欢迎指出!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值