【java】redis的bitmap实现签到功能

功能:

        1.签到

        2.判断某天是否签到

        3.统计某月的签到情况

        4.统计某月连续签到了多少天

        5.统计某月一共签到了多少次

代码

1.依赖

<dependencies>
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>4.0.1</version>
    </dependency>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.8.18</version>
    </dependency>
</dependencies>

2.用户签到

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import redis.clients.jedis.Jedis;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class UserSign {

    Jedis jedis;

    public UserSign(Jedis jedis) {
        this.jedis = jedis;
    }

    public String buildKey(int userId, Date date) {
        return Constant.SING_KEY + userId + ":" + simpleFormatDate(date);
    }

    /**
     * 用户签到
     *
     * @param userId 用户id
     * @return 签到情况
     */
    public boolean sign(int userId, Date date) {
        DateTime now = (DateTime) date;
        String key = buildKey(userId, now);
        //这里需要减一是因为偏移量是从0开始的
        int offset = now.dayOfMonth() - 1;
        return jedis.setbit(key, offset, true);
    }

    /**
     * 检测用户是否签到
     *
     * @param userId
     * @param date
     * @return
     */
    public boolean isSign(int userId, Date date) {
        DateTime dateTime = (DateTime) date;
        return jedis.getbit(buildKey(userId, date), dateTime.getDay() - 1);
    }


    /**
     * 统计签到情况
     *
     * @param userId 用户id
     * @param date   日期对象
     * @return
     */
    public Map<String, Boolean> getSignInfo(int userId, Date date) {
        Map<String, Boolean> map = new LinkedHashMap<String, Boolean>();
        //当月最后一天
        DateTime dateTime = (DateTime) date;
        String type = String.format("u%d", dateTime.getLastDayOfMonth());
        //查询当月所签到的二进制值
        List<Long> longs = jedis.bitfield(buildKey(userId, date), "get", type, "0");
        //判断当月是否有签到情况
        if (longs == null || longs.size() == 0) return null;

        Long aLong = longs.get(0);
        for (int i = dateTime.getLastDayOfMonth(); i > 0; i--) {
            DateTime now = DateTime.now();
            now.setField(DateField.DAY_OF_MONTH, i);
             /*
                如果二进制右移一位再左移一位等于原来的值,证明低位有0,断签
                   例如  6的二进制 0110
                    0110 >>右移一位 = 0011 <<左移回来 0110 还是不变,证明低位有0
             */
            if (aLong >> 1 << 1 == aLong) {
                map.put(simpleFormatDate(now, "yyyy-MM-dd"), false);
            } else {
                map.put(simpleFormatDate(now, "yyyy-MM-dd"), true);
            }
            //右移继续判断下一天
            aLong >>= 1;
        }
        return map;
    }

    /**
     * 统计连续签到
     *
     * @param userId 用户id
     * @param date   日期对象
     * @return
     */
    public int getContinuousSignNCount(int userId, Date date) {
        int count = 0;
        int nowDay = ((DateTime) date).dayOfMonth();
        //当月最后一天
        String type = String.format("u%d", nowDay);
        //查询当月所签到的二进制值
        List<Long> l = jedis.bitfield(buildKey(userId, date), "get", type, "0");
        //当月未签到
        if (l == null || l.size() == 0) return 0;
        //统计
        Long aLong = l.get(0);
        for (int i = 0; i < nowDay; i++) {
            /*
                如果二进制右移一位再左移一位等于原来的值,证明低位有0,断签
                   例如  6的二进制 0110
                    0110 >>右移一位 = 0011 <<左移回来 0110 还是不变,证明低位有0
             */
            if (aLong >> 1 << 1 == aLong) {
                //这里需要考虑当天没有签到的情况
                if (i > 0) break;
            } else {
                count += 1;
            }
            //右移继续判断下一天
            aLong >>= 1;
        }
        return count;
    }


    /**
     * 用户某月内一共签到了多少次
     *
     * @param userId 用户id
     * @param date   日期对象
     * @return
     */
    public long signCount(int userId, Date date) {
        return jedis.bitcount(buildKey(userId, date));
    }


    /**
     * 固定日期格式
     *
     * @param date
     * @return
     */
    public static String simpleFormatDate(Date date) {
        return new SimpleDateFormat("yyyyMM").format(date);
    }

    /**
     * 用户自定义日期格式
     *<>java的开闭原则</>
     * @param date
     * @param format
     * @return
     */
    public static String simpleFormatDate(Date date, String format) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
        return simpleDateFormat.format(date);
    }
}

3.测试 

import cn.hutool.core.date.DateTime;
import redis.clients.jedis.Jedis;

import java.util.Map;
import java.util.Set;

public class Test {
    public static void main(String[] args) throws InterruptedException {
        Jedis jedis = new Jedis("192.168.57.128", 6379);
        UserSign userSign = new UserSign(jedis);
        System.out.println("-----------------签到-----------------");
        DateTime now = DateTime.now();
        for (int i = 1; i <= 4; i++) {
            now.setDate(i);
            System.out.println(now);
            userSign.sign(100, now);
        }
        System.out.println("-----------------查看某一天是否签到-----------------");
        DateTime now1 = DateTime.now();
        boolean sign = userSign.isSign(100, now1);
        System.out.println(sign ? UserSign.simpleFormatDate(now1, "yyyy-MM-dd") + ":已签到" : "未签到");

        System.out.println("-----------------查看连续签到了几天-----------------");
        DateTime now2 = DateTime.now();
        int continuousSignNCount = userSign.getContinuousSignNCount(100, now2);
        System.out.println(UserSign.simpleFormatDate(now2) + "月连续签到了" + continuousSignNCount + "天");

        System.out.println("-----------------总体签到情况-----------------");
        Map<String, Boolean> signInfo = userSign.getSignInfo(100, DateTime.now());
        Set<Map.Entry<String, Boolean>> entries = signInfo.entrySet();
        for (Map.Entry<String, Boolean> entry : entries) {
            System.out.println(entry.getKey() + ":" + (entry.getValue() ? "√" : "X"));
        }
        System.out.println("-----------------统计一个月签到了多少天-----------------");
        DateTime now3 = DateTime.now();
        long l = userSign.signCount(100, now3);
        System.out.println(UserSign.simpleFormatDate(now3) + "月签到了" + l + "次");
    }
}

  • 20
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值