043 用户注册功能03--Redis安装及完成短信发送功能

1.Redis安装

(1)下载地址:https://github.com/MicrosoftArchive/redis/releases/tag/win-3.2.100   ( redis官网: https://redis.io/  )

(2)安装步骤,下一步下一步,有选择框选中即可。

 (3)安装完成配置:E:\toolsoftware\redis

设置 redis密码  :  requirepass 123456  (我的是 123456)

(4)右击此电脑---》管理

(5)window + R  输入  cmd    ===>  cd  E:\Program Files\Redis    ===>   redis-cli    =====>  auth 123456

2.Spring Data Redis

(1)介绍

官网:http://projects.spring.io/spring-data-redis/

Spring Data Redis,是Spring Data 家族的一部分。 对Jedis客户端进行了封装,与spring进行了整合。可以非常方便的来实现redis的配置和操作。

(2)RedisTemplate基本操作

Spring Data Redis 提供了一个工具类:RedisTemplate。里面封装了对于Redis的五种数据结构的各种操作,包括:

  • redisTemplate.opsForValue() :操作字符串

  • redisTemplate.opsForHash() :操作hash

  • redisTemplate.opsForList():操作list

  • redisTemplate.opsForSet():操作set

  • redisTemplate.opsForZSet():操作zset

其它一些通用命令,如expire,可以通过redisTemplate.xx()来直接调用

5种结构:

  • String:等同于java中的,Map<String,String>

  • list:等同于java中的Map<String,List<String>>

  • set:等同于java中的Map<String,Set<String>>

  • sort_set:可排序的set

  • hash:等同于java中的:`Map<String,Map<String,String>>

(3)StringRedisTemplate

RedisTemplate在创建时,可以指定其泛型类型:

  • K:代表key 的数据类型

  • V: 代表value的数据类型

注意:这里的类型不是Redis中存储的数据类型,而是Java中的数据类型,RedisTemplate会自动将Java类型转为Redis支持的数据类型:字符串、字节、二进制等等。

因为大部分情况下,我们都会使用key和value都为String的RedisTemplate,因此Spring就默认提供了这样一个实现:

 

(4)测试

我们在项目中编写一个测试案例,把课前资料中的redisTest.java导入到项目中

需要在项目中引入Redis启动器:

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

然后在配置文件中指定Redis地址:

spring:
redis:
host: 127.0.0.1
password: 123456

测试类:

package lucky.leyou.user;

import lucky.leyou.LeyouUserApplication;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Map;
import java.util.concurrent.TimeUnit;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = LeyouUserApplication.class)
public class RedisTest {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Test
    public void testRedis() {
        // 存储数据
        this.redisTemplate.opsForValue().set("name", "lucky");
        // 获取数据
        String val = this.redisTemplate.opsForValue().get("name");
        System.out.println("name = " + val);
    }

    @Test
    public void testRedis2() {
        // 存储数据,并指定剩余生命时间,5小时
        this.redisTemplate.opsForValue().set("key2", "value2",
                5, TimeUnit.HOURS);
    }

    @Test
    public void testHash() {
        BoundHashOperations<String, Object, Object> hashOps =
                this.redisTemplate.boundHashOps("user");
        // 操作hash数据
        hashOps.put("name", "jack");
        hashOps.put("age", "21");

        // 获取单个数据
        Object name = hashOps.get("name");
        System.out.println("name = " + name);

        // 获取所有数据
        Map<Object, Object> map = hashOps.entries();
        for (Map.Entry<Object, Object> me : map.entrySet()) {
            System.out.println(me.getKey() + " : " + me.getValue());
        }
    }
}

控制台输出:

3.完成短信发送功能 

根据用户输入的手机号,生成随机验证码,长度为6位,纯数字。并且调用短信服务,发送验证码到用户手机。

接口路径:

POST /code

参数说明:

返回结果:

状态码:

  • 204:请求已接收

  • 400:参数有误

  • 500:服务器内部异常

这里的业务逻辑是这样的:

  • 1)我们接收页面发送来的手机号码

  • 2)生成一个随机验证码

  • 3)将验证码保存在服务端

  • 4)发送短信,将验证码发送到用户手机

 (1)环境配置

需要三个步骤:

  • 生成随机验证码

  • 将验证码保存到Redis中,用来在注册的时候验证

  • 发送验证码到leyou-sms-service服务,发送短信

因此,我们需要引入Redis和AMQP:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

添加RabbitMQ和Redis配置:

spring:
  redis:
    host: 127.0.0.1
    password: 123456
  rabbitmq:
      host: 127.0.0.1
      username: guest
      password: guest
      virtual-host: /

另外还要用到工具类,生成6位随机码,这个我们封装到了leyou-common中,因此需要引入依赖:

        <dependency>
            <groupId>lucky.leyou.common</groupId>
            <artifactId>leyou-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

NumberUtils中有生成随机码的工具方法:

package lucky.leyou.common.utils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author: HuYi.Zhang
 * @create: 2018-04-25 09:13
 **/
public class NumberUtils {

    public static boolean isInt(Double num) {
        return num.intValue() == num;
    }

    /**
     * 判断字符串是否是数值格式
     * @param str
     * @return
     */
    public static boolean isDigit(String str){
        if(str == null || str.trim().equals("")){
            return false;
        }
        return str.matches("^\\d+$");
    }

    /**
     * 将一个小数精确到指定位数
     * @param num
     * @param scale
     * @return
     */
    public static double scale(double num, int scale) {
        BigDecimal bd = new BigDecimal(num);
        return bd.setScale(scale, RoundingMode.HALF_UP).doubleValue();
    }

    // 从字符串中根据正则表达式寻找,返回找到的数字数组
    public static Double[] searchNumber(String value, String regex){
        List<Double> doubles = new ArrayList<>();
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(value);
        if(matcher.find()) {
            MatchResult result = matcher.toMatchResult();
            for (int i = 1; i <= result.groupCount(); i++) {
                doubles.add(Double.valueOf(result.group(i)));
            }
        }
        return doubles.toArray(new Double[doubles.size()]);
    }

    /**
     * 生成指定位数的随机数字
     * @param len
     * @return
     */
    public static String generateCode(int len){
        len = Math.min(len, 8);
        int min = Double.valueOf(Math.pow(10, len - 1)).intValue();
        int num = new Random().nextInt(Double.valueOf(Math.pow(10, len + 1)).intValue() - 1) + min;
        return String.valueOf(num).substring(0,len);
    }
}

(2)controller

在leyou-user-service工程中的UserController添加方法:

/**
 * 发送手机验证码
 * @param phone
 * @return
 */
@PostMapping("code")
public ResponseEntity<Void> sendVerifyCode(String phone) {
    Boolean boo = this.userService.sendVerifyCode(phone);
    if (boo == null || !boo) {
        return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
    }
    return new ResponseEntity<>(HttpStatus.CREATED);
}

(3)service

在UserService中添加代码:

package lucky.leyou.user.service;

import lucky.leyou.common.utils.NumberUtils;
import lucky.leyou.user.domain.User;
import lucky.leyou.user.mapper.UserMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private AmqpTemplate amqpTemplate;

    static final String KEY_PREFIX = "user:code:phone:";

    static final Logger logger = LoggerFactory.getLogger(UserService.class);

    /**
     * 实现用户数据的校验,主要包括对:手机号、用户名的唯一性校验。
     * @param data 占位符参数
     * @param type
     * @return
     */
    public Boolean checkUser(String data, Integer type) {
        User record = new User();
        switch (type) {
            case 1:
                record.setUsername(data);
                break;
            case 2:
                record.setPhone(data);
                break;
            default:
                return null;
        }
        return this.userMapper.selectCount(record) == 0;
    }

    /**
     * 给指定的手机号发送验证码
     * @param phone 待发送验证码的手机号
     * @return
     */
    public Boolean sendVerifyCode(String phone) {
        // 生成验证码
        String code = NumberUtils.generateCode(6);
        try {
            // 发送短信
            Map<String, String> msg = new HashMap<>();
            msg.put("phone", phone);
            msg.put("code", code);
            //给rabbitmq的消息队列发送消息
            this.amqpTemplate.convertAndSend("leyou.sms.exchange", "sms.verify.code", msg);
            // 将code存入redis
            this.redisTemplate.opsForValue().set(KEY_PREFIX + phone, code, 5, TimeUnit.MINUTES);
            return true;
        } catch (Exception e) {
            logger.error("发送短信失败。phone:{}, code:{}", phone, code);
            return false;
        }
    }
}

注意:要设置短信验证码在Redis的缓存时间为5分钟

(4)测试

 redis中查询缓存数据:

猜你喜欢

转载自www.cnblogs.com/luckyplj/p/11626631.html