diff --git a/spring-boot-demo-rbac-security/README.md b/spring-boot-demo-rbac-security/README.md
index 89f66a0..e4eb9f4 100644
--- a/spring-boot-demo-rbac-security/README.md
+++ b/spring-boot-demo-rbac-security/README.md
@@ -9,7 +9,7 @@
- [x] **登录 / 登出**部分均使用自定义 Controller 实现,未使用 `Spring Security` 内部实现部分,适用于前后端分离项目,详情参考 [`SecurityConfig.java`](./src/main/java/com/xkcoding/rbac/security/config/SecurityConfig.java) 和 [`AuthController.java`](./src/main/java/com/xkcoding/rbac/security/config/AuthController.java)
- [x] 持久化技术使用 `spring-data-jpa` 完成
- [x] 使用 `JWT` 实现安全验证,同时引入 `Redis` 解决 `JWT` 无法手动设置过期的弊端,并且保证同一用户在同一时间仅支持同一设备登录,不同设备登录会将,详情参考 [`JwtUtil.java`](./src/main/java/com/xkcoding/rbac/security/config/JwtUtil.java)
-- [ ] 在线人数统计
+- [x] 在线人数统计
- [ ] 手动踢出用户
## 2. 运行
@@ -553,7 +553,135 @@ public class CustomUserDetailsService implements UserDetailsService {
}
```
-### 3.7. 其余代码参见本 demo
+### 3.7. RedisUtil.java
+
+> 主要功能:根据key的格式分页获取Redis存在的key列表
+
+```java
+/**
+ *
+ * Redis工具类
+ *
+ *
+ * @package: com.xkcoding.rbac.security.util
+ * @description: Redis工具类
+ * @author: yangkai.shen
+ * @date: Created in 2018-12-11 20:24
+ * @copyright: Copyright (c) 2018
+ * @version: V1.0
+ * @modified: yangkai.shen
+ */
+@Component
+@Slf4j
+public class RedisUtil {
+ @Autowired
+ private StringRedisTemplate stringRedisTemplate;
+
+ /**
+ * 分页获取指定格式key,使用 scan 命令代替 keys 命令,在大数据量的情况下可以提高查询效率
+ *
+ * @param patternKey key格式
+ * @param currentPage 当前页码
+ * @param pageSize 每页条数
+ * @return 分页获取指定格式key
+ */
+ public PageResult findKeysForPage(String patternKey, int currentPage, int pageSize) {
+ ScanOptions options = ScanOptions.scanOptions()
+ .match(patternKey)
+ .build();
+ RedisConnectionFactory factory = stringRedisTemplate.getConnectionFactory();
+ RedisConnection rc = factory.getConnection();
+ Cursor cursor = rc.scan(options);
+
+ List result = Lists.newArrayList();
+
+ long tmpIndex = 0;
+ int startIndex = (currentPage - 1) * pageSize;
+ int end = currentPage * pageSize;
+ while (cursor.hasNext()) {
+ String key = new String(cursor.next());
+ if (tmpIndex >= startIndex && tmpIndex < end) {
+ result.add(key);
+ }
+ tmpIndex++;
+ }
+
+ try {
+ cursor.close();
+ RedisConnectionUtils.releaseConnection(rc, factory);
+ } catch (Exception e) {
+ log.warn("Redis连接关闭异常,", e);
+ }
+
+ return new PageResult<>(result, tmpIndex);
+ }
+}
+```
+
+### 3.8. MonitorService.java
+
+> 监控服务,主要功能:查询当前在线人数分页列表,手动踢出某个用户
+
+```java
+package com.xkcoding.rbac.security.service;
+
+import cn.hutool.core.util.StrUtil;
+import com.google.common.collect.Lists;
+import com.xkcoding.rbac.security.common.Consts;
+import com.xkcoding.rbac.security.common.PageResult;
+import com.xkcoding.rbac.security.model.User;
+import com.xkcoding.rbac.security.repository.UserDao;
+import com.xkcoding.rbac.security.util.RedisUtil;
+import com.xkcoding.rbac.security.vo.OnlineUser;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ *
+ * 监控 Service
+ *
+ *
+ * @package: com.xkcoding.rbac.security.service
+ * @description: 监控 Service
+ * @author: yangkai.shen
+ * @date: Created in 2018-12-12 00:55
+ * @copyright: Copyright (c) 2018
+ * @version: V1.0
+ * @modified: yangkai.shen
+ */
+@Service
+public class MonitorService {
+ @Autowired
+ private RedisUtil redisUtil;
+
+ @Autowired
+ private UserDao userDao;
+
+ public PageResult onlineUser(Integer page, Integer size) {
+ PageResult keys = redisUtil.findKeysForPage(Consts.REDIS_JWT_KEY_PREFIX + Consts.SYMBOL_STAR, page, size);
+ List rows = keys.getRows();
+ Long total = keys.getTotal();
+
+ // 根据 redis 中键获取用户名列表
+ List usernameList = rows.stream()
+ .map(s -> StrUtil.subAfter(s, Consts.REDIS_JWT_KEY_PREFIX, true))
+ .collect(Collectors.toList());
+ // 根据用户名查询用户信息
+ List userList = userDao.findByUsernameIn(usernameList);
+
+ // 封装在线用户信息
+ List onlineUserList = Lists.newArrayList();
+ userList.forEach(user -> onlineUserList.add(OnlineUser.create(user)));
+
+ return new PageResult<>(onlineUserList, total);
+ }
+}
+```
+
+### 3.9. 其余代码参见本 demo
## 4. 参考