1、短信\图片验证码

有3种模型:

  • 输入图片验证码:前端自己生成UUID -> Java Redis存储key=UUID,value=随机生成的验证码
  • 短信验证码:前端输入手机号 -> Java Redis存储key=手机号,value=随机生成的验证码
  • 图片验证码输入后,获取短信验证码:前端传递自己生成的UUID 与手机号 -> Java Redis存储key是手机号:UUID,value=随机生成的验证码

UUID的作用是:确保是某一个客户端生成的。不会有设备A获取的验证码,在设备B可以使用!

Redis的使用String命令即可

    @Test
    public void 获取验证码() {
        String 给前端的UUID = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set("验证码:登录:"+给前端的UUID,"1234");
        // 返回给前端一个UUID,用于后期校验使用
    }
    
    @Test
    public void 校验验证码(){
        String uuid = "前端给的UUID";
        String 用户输入的验证码 = "1234";
        Object object = redisTemplate.opsForValue().get("验证码:登录:" + uuid);
        if (object != null){
            boolean ok = StringUtils.endsWithIgnoreCase(用户输入的验证码, object.toString());
            if (ok){
                System.out.println("校验成功");
            }else{
                System.out.println("校验失败");
            }
        }
    }

2、登录成功后

Redis的Hash命令,存储key="login:success:740969606",field="token",value=用户Token,也可记录一些用户的信息,如会员到期时间等

3、前端登录

axios有请求拦截器,在请求发起前,在请求头添加Token即可。

// 添加请求拦截器
axios.interceptors.request.use(
    function (config) {
        do......
        // 在发送请求之前进行操作
        return config;
    },
    function (error) {
        do......
        // 对请求错误进行操作
        return Promise.reject(error);
    }
);

// 添加响应拦截器
axios.interceptors.response.use(
    function (response) {
        // 对响应数据进行操作
        return response;
    },
    function (error) {
        // 对响应错误进行操作
        return Promise.reject(error);
    }
);

4、点赞功能

利用Redis set命令。有序、不重复特性。如果要点赞,sismember 判断是否已点赞。

    @Test
    public void 点赞() {
        Boolean member = redisTemplate.opsForSet().isMember("朋友圈1", "张三");
        if (Boolean.FALSE.equals(member)){
            Long 用户已点赞 = redisTemplate.opsForSet().add("朋友圈1", "张三", System.currentTimeMillis());
        }else {
            Long 用户已经取消点赞 = redisTemplate.opsForSet().remove("朋友圈1", "张三");
        }
    }

5、时间降序展示XX排行榜

4号方案set命令就不是很合适了,使用zset实现。zset存储结构有分数,我们设定为时间戳。zrange查询zrange key 1 4即可得到前5的id

    @Test
    public void 添加薪水数据() throws InterruptedException {
        redisTemplate.opsForZSet().add("薪水", "张三", 3000);
        redisTemplate.opsForZSet().add("薪水", "李四", 4000);
        redisTemplate.opsForZSet().add("薪水", "王五", 3000);
        redisTemplate.opsForZSet().add("薪水", "赵六", 8000);
        redisTemplate.opsForZSet().add("薪水", "老八", 6000);
    }

    @Test
    public void 点赞薪水数据排行() {
        Set 升序前4个排名用户姓名集合 = redisTemplate.opsForZSet().range("薪水", 0, 3);
        Set 升序全部的用户姓名集合 = redisTemplate.opsForZSet().range("薪水", 0, -1);
        Set 降序全部的用户姓名集合 = redisTemplate.opsForZSet().reverseRange("薪水", 0, -1);
        Long 某薪水段有多少人 = redisTemplate.opsForZSet().count("薪水", 4000, 6000);
        Long 升序排名第二的薪水 = redisTemplate.opsForZSet().rank("薪水", 1);
        Long 总人数 = redisTemplate.opsForZSet().size("薪水");
        Double 给老八加1薪水 = redisTemplate.opsForZSet().incrementScore("薪水", "老八", 1d);
        Long 删除用户数量 = redisTemplate.opsForZSet().remove("薪水", "赵六","王五");
        Boolean 添加结果1 = redisTemplate.opsForZSet().add("薪水", "赵六", 8000);
        Boolean 添加结果2 = redisTemplate.opsForZSet().add("薪水", "王五", 3000);
    }

我们能拿到用户的id集合,比如,1,3,5,2

sql = select * from user_info where id in(1,3,5,2) 这样的结果是无序的

我们要做的就是改造 sql = select * from user_info where user_account in(1,3,5,2) order by field(user_account,1,3,5,2) 这样就是有序的了!

6、共同好友:采用set吧

    @Test
    public void 构造好友关系() throws InterruptedException {
        redisTemplate.opsForSet().add("张三的好友", "AAA","李四","王五");
        redisTemplate.opsForSet().add("李四的好友", "AAA","张三","赵六");
    }
    @Test
    public void 好友关系() {
        Set 共同好友 = redisTemplate.opsForSet().intersect("李四的好友", "张三的好友"); // AAA
        // 需要手动在集合删除2人本身才能得到共同好友
        Set 张三比李四多的好友 = redisTemplate.opsForSet().difference("张三的好友", "李四的好友"); // 李四、王五
    }

7、feed实现用户推送 Redis做朋友圈id暂存-数据真实存储在MongoDB方案

本Redis方案有重大BUG产生,勿用。如果scope不允许相同,则可以随意使用(案例代码有描述)

这类使用场景,往往是类似于朋友圈的功能。用户B关注A,C没关注A,那么用户A发送朋友圈,需要主动推送到B的消息邮箱中。常见模式有:

:推送给所有关注发送者的人。 缺点:太占用缓存

:用户遍历所有关注的人,从所有人最新的消息汇总合并。缺点:单次操作复杂,太伤sql,维护性较大

混合模式:用户大V发送的朋友圈,使用推模式,普通人的发送的朋友圈,使用拉模式。缺点:维护性太大

底层实现方式是:Zset集合 key=用户id,value=朋友圈id,scope=朋友圈发送的时间。这样每个用户的朋友圈本身就是根据朋友圈时间倒叙!

    @Test
    public void 添加消息至暂存箱() {
        redisTemplate.opsForZSet().add("朋友圈:张三的消息暂存箱", "文章id:001", 1);
        redisTemplate.opsForZSet().add("朋友圈:张三的消息暂存箱", "文章id:002", 2);
        redisTemplate.opsForZSet().add("朋友圈:张三的消息暂存箱", "文章id:003", 3);
        redisTemplate.opsForZSet().add("朋友圈:张三的消息暂存箱", "文章id:004", 4);
        redisTemplate.opsForZSet().add("朋友圈:张三的消息暂存箱", "文章id:005", 5);
    }

    // 本方案不允许相同scope,如果相同直接跳过,
    @Test
    public void 读取消息暂存箱() {
        redisTemplate.opsForZSet().remove("朋友圈:张三的消息暂存箱", "文章id:006");
        int max = 1000000; // 这个本应该是时间戳。当前时间戳是就是现在朋友圈发布时间最大的,这里我模拟最大为 1000000
        int pageSize = 3; // 这个固定需要与前端沟通好,能否随意变化尚未测试!
        int offset = 0; // 偏移量:本质就是跳过重复的内容
        Set<ZSetOperations.TypedTuple> 第一次结果 = redisTemplate.opsForZSet()
                .reverseRangeByScoreWithScores("朋友圈:张三的消息暂存箱", 0, max, offset, pageSize);

        int 第二次最大值 = 0; // 第二次查询需要跳过一条:根据时间倒叙,第二次查询的时候,最大时间就是第一次查询的最小时间,所以最小跳过1次(如果时间一样,还有好几个,那么都需要跳过就不在是1了)。
        for (ZSetOperations.TypedTuple typedTuple : 第一次结果) {
            System.out.printf(typedTuple.getValue().toString());
            if (第二次最大值 == typedTuple.getScore().intValue()) {
                offset++;
            } else {
                第二次最大值 = typedTuple.getScore().intValue();
                offset = 1;
            }
        }
        max = 第二次最大值;
        Boolean 插入一个同等分数的以影响结果 = redisTemplate.opsForZSet().add("朋友圈:张三的消息暂存箱", "文章id:006", 3);
        Set<ZSetOperations.TypedTuple> forDEBUG = redisTemplate.opsForZSet()
                .reverseRangeByScoreWithScores("朋友圈:张三的消息暂存箱", 0, 10000, 0, 100);
        Set 第二页结果 = redisTemplate.opsForZSet()
                .reverseRangeByScoreWithScores("朋友圈:张三的消息暂存箱", 0, max, offset, pageSize);
        System.out.println("请在本行DEBUG以便于发现问题 第一次结果是005 004 003,第二次结果是003 002 001。本被吞掉的006 以证明本方案不适合重复时间戳分页!");
        System.out.println("这里需要返回给前端max,offset下一次跳过的个数,以便于第二次查询使用");
    }

可用方案参考:https://www.zanglikun.com/12708.html

8、BitMap 用户签到

先了解位运算基本规则,然后再去看本博客文章:https://www.zanglikun.com/5294.html

我们也可以完全实现对一个数字 来识别用户的多种功能!

9、缓存

请看本站教程:https://www.zanglikun.com/12743.html

10、Redis队列

请看本站教程:https://www.zanglikun.com/17217.html

特殊说明:
上述文章均是作者实际操作后产出。烦请各位,请勿直接盗用!转载记得标注原文链接:www.zanglikun.com
第三方平台不会及时更新本文最新内容。如果发现本文资料不全,可访问本人的Java博客搜索:标题关键字。以获取最新全部资料 ❤