当前位置: 首页 > article >正文

Springboot redis bitMap实现用户签到以及统计,保姆级教程

项目架构,这是作为demo展示使用:
在这里插入图片描述

在这里插入图片描述

Redis config:

package com.zy.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * @Author: zy
 * @Date: 2025-03-08-13:22
 * @Description:
 */
@Configuration
public class RedisConfig {

    /**
     * RedisTemplate配置
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(factory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}

Controller:

package com.zy.controller;

import com.zy.config.RedisConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.Optional;

/**
 * @Author: zy
 * @Date: 2025-03-08-12:43
 * @Description:
 */
@RestController
@Slf4j
@RequestMapping("/user")
public class SignController {

    @Autowired
    private RedisTemplate redisTemplate;

    @PostMapping("/sign")
    public Boolean sign() {
        try {
            //1. 获取登录用户
            //Long userId = SSOThreadHolder.getUserAndCheck().getUserId();
            Long userId = 1001012345L;
            //2. 获取日期
            LocalDateTime now = LocalDateTime.now();
            for (int i = 0; i < 100; i++) {
                LocalDate date = LocalDateTime.now().minusDays(i).toLocalDate();
                String format = date.format(DateTimeFormatter.ofPattern(":yyyyMM"));

                //3. 拼接key
                String keySuffix = format;
                String key = RedisConstants.USER_SIGN_KEY + userId + keySuffix;
                log.info("redis key:" + key);
                //4. 获取今天是本月的第几天
                int dayOfMonth = date.getDayOfMonth();
                //5. 写入redis setbit key offset 1
                System.out.println("dayOfMonth:" + dayOfMonth);
                Boolean aBoolean = redisTemplate.opsForValue().setBit(key, dayOfMonth - 1, true);
                System.out.println("aboolean:" + aBoolean);

            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
        }

        return true;
    }

    @GetMapping("/signCount")
    public String signCount() {

        long l = countSignInDays("sign:1001012345:202503");
        System.out.println("l:" + l);
        return String.valueOf(l);
    }

    /**
     * 统计当前月的签到总数
     *
     * @param key Redis键
     * @return 签到总数
     */
    public long countSignInDays(String key) {
        key = "sign:1001012345:202503";
        // 获取当前月的总天数
        YearMonth currentYearMonth = YearMonth.now();
        int daysInMonth = currentYearMonth.lengthOfMonth();

        // 使用 execute 方法执行 BITCOUNT 命令
        String finalKey = key;
        Long bitCount = (Long) redisTemplate.execute((RedisConnection connection) -> {
            // 检查键是否存在
            if (!connection.exists(finalKey.getBytes())) {
                return 0L;
            }
            // 执行 BITCOUNT 命令,统计指定范围内的 1 的数量
            return connection.bitCount(finalKey.getBytes(), 0, daysInMonth - 1);
        });

        return Optional.ofNullable(bitCount).orElse(0L);
    }

}

yml文件:

server:
  port: 8090


spring:
  #redis哨兵配置
  redis:
    sentinel:
      master: mymaster
      nodes: # 我这里使用的是哨兵模式,不影响,根据你自己的来,但是如果没有,为啥不搭建一下,自己使用呢
        - localhost:26379
        - localhost:26380
        - localhost:26381
      password: 你的密码
    password: 你的密码



接口测试:
签到接口,在代码中模拟了100天的签到
在这里插入图片描述

统计接口:统计的什么,具体看代码
在这里插入图片描述


http://www.kler.cn/a/583416.html

相关文章:

  • MongoDB分页实现方式对比:PageRequest vs Skip/Limit
  • Ubuntu-配置apt国内源
  • 暴力破解Excel受保护的单元格密码
  • 数据批处理(队列方式)
  • QT系列教程(13) 事件系统
  • linux学习(十二)(联网(TCP/IP堆栈,子网掩码,以太网arp/rarp,DHCP,IP路由,DNS解析,网络过滤器,SSH公司,文件传输))
  • 在类似于Manus的项目中,我想使用python控制用户的浏览器,我应该选择selenium呢?还是playwright?
  • ubuntu22.04 关于挂在设备为nfts文件格式无法创建软连接的问题
  • 4-文件导入功能文档
  • 基于Redis实现限流
  • 蓝桥杯第三天:2023蓝桥杯省赛 第 1 题
  • Django系列教程(4)——实例项目任务管理小应用
  • 链上权益:基于区块链技术的数字版权管理革命
  • C#+AForge 实现视频录制
  • C#线程上异步执行(this.BeginInvoke)
  • 【CSS3】筑基篇
  • BambuStudio学习笔记:ModelArrange
  • Linux云计算SRE-第十八周
  • 基于OpenCV的车牌识别系统(源码+论文+部署教程)
  • 策略模式和责任链模式的区别