Spring Boot:运用Redis统计用户在线数量

在Spring Boot里运用Redis统计用户在线数量。

项目依赖与配置

1. 引入依赖

首先,在pom.xml文件中添加Spring Data Redis依赖:

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2. 配置Redis连接

application.properties中进行Redis连接的配置:

properties 复制代码
spring.redis.host=localhost
spring.redis.port=6379

方案1:借助Redis Set实现精确统计

1. 创建Redis操作Service

编写一个Redis操作Service,用于处理用户在线状态:

java 复制代码
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Set;

@Service
public class OnlineUserService {

    private static final String ONLINE_USERS_KEY = "online_users";

    private final RedisTemplate<String, String> redisTemplate;

    public OnlineUserService(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    // 用户登录
    public void login(String userId) {
        redisTemplate.opsForSet().add(ONLINE_USERS_KEY, userId);
    }

    // 用户退出
    public void logout(String userId) {
        redisTemplate.opsForSet().remove(ONLINE_USERS_KEY, userId);
    }

    // 获取在线用户数
    public Long getOnlineCount() {
        return redisTemplate.opsForSet().size(ONLINE_USERS_KEY);
    }

    // 获取所有在线用户ID
    public Set<String> getOnlineUsers() {
        return redisTemplate.opsForSet().members(ONLINE_USERS_KEY);
    }
}
2. 控制器示例

创建一个控制器,用于测试上述功能:

java 复制代码
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/online")
public class OnlineUserController {

    private final OnlineUserService onlineUserService;

    public OnlineUserController(OnlineUserService onlineUserService) {
        this.onlineUserService = onlineUserService;
    }

    @PostMapping("/login/{userId}")
    public String login(@PathVariable String userId) {
        onlineUserService.login(userId);
        return userId + " 已登录";
    }

    @PostMapping("/logout/{userId}")
    public String logout(@PathVariable String userId) {
        onlineUserService.logout(userId);
        return userId + " 已退出";
    }

    @GetMapping("/count")
    public Long getCount() {
        return onlineUserService.getOnlineCount();
    }

    @GetMapping("/users")
    public Set<String> getUsers() {
        return onlineUserService.getOnlineUsers();
    }
}

方案2:使用Redis Bitmap实现按位存储

1. Bitmap操作Service

创建一个专门用于Bitmap操作的Service:

java 复制代码
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

@Service
public class OnlineUserBitmapService {

    private static final String ONLINE_USERS_BITMAP_KEY = "online_users_bitmap";

    private final RedisTemplate<String, Object> redisTemplate;

    public OnlineUserBitmapService(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    // 用户登录(userId需为Long类型)
    public void login(Long userId) {
        redisTemplate.execute((RedisCallback<Boolean>) connection ->
                connection.setBit(ONLINE_USERS_BITMAP_KEY.getBytes(), userId, true));
    }

    // 用户退出
    public void logout(Long userId) {
        redisTemplate.execute((RedisCallback<Boolean>) connection ->
                connection.setBit(ONLINE_USERS_BITMAP_KEY.getBytes(), userId, false));
    }

    // 检查用户是否在线
    public Boolean isOnline(Long userId) {
        return redisTemplate.execute((RedisCallback<Boolean>) connection ->
                connection.getBit(ONLINE_USERS_BITMAP_KEY.getBytes(), userId));
    }

    // 获取在线用户数
    public Long getOnlineCount() {
        return redisTemplate.execute((RedisCallback<Long>) connection ->
                connection.bitCount(ONLINE_USERS_BITMAP_KEY.getBytes()));
    }

    // 统计指定范围内的在线用户数
    public Long getOnlineCount(long start, long end) {
        return redisTemplate.execute((RedisCallback<Long>) connection ->
                connection.bitCount(ONLINE_USERS_BITMAP_KEY.getBytes(), start, end));
    }
}
2. 控制器示例

创建对应的控制器:

java 复制代码
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/online/bitmap")
public class OnlineUserBitmapController {

    private final OnlineUserBitmapService onlineUserBitmapService;

    public OnlineUserBitmapController(OnlineUserBitmapService onlineUserBitmapService) {
        this.onlineUserBitmapService = onlineUserBitmapService;
    }

    @PostMapping("/login/{userId}")
    public String login(@PathVariable Long userId) {
        onlineUserBitmapService.login(userId);
        return userId + " 已登录";
    }

    @PostMapping("/logout/{userId}")
    public String logout(@PathVariable Long userId) {
        onlineUserBitmapService.logout(userId);
        return userId + " 已退出";
    }

    @GetMapping("/count")
    public Long getCount() {
        return onlineUserBitmapService.getOnlineCount();
    }

    @GetMapping("/{userId}")
    public Boolean isOnline(@PathVariable Long userId) {
        return onlineUserBitmapService.isOnline(userId);
    }
}

使用建议

1. Set方案的适用场景
  • 当需要精确统计在线用户数量,并且能够获取在线用户列表时,可以使用Set方案。
  • 适合用户规模在百万级别以下的情况,因为Set会存储每个用户的ID。
2. Bitmap方案的适用场景
  • 若用户ID是连续的整数(或者可以映射为连续整数),Bitmap方案会更节省内存。
  • 对于大规模用户(比如亿级)的在线统计,Bitmap方案具有明显优势。
  • 示例中使用Long类型的userId,在实际应用中,你可能需要一个ID映射器,将业务ID转换为连续的整数。
相关推荐
杨运交20 分钟前
[069][公共模块]Spring Boot 全局异常处理与参数校验实战(下):校验异常精细化处理与 WebFlux 适配
java·spring boot·后端
行者-全栈开发33 分钟前
Spring Boot + FFmpeg 视频批量处理实战:压缩、HLS切片与异步任务引擎
spring boot·ffmpeg·异步处理·视频压缩·hls切片·批量任务·redis队列
Raas10039 分钟前
MAI Gateway(魔芋企业级AI网关)对比分析:AI网关和OpenRouter区别?企业级能力差距一览
java·服务器·网络·人工智能·gateway·ai网关·mai gateway
Andya_net1 小时前
Spring Boot | 条件注解完全指南:从 @Conditional 到 @ConditionalOnExpression 的原理、实践与避坑
spring boot·后端·python
APItesterCris1 小时前
告别人工盯品!借助 Open‑Claw 快速搭建电商商品全自动监控与数据分析系统(完整实操代码)
java·大数据·前端·数据库
青山木1 小时前
Hot 100 --- 跳跃游戏 II
java·数据结构·算法·leetcode·贪心算法
ly76891 小时前
Spring 中的 @Configuration 与 @Component 差异:为何代理时机决定 Bean 生命周期行为
java·后端·spring·注解·代理·bean生命周期
qq_452396231 小时前
第十二篇:《数据采集:Grafana Alloy、Fluent Bit、Vector 的选型与配置》
java·贪心算法·grafana
珍珠先生1 小时前
P16 · IDEA 启动报错:找不到或无法加载主类
java
子非鱼a1 小时前
【WEB】[RoarCTF 2019]Easy Java
java·开发语言