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

springboot + redis实现签到与统计功能

在很多项目中都会有签到与统计功能,最容易想到的方案是创建一个签到表来记录每个用户的签到记录,比如设计一个mysql数据库表:

CREATE TABLE tb_sign
id bigint(20) unsigned NOT NULL AUTOINCREMENT COMMENT '主键',
user_id bigint(20) unsigned NOT NULL COMMENT '用户ID',
sign_date date NOT NULL COMMENT '签到的日期',
is_backup tinyint(1) unsigned DEFAUL TNULL COMMENT '是否补签',
PRIMARY KEY (id) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW FORMAT=COMPACT;

用户签到一次就可以往表里添加一条记录;但是这样有一个坏处,就是占用的内存太大了,会极大的消耗内存空间;比如有1万用户,每个用户每个月签到10次,那么一个月就是10万条记录,一年就是120万条;如果用户更多并且签到的次数越多,那么数据量就会更大哦。

签到一次需要使用8+8+3+1 = 20个字节,如果使用redis中的bitmap来实现,每次签到与未签到用1与0来表示,那么只需要2个字节即可了,这样极大的节约了内存;那么接下来认识与使用bitmap。

1.bitmap基本操作指令

SETBIT:向指定位置(offset)存入一个0或1

GETBIT:获取指定位置(offset)的bit值

BITCOUNT:统计BitMap中值为1的bit位的数量

BITFIELD:操作(查询、修改、自增)BitMap中bit数组中的指定位置(offset)的值

BITFIELD_RO:获取BitMap中bit数组,并以十进制形式返回

BITOP:将多个BitMap的结果做位运算(与 、或、异或)

BITPOS:查找bit数组中指定范围内第一个0或1出现的位置

1.1 新增

在这里插入图片描述
在这里插入图片描述

1.2 查询

在这里插入图片描述
在这里插入图片描述

1.3 统计值为1的数量

在这里插入图片描述

在这里插入图片描述

1.4 查询1 和 0 第一次出现的坐标

在这里插入图片描述
在这里插入图片描述

2.springboot整合redis

  • 创建一个spring boot项目,这里比较简单,不用过多介绍;

  • 添加redis依赖

<!--redis--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!--spring2.x集成redis所需common-pool2--><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.11.0</version></dependency>
  • 配置配置文件
#redis服务器地址
spring.redis.host=127.0.0.1
#redis服务器连接端口
spring.redis.port=6379
#redis数据库索引(默认是0)
spring.redis.database=0
#连接超时时间
spring.redis.timeout=1800000
#连接池最大连接数(使用负值表示没有限制)
spring.redis.lettuce.pool.max-active=20
#最大阻塞等待时间(负数表示没有限制)
spring.redis.lettuce.pool.max-wait=-1
#连接池中最大空闲连接
spring.redis.lettuce.pool.max-idle=5
#连接池中最小空闲连接
spring.redis.lettuce.pool.min-idle=0
  • 测试一下
@SpringBootTest
class SpringbootRedisSigninApplicationTests {@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Testvoid testRedisSet() {stringRedisTemplate.opsForValue().set("name", "picacho");String name = (String)stringRedisTemplate.opsForValue().get("name");System.out.println(name);}}

在这里插入图片描述
在redis中也可以看到我们插入进去的数据;
在这里插入图片描述

3. 实现

我们可以用年和月作为BitMap的key,然后保存到一个BitMap中,每次签到就把对应的位上把数字从0变为1,如果是1,就表示这一天签到了,反之就表示没有签到。

3.1 实现签到的核心代码

这里主要讨论基本思路和处理流程,因此代码并没有非常规范,仅仅作为示例看待即可;

  • UserController
@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@PostMapping("/sign")public String sign(){return userService.sign();}
}
  • UserService
@Service
public class UserService {@Autowiredprivate StringRedisTemplate stringRedisTemplate;public String sign(){// 1.模拟获取用户idLong userId = 1L;// 2.获取日期LocalDateTime now = LocalDateTime.now();// 3.拼接key字符串String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));String key = "sign:" + userId + keySuffix;// 4.获取今天是本月的第几天int dayOfMonth = now.getDayOfMonth();// 5.写入redisstringRedisTemplate.opsForValue().setBit(key, dayOfMonth - 1, true);return "ok";}
}
  • 测试一下
    在这里插入图片描述
  • 查看redis,可以看到本月26号完成了签到。
    在这里插入图片描述

3.2 统计连续签到次数的核心代码

这里先构造几天签到的测试数据便于测试使用;我们这里构造了26,25,24,22号完成了签到。

在这里插入图片描述
我们需要获取本月到今天为止的所有签到数据,今天是26号,那么我们就可以从当前月的第一天开始,获得到26号的位数,那么就是26位,去拿这段时间的数据,就能拿到所有的数据了,那么这26天里边签到了多少次呢?统计有多少个1即可。

注意:bitMap返回的数据是10进制,哪假如说返回一个数字8,我们只需要让得到的10进制数字和1做与运算就可以了,因为1只有遇见1才是1,其他数字都是0 ,我们把签到结果和1进行与操作,每与一次,就把签到结果向右移动一位,依次类推即可。

  • UserController
@PostMapping("/count")public String countSign(){return userService.countSign();}
  • UserService
public Integer countSign(){// 1.模拟获取用户idLong userId = 1L;// 2.获取日期LocalDateTime now = LocalDateTime.now();// 3.拼接key字符串String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));String key = "sign:" + userId + keySuffix;// 4.获取今天是本月的第几天int dayOfMonth = now.getDayOfMonth();// 5.统计签到次数List<Long> result = stringRedisTemplate.opsForValue().bitField(key,BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0));// 5.1 没有签到结果if(result == null || result.isEmpty()){return 0;}Long num = result.get(0);if(num == null || num == 0){return 0;}// 5.2 统计签到次数int count = 0;while(true){if((num & 1) == 0){break;}else{count++;}num >>>= 1;}return count;}
  • 测试一下
    在这里插入图片描述
    可以看到24,25,26号完成了连续3天的的签到,刚好是3天。

到这里demo就结束了,源码地址:demo地址

相关文章:

springboot + redis实现签到与统计功能

在很多项目中都会有签到与统计功能&#xff0c;最容易想到的方案是创建一个签到表来记录每个用户的签到记录&#xff0c;比如设计一个mysql数据库表&#xff1a; CREATE TABLE tb_sign id bigint(20) unsigned NOT NULL AUTOINCREMENT COMMENT 主键, user_id bigint(20) unsig…...

Redis | 数据结构(02)SDS

一、键值对数据库是怎么实现的&#xff1f; 在开始讲数据结构之前&#xff0c;先给介绍下 Redis 是怎样实现键值对&#xff08;key-value&#xff09;数据库的。 Redis 的键值对中的 key 就是字符串对象&#xff0c;而 value 可以是字符串对象&#xff0c;也可以是集合数据类型…...

Linux C语言开发-D7D8运算符

算术运算符&#xff1a;-*/%&#xff0c;浮点数可以参与除法运算&#xff0c;但不能参与取余运算 a%b&#xff1a;表示取模或取余 关系运算符&#xff1a;<,>,>,<,,! 逻辑运算符:!,&&,|| &&,||逻辑运算符是从左到右&#xff0c;依次运算&#…...

redis 配置主从复制,哨兵模式案例

哨兵(Sentinel)模式 1 . 什么是哨兵模式&#xff1f; 反客为主的自动版&#xff0c;能够自动监控master是否发生故障&#xff0c;如果故障了会根据投票数从slave中挑选一个 作为master&#xff0c;其他的slave会自动转向同步新的master&#xff0c;实现故障自动转义 2 . 原理…...

Python---练习:使用for循环实现用户名+密码认证

案例&#xff1a; 用for循环实现用户登录 ① 输入用户名和密码 ② 判断用户名和密码是否正确&#xff08;usernamelaowang&#xff0c;passwordlw123&#xff09; ③ 登录仅有三次机会&#xff0c;超过3次会报错 思考&#xff1a; 用户登陆情况有3种: ① 用户名错误(此时…...

react中使用jquery 语法

react中使用jquery 语法 npm install jquery引入 import $ from ‘jquery’ import React from react; import ./css/App.css import { Button } from antd; import $ from jquerylet slider_img [https://cdn.jsdelivr.net/gh/xaoxuu/cdn-wallpaper/abstract/41F215B9-261F…...

服务器中了360后缀勒索病毒怎么解决,勒索病毒解密,数据恢复

近期&#xff0c;网络上的各种病毒都比较猖獗&#xff0c;而其中较为明显的就是360后缀勒索病毒&#xff0c;从这个月开始云天数据恢复中心接到很多企业的求助&#xff0c;企业的服务器遭到了360后缀勒索病毒的攻击&#xff0c;通过给用户的服务器检测与加密病毒的分析&#xf…...

使用字节流读取文件中的数据的几种方式

public class FileReader02_ {public static void main(String[] args) {}Testpublic void m1() {String filePath "e:\\hello.txt";FileReader fileReader null;int date0;try {fileReader new FileReader(filePath);//循环读取 使用readwhile ((datefileReader.…...

Android WMS——概述(一)

Android 中的 WMS 指的是 Window Manager Service(窗口管理服务)。WMS 是 Android 系统中的核心服务,主要分为四大部分,分别是窗口管理,窗口动画,输入系统中转站和 Surface 管理 。负责管理应用程序窗口的创建、移动、调整大小和显示等操作。 一、功能简介 WMS 的职责可…...

Node编写获取用户信息接口

目录 前言 初始化路由模块 使用postman发送get获取用户信息请求 初始化路由处理函数模块 获取用户基本信息 前言 在前两篇文章中已经介绍了如何编写用户注册接口以及用户登录接口&#xff0c;这篇文章介绍如何获取用户信息&#xff0c;本篇文章建立在Node编写用户登录接口…...

【从0到1设计一个网关】自研网关的设计要点以及架构设计

文章目录 请求的流程架构设计设计要点项目架构流程设计源码地址: 源码地址 请求的流程 一个HTTP请求发送到网关并完成整个生命周期通常包括以下步骤: 客户端请求: 请求始于客户端,客户端通过HTTP请求(例如GET、POST等)发送请求到API网关的入口点。 API网关接收: API…...

论文-分布式-分布式计算|容错-分布式控制下的自稳定系统

参考文献Self-stabilizing systems in spite of distributed control可以把松散耦合的 循环序列过程 间的同步任务&#xff0c;看成是要保持一个这样的不变性&#xff1a;“系统要处于一种合法状态”因此每个进程在运行每一个可能会改变不变性的步骤之前都要先检查一下是可以执…...

C#压缩图片的方法

/// <summary> /// 图片压缩 /// </summary> /// <param name"imagePath">图片文件路径</param> /// <param name"targetFolder">保存文件夹</param> /// <param name"quality">压缩质量</param&g…...

安装 fcitx + 搜狗/谷歌输入法 之后导致 死机,重启后黑屏只有鼠标可以移动

一般的原因就是 &#xff1a; fcitx 导致的问题 方法就是 先卸载搜狗&#xff0c;再卸载fcitx 解决办法&#xff1a; 首先&#xff1a;ctrlaltF6 进入命令行界面&#xff0c;如果进不去就 ctrlaltF2 接下来执行&#xff1a; sudo apt-get remove sogoupinyin sudo apt-get …...

Maven项目转为SpringBoot项目

Maven项目转为SpringBoot项目 前言创建一个maven项目前的软件的一些通用设置Maven仓库的设置其他的设置字符编码编译器注解支持 创建的Maven项目修改为Spring Boot项目修改pom.xml文件修改启动类-Main新建WAR包所需的类 添加核心配置文件 测试的控制器最后整个项目的目录结构![…...

C语言之预处理

目录 前言 宏定义define的用法 文件包含include的用法 条件编译的用法 其他预处理命令 练习题 练习一 练习二 练习三 前言 预处理命令可以改变程序设计环境&#xff0c;提高编程效率&#xff0c;它们并不是C语言本身的组成部分&#xff0c;不能直接对它们进行编译&am…...

css步骤条

html 代码以及样式 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>css步骤条</title><style>.steps {display: flex;justify-content: space-between;padding: 0;margin: 20px 10px;lis…...

[Hive] 常见函数

文章目录 字符串函数数值函数随机函数日期和时间函数字符串转时间 聚合函数数组函数结构体函数数组函数映射函数 map正则处理JSON 字符串函数 CONCAT(string1, string2, …)&#xff1a;将多个字符串连接成一个字符串。 LENGTH(string)&#xff1a;返回字符串的长度。 LOWER…...

Mac用NTFS文件夹读写NTFS硬盘 NTFS能复制多大的文件

Mac作为一款备受欢迎的计算机操作系统&#xff0c;具备了许多令人惊叹的功能和特性。然而&#xff0c;对于一些Mac用户来说&#xff0c;使用NTFS格式的硬盘可能存在一些疑问。他们可能想知道Mac是否能够读写NTFS格式的硬盘&#xff0c;以及NTFS格式的硬盘是否有文件大小的限制。…...

【unity3D】Scroll Rect组件—制作下滑列表

&#x1f497; 未来的游戏开发程序媛&#xff0c;现在的努力学习菜鸡 &#x1f4a6;本专栏是我关于游戏开发的学习笔记 &#x1f236;本篇是unity的Scroll Rect组件 Scroll Rect组件 基础知识详细说明案例演示——制作一个简单的下滑框扩展 介绍&#xff1a;Scroll Rect组件是用…...

高频面试之3Zookeeper

高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个&#xff1f;3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制&#xff08;过半机制&#xff0…...

uniapp微信小程序视频实时流+pc端预览方案

方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度​WebSocket图片帧​定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐​RTMP推流​TRTC/即构SDK推流❌ 付费方案 &#xff08;部分有免费额度&#x…...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

windows系统MySQL安装文档

概览&#xff1a;本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容&#xff0c;为学习者提供全面的操作指导。关键要点包括&#xff1a; 解压 &#xff1a;下载完成后解压压缩包&#xff0c;得到MySQL 8.…...

Spring Boot + MyBatis 集成支付宝支付流程

Spring Boot MyBatis 集成支付宝支付流程 核心流程 商户系统生成订单调用支付宝创建预支付订单用户跳转支付宝完成支付支付宝异步通知支付结果商户处理支付结果更新订单状态支付宝同步跳转回商户页面 代码实现示例&#xff08;电脑网站支付&#xff09; 1. 添加依赖 <!…...

对象回调初步研究

_OBJECT_TYPE结构分析 在介绍什么是对象回调前&#xff0c;首先要熟悉下结构 以我们上篇线程回调介绍过的导出的PsProcessType 结构为例&#xff0c;用_OBJECT_TYPE这个结构来解析它&#xff0c;0x80处就是今天要介绍的回调链表&#xff0c;但是先不着急&#xff0c;先把目光…...

数据挖掘是什么?数据挖掘技术有哪些?

目录 一、数据挖掘是什么 二、常见的数据挖掘技术 1. 关联规则挖掘 2. 分类算法 3. 聚类分析 4. 回归分析 三、数据挖掘的应用领域 1. 商业领域 2. 医疗领域 3. 金融领域 4. 其他领域 四、数据挖掘面临的挑战和未来趋势 1. 面临的挑战 2. 未来趋势 五、总结 数据…...