栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

使用redis的BitMap来统计签到入门

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

使用redis的BitMap来统计签到入门

介绍

redis有一个bitMap数据结构,可以看成是一个二进制的数组,数组元素只有0和1。

ps:
**这里要注意bitcount范围统计时,计算的是字节数,即一次性计算8位里面,1的个数。只有getbit时后面跟的偏移量才是从(bit位)数起。
**

签到

命令行操作demo
是否签到: setbit key 第几天 是否签到
统计一段时间内的签到天数: bitcount key 开始日期 结束日期

java的Calendar自带获取今天是一年中第几天的方法
那么当天是否签到只要把值往redis一塞就ok了

Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
System.out.println(calendar.get(Calendar.DAY_OF_YEAR));

LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime.getDayOfYear());

LocalDate localDate = LocalDate.now();
System.out.println(localDate.getDayOfYear());

来一波实际操作demo

demo中是一个月的统计签到次数

import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.BitFieldSubCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;


@RestController
@RequestMapping("/bitMap")
public class RedisBitMapController {

     private final String userId="155852412069";

    @Resource
    private RedisTemplate redisTemplate;


    
    @GetMapping("/getKey")
    public String getRedis() {
        String s1 = buildSignKey(userId, LocalDate.now());
        Object s = redisTemplate.execute((RedisCallback) con -> con.bitCount(s1.getBytes()));
        return String.valueOf(s);
    }

    
    @GetMapping("/sign")
    public String setBitFild(@RequestParam String signDay) {
        LocalDate localDate = formatDay(signDay);
        redisTemplate.opsForValue().setBit(buildSignKey(userId, localDate), localDate.getDayOfMonth(), true);
        return localDate.getDayOfMonth() + "日签到成功";
    }

    
    @GetMapping("/unsign")
    public String unsetBitFild(@RequestParam String signDay) {
        LocalDate localDate = formatDay(signDay);
        redisTemplate.opsForValue().setBit(buildSignKey(userId, localDate), localDate.getDayOfMonth(), false);
        return localDate.getDayOfMonth() + "日取消签到成功";
    }

    
    @GetMapping("/getSign")
    public long getBitFild(@RequestParam String signDay) {
        LocalDate localDate = formatDay(signDay);
        long continueSignCountDay = getContinueSignCountDay(userId, localDate, 1);
        System.out.println(continueSignCountDay);
        return continueSignCountDay;
    }

    
    @GetMapping("/checkSign")
    public Boolean checkSign(@RequestParam String signDay) {
        LocalDate localDate = formatDay(signDay);
        Boolean bit = redisTemplate.opsForValue().getBit(buildSignKey(userId, localDate), localDate.getDayOfMonth());
        return bit;
    }


    public LocalDate formatDay(String signDay) {
        DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        return LocalDate.parse(signDay, format);
    }

    
    @GetMapping("/getsignDetail")
    public String setBitFild1() {
        Map signInfo = getSignInfo(userId, LocalDate.now());
        System.out.println(signInfo);
        return JSON.toJSONString(signInfo);
    }


    
    @GetMapping("getSignSum")
    public String getSignSum(@RequestParam("signDay") String signDay){
        LocalDate localDate = formatDay(signDay);
        String signKey = buildSignKey(userId, localDate);
        Long signSum = redisTemplate.execute((RedisCallback) con -> {
            return con.bitCount(signKey.getBytes());
        });

        return signSum.toString();
    }


    
    public List bitfiled(String signKey, int limit, int offset) {
        List execute = (List) redisTemplate.execute((RedisCallback>) con -> con.bitField(
                signKey.getBytes(), BitFieldSubCommands.create().
                        get(BitFieldSubCommands.BitFieldType.unsigned(limit)).valueAt(offset)));
        return execute;
    }


    private static String buildSignKey(String uid, LocalDate date) {
        return String.format("u:sign:%s:%s", uid, formatDate(date, "yyyyMM"));
    }

    private static String formatDate(LocalDate date, String pattern) {
        return date.format(DateTimeFormatter.ofPattern(pattern));
    }

    
    public long getContinueSignCountDay(String userId, LocalDate localDate, int offset) {
        long signDayCount = 0;
        List list = bitfiled(buildSignKey(userId, localDate), localDate.getDayOfMonth(), offset);
        System.out.println(list.get(0));
        if (!CollectionUtils.isEmpty(list) && list.size() > 0) {
            long result = list.get(0) == null ? 0 : list.get(0);
            for (int i = 0; i < localDate.getDayOfMonth(); i++) {

                //相等的代表没有签到,左右右移后最右边的1会变成0
                if (result >> 1 << 1 == result) {
                    if (i > 0) {
                        //当前日期的第一天就没签到,连续签到中断
                        break;
                    }
                } else {
                    signDayCount += 1;
                }

                //将右移两位后的值赋值给result
                result >>= 1;
            }
        }
        return signDayCount;
    }


    

    public Map getSignInfo(String userId, LocalDate date) {
        Map signMap = new LinkedHashMap<>(date.getDayOfMonth());
        List list = bitfiled(buildSignKey(userId, date), date.lengthOfMonth(), 1);
        System.out.println(list.get(0));
        if (!CollectionUtils.isEmpty(list) && list.size() > 0) {
            // 由低位到高位,为0表示未签,为1表示已签
            long result = list.get(0) == null ? 0 : list.get(0);
            for (int i = date.lengthOfMonth(); i > 0; i--) {
                LocalDate d = date.withDayOfMonth(i);
                //在redis中数据存放是从左往右的,即最右边是最近的签到。
                //位移的时候是从最右边开始,所以这里从最新的日期开始
                signMap.put(formatDate(d, "yyyy-MM-dd"), result >> 1 << 1 != result);
                result >>= 1;
            }
        }
        return signMap;
    }

}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1032975.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号