Browse Source

当前在线人数分页列表完成

pull/1/head
Yangkai.Shen 5 years ago
parent
commit
bda597bb32
12 changed files with 431 additions and 28 deletions
  1. +5
    -0
      spring-boot-demo-rbac-security/pom.xml
  2. +27
    -18
      spring-boot-demo-rbac-security/sql/security.sql
  3. +10
    -0
      spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/common/Consts.java
  4. +42
    -0
      spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/common/PageResult.java
  5. +46
    -0
      spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/controller/MonitorController.java
  6. +9
    -1
      spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/repository/UserDao.java
  7. +63
    -0
      spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/service/MonitorService.java
  8. +74
    -0
      spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/util/RedisUtil.java
  9. +68
    -0
      spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/vo/OnlineUser.java
  10. +14
    -9
      spring-boot-demo-rbac-security/src/test/java/com/xkcoding/rbac/security/repository/DataInitTest.java
  11. +39
    -0
      spring-boot-demo-rbac-security/src/test/java/com/xkcoding/rbac/security/repository/UserDaoTest.java
  12. +34
    -0
      spring-boot-demo-rbac-security/src/test/java/com/xkcoding/rbac/security/util/RedisUtilTest.java

+ 5
- 0
spring-boot-demo-rbac-security/pom.xml View File

@@ -78,6 +78,11 @@
<artifactId>hutool-all</artifactId>
</dependency>

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>


+ 27
- 18
spring-boot-demo-rbac-security/sql/security.sql View File

@@ -11,7 +11,7 @@
Target Server Version : 50718
File Encoding : 65001

Date: 10/12/2018 14:46:38
Date: 12/12/2018 01:52:06
*/

SET NAMES utf8mb4;
@@ -40,11 +40,16 @@ CREATE TABLE `sec_permission`
-- ----------------------------
BEGIN;
INSERT INTO `sec_permission`
VALUES (1072019441543417856, '测试页面', '/test', 1, 'page:test', NULL, 1, 0);
VALUES (1072548676754345984, '测试页面', '/test', 1, 'page:test', NULL, 1, 0);
INSERT INTO `sec_permission`
VALUES (1072019441564389376, '测试页面-查询', '/**/test', 2, 'btn:test:query', 'GET', 1, 1072019441543417856);
VALUES (1072548676771123200, '测试页面-查询', '/**/test', 2, 'btn:test:query', 'GET', 1, 1072548676754345984);
INSERT INTO `sec_permission`
VALUES (1072019441576972288, '测试页面-添加', '/**/test', 2, 'btn:test:insert', 'POST', 2, 1072019441543417856);
VALUES (1072548676783706112, '测试页面-添加', '/**/test', 2, 'btn:test:insert', 'POST', 2, 1072548676754345984);
INSERT INTO `sec_permission`
VALUES (1072548676792094720, '监控在线用户页面', '/monitor', 1, 'page:monitor:online', NULL, 2, 0);
INSERT INTO `sec_permission`
VALUES (1072548676800483328, '在线用户页面-查询', '/**/api/monitor/online/user/**', 2, 'btn:monitor:online:query', 'POST', 1,
1072548676792094720);
COMMIT;

-- ----------------------------
@@ -68,9 +73,9 @@ CREATE TABLE `sec_role`
-- ----------------------------
BEGIN;
INSERT INTO `sec_role`
VALUES (1072019441480503296, '管理员', '超级管理员', 1544424326664, 1544424326664);
VALUES (1072548676695625728, '管理员', '超级管理员', 1544550506172, 1544550506172);
INSERT INTO `sec_role`
VALUES (1072019441501474816, '普通用户', '普通用户', 1544424326669, 1544424326669);
VALUES (1072548676716597248, '普通用户', '普通用户', 1544550506177, 1544550506177);
COMMIT;

-- ----------------------------
@@ -90,15 +95,19 @@ CREATE TABLE `sec_role_permission`
-- ----------------------------
BEGIN;
INSERT INTO `sec_role_permission`
VALUES (1072019441480503296, 1072019441543417856);
VALUES (1072548676695625728, 1072548676754345984);
INSERT INTO `sec_role_permission`
VALUES (1072548676695625728, 1072548676771123200);
INSERT INTO `sec_role_permission`
VALUES (1072548676695625728, 1072548676783706112);
INSERT INTO `sec_role_permission`
VALUES (1072019441480503296, 1072019441564389376);
VALUES (1072548676695625728, 1072548676792094720);
INSERT INTO `sec_role_permission`
VALUES (1072019441480503296, 1072019441576972288);
VALUES (1072548676695625728, 1072548676800483328);
INSERT INTO `sec_role_permission`
VALUES (1072019441501474816, 1072019441543417856);
VALUES (1072548676716597248, 1072548676754345984);
INSERT INTO `sec_role_permission`
VALUES (1072019441501474816, 1072019441564389376);
VALUES (1072548676716597248, 1072548676771123200);
COMMIT;

-- ----------------------------
@@ -130,11 +139,11 @@ CREATE TABLE `sec_user`
-- ----------------------------
BEGIN;
INSERT INTO `sec_user`
VALUES (1072019440205434880, 'admin', '$2a$10$TwdumjYKUYRQvc3VC8dleOlWr4Q2TysQtfmCMplOWygOzyfrKQee2', '管理员',
'17300000000', 'admin@xkcoding.com', 785433600000, 1, 1, 1544424326483, 1544424326483);
VALUES (1072548675445723136, 'admin', '$2a$10$YNfKodirWWpUOQruzXEq9.sy3G9tATDlonLsPx2si7oVj6InP2KX2', '管理员',
'17300000000', 'admin@xkcoding.com', 785433600000, 1, 1, 1544550505995, 1544550505995);
INSERT INTO `sec_user`
VALUES (1072019441035907072, 'user', '$2a$10$8hL7INOxQCzDzI08GGYNCOFKV6mjDcOqhJ/7c1VeF9agO.wBS3ylq', '普通用户',
'17300001111', 'user@xkcoding.com', 785433600000, 1, 1, 1544424326659, 1544424326659);
VALUES (1072548676288778240, 'user', '$2a$10$xAZBKSftV9/ZkkR2TEZUUeYPkn1yTXElmPE2.K/DmU1FrR4AR.Ggu', '普通用户',
'17300001111', 'user@xkcoding.com', 785433600000, 1, 1, 1544550506168, 1544550506168);
COMMIT;

-- ----------------------------
@@ -154,9 +163,9 @@ CREATE TABLE `sec_user_role`
-- ----------------------------
BEGIN;
INSERT INTO `sec_user_role`
VALUES (1072019440205434880, 1072019441480503296);
VALUES (1072548675445723136, 1072548676695625728);
INSERT INTO `sec_user_role`
VALUES (1072019441035907072, 1072019441501474816);
VALUES (1072548676288778240, 1072548676716597248);
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;
SET FOREIGN_KEY_CHECKS = 1;

+ 10
- 0
spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/common/Consts.java View File

@@ -37,4 +37,14 @@ public interface Consts {
* JWT 在 Redis 中保存的key前缀
*/
String REDIS_JWT_KEY_PREFIX = "security:jwt:";

/**
* 星号
*/
String SYMBOL_STAR = "*";

/**
* 邮箱符号
*/
String SYMBOL_EMAIL = "@";
}

+ 42
- 0
spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/common/PageResult.java View File

@@ -0,0 +1,42 @@
package com.xkcoding.rbac.security.common;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.List;

/**
* <p>
* 通用分页参数返回
* </p>
*
* @package: com.xkcoding.rbac.security.common
* @description: 通用分页参数返回
* @author: yangkai.shen
* @date: Created in 2018-12-11 20:26
* @copyright: Copyright (c) 2018
* @version: V1.0
* @modified: yangkai.shen
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageResult<T> implements Serializable {
private static final long serialVersionUID = 3420391142991247367L;

/**
* 当前页数据
*/
private List<T> rows;

/**
* 总条数
*/
private Long total;

public static <T> PageResult of(List<T> rows, Long total) {
return new PageResult<>(rows, total);
}
}

+ 46
- 0
spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/controller/MonitorController.java View File

@@ -0,0 +1,46 @@
package com.xkcoding.rbac.security.controller;

import com.xkcoding.rbac.security.common.ApiResponse;
import com.xkcoding.rbac.security.common.PageResult;
import com.xkcoding.rbac.security.service.MonitorService;
import com.xkcoding.rbac.security.vo.OnlineUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* <p>
* 监控 Controller,在线用户,手动踢出用户等功能
* </p>
*
* @package: com.xkcoding.rbac.security.controller
* @description: 监控 Controller,在线用户,手动踢出用户等功能
* @author: yangkai.shen
* @date: Created in 2018-12-11 20:55
* @copyright: Copyright (c) 2018
* @version: V1.0
* @modified: yangkai.shen
*/
@Slf4j
@RestController
@RequestMapping("/api/monitor")
public class MonitorController {
@Autowired
private MonitorService monitorService;

/**
* 在线用户列表
*
* @param page 当前页码
* @param size 每页条数
*/
@PostMapping("/online/user/{page}/{size}")
public ApiResponse onlineUser(@PathVariable Integer page, @PathVariable Integer size) {
PageResult<OnlineUser> pageResult = monitorService.onlineUser(page, size);
return ApiResponse.ofSuccess(pageResult);
}

}

+ 9
- 1
spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/repository/UserDao.java View File

@@ -1,10 +1,10 @@
package com.xkcoding.rbac.security.repository;

import com.xkcoding.rbac.security.model.Permission;
import com.xkcoding.rbac.security.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

import java.util.List;
import java.util.Optional;

/**
@@ -30,4 +30,12 @@ public interface UserDao extends JpaRepository<User, Long>, JpaSpecificationExec
* @return 用户信息
*/
Optional<User> findByUsernameOrEmailOrPhone(String username, String email, String phone);

/**
* 根据用户名列表查询用户列表
*
* @param usernameList 用户名列表
* @return 用户列表
*/
List<User> findByUsernameIn(List<String> usernameList);
}

+ 63
- 0
spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/service/MonitorService.java View File

@@ -0,0 +1,63 @@
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;

/**
* <p>
* 监控 Service
* </p>
*
* @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;

/**
* 在线用户分页列表
*
* @param page 当前页
* @param size 每页条数
* @return 在线用户分页列表
*/
public PageResult<OnlineUser> onlineUser(Integer page, Integer size) {
PageResult<String> keys = redisUtil.findKeysForPage(Consts.REDIS_JWT_KEY_PREFIX + Consts.SYMBOL_STAR, page, size);
List<String> rows = keys.getRows();
Long total = keys.getTotal();

// 根据 redis 中键获取用户名列表
List<String> usernameList = rows.stream()
.map(s -> StrUtil.subAfter(s, Consts.REDIS_JWT_KEY_PREFIX, true))
.collect(Collectors.toList());
// 根据用户名查询用户信息
List<User> userList = userDao.findByUsernameIn(usernameList);

// 封装在线用户信息
List<OnlineUser> onlineUserList = Lists.newArrayList();
userList.forEach(user -> onlineUserList.add(OnlineUser.create(user)));

return new PageResult<>(onlineUserList, total);
}
}

+ 74
- 0
spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/util/RedisUtil.java View File

@@ -0,0 +1,74 @@
package com.xkcoding.rbac.security.util;

import com.google.common.collect.Lists;
import com.xkcoding.rbac.security.common.PageResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisConnectionUtils;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.List;

/**
* <p>
* Redis工具类
* </p>
*
* @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<String> findKeysForPage(String patternKey, int currentPage, int pageSize) {
ScanOptions options = ScanOptions.scanOptions()
.match(patternKey)
.build();
RedisConnectionFactory factory = stringRedisTemplate.getConnectionFactory();
RedisConnection rc = factory.getConnection();
Cursor<byte[]> cursor = rc.scan(options);

List<String> 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);
}
}

+ 68
- 0
spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/vo/OnlineUser.java View File

@@ -0,0 +1,68 @@
package com.xkcoding.rbac.security.vo;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.xkcoding.rbac.security.common.Consts;
import com.xkcoding.rbac.security.model.User;
import lombok.Data;

/**
* <p>
* 在线用户 VO
* </p>
*
* @package: com.xkcoding.rbac.security.vo
* @description: 在线用户 VO
* @author: yangkai.shen
* @date: Created in 2018-12-12 00:58
* @copyright: Copyright (c) 2018
* @version: V1.0
* @modified: yangkai.shen
*/
@Data
public class OnlineUser {

/**
* 主键
*/
private Long id;

/**
* 用户名
*/
private String username;

/**
* 昵称
*/
private String nickname;

/**
* 手机
*/
private String phone;

/**
* 邮箱
*/
private String email;

/**
* 生日
*/
private Long birthday;

/**
* 性别,男-1,女-2
*/
private Integer sex;

public static OnlineUser create(User user) {
OnlineUser onlineUser = new OnlineUser();
BeanUtil.copyProperties(user, onlineUser);
// 脱敏
onlineUser.setPhone(StrUtil.hide(user.getPhone(), 3, 7));
onlineUser.setEmail(StrUtil.hide(user.getEmail(), 1, StrUtil.indexOfIgnoreCase(user.getEmail(), Consts.SYMBOL_EMAIL)));
return onlineUser;
}
}

+ 14
- 9
spring-boot-demo-rbac-security/src/test/java/com/xkcoding/rbac/security/repository/DataInitTest.java View File

@@ -62,16 +62,21 @@ public class DataInitTest extends SpringBootDemoRbacSecurityApplicationTests {
createUserRoleRelation(user.getId(), roleUser.getId());

// 页面权限
Permission pagePerm = createPermission("/test", "测试页面", 1, "page:test", null, 1, 0L);
Permission testPagePerm = createPermission("/test", "测试页面", 1, "page:test", null, 1, 0L);
// 按钮权限
Permission btnQueryPerm = createPermission("/**/test", "测试页面-查询", 2, "btn:test:query", "GET", 1, pagePerm.getId());
Permission btnPermInsert = createPermission("/**/test", "测试页面-添加", 2, "btn:test:insert", "POST", 2, pagePerm.getId());

createRolePermissionRelation(roleAdmin.getId(), pagePerm.getId());
createRolePermissionRelation(roleUser.getId(), pagePerm.getId());
createRolePermissionRelation(roleAdmin.getId(), btnQueryPerm.getId());
createRolePermissionRelation(roleUser.getId(), btnQueryPerm.getId());
createRolePermissionRelation(roleAdmin.getId(), btnPermInsert.getId());
Permission testBtnQueryPerm = createPermission("/**/test", "测试页面-查询", 2, "btn:test:query", "GET", 1, testPagePerm.getId());
Permission testBtnPermInsert = createPermission("/**/test", "测试页面-添加", 2, "btn:test:insert", "POST", 2, testPagePerm.getId());

Permission monitorOnlinePagePerm = createPermission("/monitor", "监控在线用户页面", 1, "page:monitor:online", null, 2, 0L);
Permission monitorOnlineBtnQueryPerm = createPermission("/**/api/monitor/online/user/**", "在线用户页面-查询", 2, "btn:monitor:online:query", "POST", 1, monitorOnlinePagePerm.getId());

createRolePermissionRelation(roleAdmin.getId(), testPagePerm.getId());
createRolePermissionRelation(roleUser.getId(), testPagePerm.getId());
createRolePermissionRelation(roleAdmin.getId(), testBtnQueryPerm.getId());
createRolePermissionRelation(roleUser.getId(), testBtnQueryPerm.getId());
createRolePermissionRelation(roleAdmin.getId(), testBtnPermInsert.getId());
createRolePermissionRelation(roleAdmin.getId(), monitorOnlinePagePerm.getId());
createRolePermissionRelation(roleAdmin.getId(), monitorOnlineBtnQueryPerm.getId());
}

private void createRolePermissionRelation(Long roleId, Long permissionId) {


+ 39
- 0
spring-boot-demo-rbac-security/src/test/java/com/xkcoding/rbac/security/repository/UserDaoTest.java View File

@@ -0,0 +1,39 @@
package com.xkcoding.rbac.security.repository;

import com.xkcoding.rbac.security.SpringBootDemoRbacSecurityApplicationTests;
import com.xkcoding.rbac.security.model.User;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.util.Lists;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.Optional;

/**
* <p>
* UserDao 测试
* </p>
*
* @package: com.xkcoding.rbac.security.repository
* @description: UserDao 测试
* @author: yangkai.shen
* @date: Created in 2018-12-12 01:10
* @copyright: Copyright (c) 2018
* @version: V1.0
* @modified: yangkai.shen
*/
@Slf4j
public class UserDaoTest extends SpringBootDemoRbacSecurityApplicationTests {
@Autowired
private UserDao userDao;

@Test
public void findByUsernameIn() {
List<String> usernameList = Lists.newArrayList("admin", "user");
List<User> userList = userDao.findByUsernameIn(usernameList);
Assert.assertEquals(2, userList.size());
log.info("【userList】= {}", userList);
}
}

+ 34
- 0
spring-boot-demo-rbac-security/src/test/java/com/xkcoding/rbac/security/util/RedisUtilTest.java View File

@@ -0,0 +1,34 @@
package com.xkcoding.rbac.security.util;

import cn.hutool.json.JSONUtil;
import com.xkcoding.rbac.security.SpringBootDemoRbacSecurityApplicationTests;
import com.xkcoding.rbac.security.common.Consts;
import com.xkcoding.rbac.security.common.PageResult;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

/**
* <p>
* 测试RedisUtil
* </p>
*
* @package: com.xkcoding.rbac.security.util
* @description: 测试RedisUtil
* @author: yangkai.shen
* @date: Created in 2018-12-11 20:44
* @copyright: Copyright (c) 2018
* @version: V1.0
* @modified: yangkai.shen
*/
@Slf4j
public class RedisUtilTest extends SpringBootDemoRbacSecurityApplicationTests {
@Autowired
private RedisUtil redisUtil;

@Test
public void findKeysForPage() {
PageResult pageResult = redisUtil.findKeysForPage(Consts.REDIS_JWT_KEY_PREFIX + Consts.SYMBOL_STAR, 2, 1);
log.info("【pageResult】= {}", JSONUtil.toJsonStr(pageResult));
}
}

Loading…
Cancel
Save