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
第三方平台不会及时更新本文最新内容。如果发现本文资料不全,可访问本人的Java博客搜索:标题关键字。以获取最新全部资料 ❤