需求:利用redis实现签到的3个功能:用户签到、连续签到统计、获取签到情况。
controller层:
/**
* 用户签到
* @return
*/
@PostMapping("/sign")
public Result sign(){
return userService.sign();
}
/**
* 连续签到统计
* @return
*/
@GetMapping("/sign/count")
public Result signCount(){
return userService.signCount();
}
/**
* 获取签到情况
* @return
*/
@GetMapping("/sign/info")
public Result signInfo(){
return userService.signInfo();
}
service实现层:
/**
* 用户签到
* @return
*/
@Override
public Result sign() {
//获取当前登录用户
Long userId = UserHolder.getUser().getId();
//组装key sign:userId:202401
LocalDateTime now = LocalDateTime.now();
String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
String key = USER_SIGN_KEY + userId + keySuffix ;
//存入redis 执行签到
int dayOfMonth = now.getDayOfMonth();//这个月的第几天
redisTemplate.opsForValue().setBit(key,dayOfMonth-1,true);
return Result.ok();
}
/**
* 连续签到统计
* @return
*/
@Override
public Result signCount() {
//1.获取当前用户
Long userId = UserHolder.getUser().getId();
//2.获取本月开始到目前为止的签到数据(10进制)
LocalDateTime now = LocalDateTime.now();
String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
String key = USER_SIGN_KEY + userId + keySuffix ;
//2,1获取当前天数
int dayOfMonth = now.getDayOfMonth();
//2.1获取签到数据 返回的是一个十进制的数字 BITFIELD sign:5:202203 GET u14 0 获取从0号角标开始 忽略符号一共获取14位
List<Long> longs = redisTemplate.opsForValue().bitField(key, BitFieldSubCommands.create()
.get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth))//当前天数
.valueAt(0)
);
//健壮性判断
if (longs == null || longs.isEmpty()) {
// 没有任何签到结果
return Result.ok(0);
}
//获取10进制数 集合第一个
Long num = longs.get(0);
if (num == null || num == 0){
// 没有任何签到结果
return Result.ok(0);
}
//3.循环进行与运算和计算器
int signCount = 0;
while (true){
if((num & 1) == 0){
// 如果为0,说明未签到,结束
break;
}else {
//如果不为0,说明已签到,计数器+1
signCount++;
}
// 把数字右移一位,抛弃最后一个bit位,继续下一个bit位
num >>>= 1;
}
return Result.ok(signCount);
}
/**
* 获取签到情况
* @return
*/
@Override
public Result signInfo() {
//1.获取当前用户
Long userId = UserHolder.getUser().getId();
//2.获取本月开始到目前为止的签到数据(10进制)
LocalDateTime now = LocalDateTime.now();
String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
String key = USER_SIGN_KEY + userId + keySuffix ;
//2,1获取当前天数
int dayOfMonth = now.getDayOfMonth();
//2.1获取签到数据 返回的是一个十进制的数字 BITFIELD sign:5:202203 GET u14 0 获取从0号角标开始 忽略符号一共获取14位
List<Long> longs = redisTemplate.opsForValue().bitField(key, BitFieldSubCommands.create()
.get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth))//当前天数
.valueAt(0)
);
//健壮性判断
if (longs == null || longs.isEmpty()) {
// 没有任何签到结果
return Result.ok(0);
}
//获取10进制数 集合第一个
int num = longs.get(0).intValue();
if (num == 0){
// 没有任何签到结果
return Result.ok(0);
}
//角标
int index = dayOfMonth-1;
//byte集合
Byte[] arr = new Byte[dayOfMonth];
//2.处理记录
while (index >= 0){
arr[index] = (byte) (num & 1);
//角标-1
index--;
//num右移1位
num = num >>> 1;
}
log.info("签到记录:{}",Arrays.toString(arr));
//3.返回
return Result.ok(arr);
}