当前位置: 首页 > 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组件是用…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

(十)学生端搭建

本次旨在将之前的已完成的部分功能进行拼装到学生端&#xff0c;同时完善学生端的构建。本次工作主要包括&#xff1a; 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

Debian系统简介

目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版&#xff…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题&#xff1a;3564. 季节性销售分析 题目&#xff1a; 表&#xff1a;sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

【生成模型】视频生成论文调研

工作清单 上游应用方向&#xff1a;控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...

技术栈RabbitMq的介绍和使用

目录 1. 什么是消息队列&#xff1f;2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...

MySQL 知识小结(一)

一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库&#xff0c;分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷&#xff0c;但是文件存放起来数据比较冗余&#xff0c;用二进制能够更好管理咱们M…...

Modbus RTU与Modbus TCP详解指南

目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...