diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDao.java b/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDao.java index a51a651d..abba69ec 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDao.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDao.java @@ -1,5 +1,7 @@ package cn.dev33.satoken.dao; +import java.util.List; + import cn.dev33.satoken.session.SaSession; /** @@ -8,14 +10,14 @@ import cn.dev33.satoken.session.SaSession; */ public interface SaTokenDao { - /** 常量,表示一个key永不过期 (在一个key被标注为永远不过期时返回此值) */ public static final Long NEVER_EXPIRE = -1L; /** 常量,表示系统中不存在这个缓存 (在对不存在的key获取剩余存活时间时返回此值) */ public static final Long NOT_VALUE_EXPIRE = -2L; + - + // --------------------- token相关 --------------------- /** * 根据key获取value,如果没有,则返回空 @@ -58,7 +60,9 @@ public interface SaTokenDao { * @param timeout 过期时间 */ public void updateTimeout(String key, long timeout); + + // --------------------- Session相关 --------------------- /** * 根据指定key的Session,如果没有,则返回空 @@ -101,7 +105,17 @@ public interface SaTokenDao { public void updateSessionTimeout(String sessionId, long timeout); - + // --------------------- 会话管理 --------------------- + + /** + * 搜索数据 + * @param prefix 前缀 + * @param keyword 关键字 + * @param start 开始处索引 (-1代表查询所有) + * @param size 获取数量 + * @return sessionId集合 + */ + public List searchData(String prefix, String keyword, int start, int size); } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDaoDefaultImpl.java b/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDaoDefaultImpl.java index af2fe783..c5206c7c 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDaoDefaultImpl.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDaoDefaultImpl.java @@ -2,6 +2,7 @@ package cn.dev33.satoken.dao; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Timer; import java.util.concurrent.ConcurrentHashMap; @@ -10,6 +11,7 @@ import cn.dev33.satoken.SaTokenManager; import cn.dev33.satoken.session.SaSession; import cn.dev33.satoken.util.SaTaskUtil; import cn.dev33.satoken.util.SaTaskUtil.FunctionRunClass; +import cn.dev33.satoken.util.SaTokenInsideUtil; /** * sa-token持久层默认的实现类 , 基于内存Map @@ -207,6 +209,14 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao { + // --------------------- 会话管理 + + @Override + public List searchData(String prefix, String keyword, int start, int size) { + return SaTokenInsideUtil.searchList(expireMap.keySet(), prefix, keyword, start, size); + } + + diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java index c8060c57..25a9472e 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java @@ -202,7 +202,6 @@ public class StpLogic { } } - /** * 当前会话注销登录 */ @@ -219,7 +218,6 @@ public class StpLogic { logoutByTokenValue(tokenValue); } - /** * 指定token的会话注销登录 * @param tokenValue 指定token @@ -246,7 +244,6 @@ public class StpLogic { session.logoutByTokenSignCountToZero(); } - /** * 指定loginId的会话注销登录(踢人下线) *

当对方再次访问系统时,会抛出NotLoginException异常,场景值=-2 @@ -287,7 +284,6 @@ public class StpLogic { session.logoutByTokenSignCountToZero(); } - // 查询相关 /** @@ -299,7 +295,6 @@ public class StpLogic { return getLoginIdDefaultNull() != null; } - /** * 检验当前会话是否已经登录,如未登录,则抛出异常 */ @@ -307,7 +302,6 @@ public class StpLogic { getLoginId(); } - /** * 获取当前会话账号id, 如果未登录,则抛出异常 * @return 账号id @@ -342,7 +336,6 @@ public class StpLogic { return loginId; } - /** * 获取当前会话登录id, 如果未登录,则返回默认值 * @param 返回类型 @@ -369,7 +362,6 @@ public class StpLogic { return (T)loginId; } - /** * 获取当前会话登录id, 如果未登录,则返回null * @return 账号id @@ -393,7 +385,6 @@ public class StpLogic { return loginId; } - /** * 获取当前会话登录id, 并转换为String * @return 账号id @@ -402,7 +393,6 @@ public class StpLogic { return String.valueOf(getLoginId()); } - /** * 获取当前会话登录id, 并转换为int * @return 账号id @@ -415,7 +405,6 @@ public class StpLogic { return Integer.valueOf(String.valueOf(getLoginId())); } - /** * 获取当前会话登录id, 并转换为long * @return 账号id @@ -428,7 +417,6 @@ public class StpLogic { return Long.valueOf(String.valueOf(getLoginId())); } - /** * 获取指定token对应的登录id,如果未登录,则返回 null * @param tokenValue token @@ -462,6 +450,14 @@ public class StpLogic { return session; } + /** + * 获取指定key的session, 如果session尚未创建,则返回null + * @param sessionId sessionId + * @return session对象 + */ + public SaSession getSessionBySessionId(String sessionId) { + return getSessionBySessionId(sessionId, false); + } /** * 获取指定loginId的session, 如果session尚未创建,isCreate=是否新建并返回 @@ -473,7 +469,6 @@ public class StpLogic { return getSessionBySessionId(getKeySession(loginId), isCreate); } - /** * 获取指定loginId的session,如果session尚未创建,则新建并返回 * @param loginId 账号id @@ -483,7 +478,6 @@ public class StpLogic { return getSessionByLoginId(loginId, true); } - /** * 获取当前会话的session, 如果session尚未创建,isCreate=是否新建并返回 * @param isCreate 是否新建 @@ -493,7 +487,6 @@ public class StpLogic { return getSessionByLoginId(getLoginId(), isCreate); } - /** * 获取当前会话的session,如果session尚未创建,则新建并返回 * @return 当前会话的session @@ -505,7 +498,6 @@ public class StpLogic { // =================== token专属session =================== - /** * 获取指定token的专属session,如果session尚未创建,isCreate代表是否新建并返回 * @param tokenValue token值 @@ -516,7 +508,6 @@ public class StpLogic { return getSessionBySessionId(getKeyTokenSession(tokenValue), isCreate); } - /** * 获取指定token的专属session,如果session尚未创建,则新建并返回 * @param tokenValue token值 @@ -526,7 +517,6 @@ public class StpLogic { return getSessionBySessionId(getKeyTokenSession(tokenValue), true); } - /** * 获取当前token的专属-session,如果session尚未创建,isCreate代表是否新建并返回 * @param isCreate 是否新建 @@ -547,7 +537,6 @@ public class StpLogic { return getSessionBySessionId(getKeyTokenSession(getTokenValue()), isCreate); } - /** * 获取当前token的专属-session,如果session尚未创建,则新建并返回 * @return session会话 @@ -559,7 +548,6 @@ public class StpLogic { // =================== [临时过期] 验证相关 =================== - /** * 写入指定token的 [最后操作时间] 为当前时间戳 * @param tokenValue 指定token @@ -573,7 +561,6 @@ public class StpLogic { SaTokenManager.getSaTokenDao().setValue(getKeyLastActivityTime(tokenValue), String.valueOf(System.currentTimeMillis()), getConfig().getTimeout()); } - /** * 清除指定token的 [最后操作时间] * @param tokenValue 指定token @@ -589,7 +576,6 @@ public class StpLogic { SaTokenManager.getSaTokenServlet().getRequest().removeAttribute(SaTokenConsts.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY); } - /** * 检查指定token 是否已经[临时过期],如果已经过期则抛出异常 * @param tokenValue 指定token @@ -621,7 +607,6 @@ public class StpLogic { request.setAttribute(SaTokenConsts.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY, true); } - /** * 检查当前token 是否已经[临时过期],如果已经过期则抛出异常 */ @@ -629,7 +614,6 @@ public class StpLogic { checkActivityTimeout(getTokenValue()); } - /** * 续签指定token:(将 [最后操作时间] 更新为当前时间戳) * @param tokenValue 指定token @@ -642,7 +626,6 @@ public class StpLogic { SaTokenManager.getSaTokenDao().updateValue(getKeyLastActivityTime(tokenValue), String.valueOf(System.currentTimeMillis())); } - /** * 续签当前token:(将 [最后操作时间] 更新为当前时间戳) *

请注意: 即时token已经 [临时过期] 也可续签成功, @@ -653,7 +636,6 @@ public class StpLogic { } - // =================== 过期时间相关 =================== /** @@ -965,6 +947,42 @@ public class StpLogic { } + // =================== 会话管理 =================== + + /** + * 根据条件查询token + * @param keyword 关键字 + * @param start 开始处索引 (-1代表查询所有) + * @param size 获取数量 + * @return token集合 + */ + public List searchTokenValue(String keyword, int start, int size) { + return SaTokenManager.getSaTokenDao().searchData(getKeyTokenValue(""), keyword, start, size); + } + + /** + * 根据条件查询SessionId + * @param keyword 关键字 + * @param start 开始处索引 (-1代表查询所有) + * @param size 获取数量 + * @return sessionId集合 + */ + public List searchSessionId(String keyword, int start, int size) { + return SaTokenManager.getSaTokenDao().searchData(getKeySession(""), keyword, start, size); + } + + /** + * 根据条件查询token专属Session的Id + * @param keyword 关键字 + * @param start 开始处索引 (-1代表查询所有) + * @param size 获取数量 + * @return sessionId集合 + */ + public List searchTokenSessionId(String keyword, int start, int size) { + return SaTokenManager.getSaTokenDao().searchData(getKeyTokenSession(""), keyword, start, size); + } + + // =================== 返回相应key =================== /** diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java index 786f3ad8..8c3b0953 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java @@ -194,6 +194,15 @@ public class StpUtil { return stpLogic.getSessionByLoginId(loginId, isCreate); } + /** + * 获取指定key的session, 如果session尚未创建,则返回null + * @param sessionId sessionId + * @return session对象 + */ + public static SaSession getSessionBySessionId(String sessionId) { + return stpLogic.getSessionBySessionId(sessionId); + } + /** * 获取指定loginId的session,如果session尚未创建,则新建并返回 * @param loginId 账号id @@ -439,5 +448,42 @@ public class StpUtil { public static String getLoginDevice() { return stpLogic.getLoginDevice(); } + + // =================== 会话管理 =================== + + /** + * 根据条件查询token + * @param keyword 关键字 + * @param start 开始处索引 (-1代表查询所有) + * @param size 获取数量 + * @return token集合 + */ + public static List searchTokenValue(String keyword, int start, int size) { + return stpLogic.searchTokenValue(keyword, start, size); + } + + /** + * 根据条件查询SessionId + * @param keyword 关键字 + * @param start 开始处索引 (-1代表查询所有) + * @param size 获取数量 + * @return sessionId集合 + */ + public static List searchSessionId(String keyword, int start, int size) { + return stpLogic.searchSessionId(keyword, start, size); + } + + /** + * 根据条件查询token专属Session的Id + * @param keyword 关键字 + * @param start 开始处索引 (-1代表查询所有) + * @param size 获取数量 + * @return sessionId集合 + */ + public static List searchTokenSessionId(String keyword, int start, int size) { + return stpLogic.searchTokenSessionId(keyword, start, size); + } + + } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaTokenInsideUtil.java b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaTokenInsideUtil.java index 483a3422..57b3ec7c 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaTokenInsideUtil.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaTokenInsideUtil.java @@ -1,9 +1,13 @@ package cn.dev33.satoken.util; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; import java.util.Random; /** - * sa-token 工具类 + * sa-token 内部代码工具类 * @author kong * */ @@ -49,4 +53,58 @@ public class SaTokenInsideUtil { } + /** + * 从集合里查询数据 + * @param dataList 数据集合 + * @param prefix 前缀 + * @param keyword 关键字 + * @param start 起始位置 (-1代表查询所有) + * @param size 获取条数 + * @return 符合条件的新数据集合 + */ + public static List searchList(Collection dataList, String prefix, String keyword, int start, int size) { + if(prefix == null) { + prefix = ""; + } + if(keyword == null) { + keyword = ""; + } + // 挑选出所有符合条件的 + List list = new ArrayList(); + Iterator keys = dataList.iterator(); + while (keys.hasNext()) { + String key = keys.next(); + if(key.startsWith(prefix) && key.indexOf(keyword) > -1) { + list.add(key); + } + } + // 取指定段数据 + return searchList(list, start, size); + } + + /** + * 从集合里查询数据 + * @param list 数据集合 + * @param start 起始位置 (-1代表查询所有) + * @param size 获取条数 + * @return 符合条件的新数据集合 + */ + public static List searchList(List list, int start, int size) { + // 取指定段数据 + if(start < 0) { + return list; + } + int end = start + size; + List list2 = new ArrayList(); + for (int i = start; i < end; i++) { + if(i >= list.size()) { + return list2; + } + list2.add(list.get(i)); + } + return list2; + } + + + } diff --git a/sa-token-dao-redis-jackson/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisJackson.java b/sa-token-dao-redis-jackson/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisJackson.java index e0af12ba..7292c40a 100644 --- a/sa-token-dao-redis-jackson/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisJackson.java +++ b/sa-token-dao-redis-jackson/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisJackson.java @@ -1,6 +1,9 @@ package cn.dev33.satoken.dao; import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; import java.util.concurrent.TimeUnit; import org.springframework.beans.factory.annotation.Autowired; @@ -15,6 +18,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import cn.dev33.satoken.session.SaSession; +import cn.dev33.satoken.util.SaTokenInsideUtil; /** * sa-token持久层的实现类, 基于redis (to jackson) @@ -181,5 +185,15 @@ public class SaTokenDaoRedisJackson implements SaTokenDao { public void updateSessionTimeout(String sessionId, long timeout) { sessionRedisTemplate.expire(sessionId, timeout, TimeUnit.SECONDS); } + + /** + * 搜索数据 + */ + @Override + public List searchData(String prefix, String keyword, int start, int size) { + Set keys = stringRedisTemplate.keys(prefix + "*" + keyword + "*"); + List list = new ArrayList(keys); + return SaTokenInsideUtil.searchList(list, start, size); + } } diff --git a/sa-token-dao-redis/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedis.java b/sa-token-dao-redis/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedis.java index 81d5e0be..266d0c96 100644 --- a/sa-token-dao-redis/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedis.java +++ b/sa-token-dao-redis/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedis.java @@ -1,5 +1,8 @@ package cn.dev33.satoken.dao; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; import java.util.concurrent.TimeUnit; import org.springframework.beans.factory.annotation.Autowired; @@ -11,6 +14,7 @@ import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.stereotype.Component; import cn.dev33.satoken.session.SaSession; +import cn.dev33.satoken.util.SaTokenInsideUtil; /** * sa-token持久层的实现类, 基于redis @@ -162,5 +166,18 @@ public class SaTokenDaoRedis implements SaTokenDao { public void updateSessionTimeout(String sessionId, long timeout) { sessionRedisTemplate.expire(sessionId, timeout, TimeUnit.SECONDS); } + + + + /** + * 搜索数据 + */ + @Override + public List searchData(String prefix, String keyword, int start, int size) { + Set keys = stringRedisTemplate.keys(prefix + "*" + keyword + "*"); + List list = new ArrayList(keys); + return SaTokenInsideUtil.searchList(list, start, size); + } + } diff --git a/sa-token-demo-springboot/src/main/java/com/pj/test/GlobalException.java b/sa-token-demo-springboot/src/main/java/com/pj/test/GlobalException.java index d49a6782..f128bcac 100644 --- a/sa-token-demo-springboot/src/main/java/com/pj/test/GlobalException.java +++ b/sa-token-demo-springboot/src/main/java/com/pj/test/GlobalException.java @@ -9,6 +9,8 @@ import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RestControllerAdvice; +import com.pj.util.AjaxJson; + import cn.dev33.satoken.exception.NotLoginException; import cn.dev33.satoken.exception.NotPermissionException; import cn.dev33.satoken.exception.NotRoleException; diff --git a/sa-token-demo-springboot/src/main/java/com/pj/test/StressTestController.java b/sa-token-demo-springboot/src/main/java/com/pj/test/StressTestController.java new file mode 100644 index 00000000..640d65dd --- /dev/null +++ b/sa-token-demo-springboot/src/main/java/com/pj/test/StressTestController.java @@ -0,0 +1,62 @@ +package com.pj.test; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.pj.util.AjaxJson; +import com.pj.util.Ttime; + +import cn.dev33.satoken.stp.StpUtil; + +/** + * 压力测试 + * @author kong + * + */ +@RestController +@RequestMapping("/s-test/") +public class StressTestController { + + + // 测试 浏览器访问: http://localhost:8081/s-test/login + // 测试前,请先将 is-read-cookie 配置为 false + @RequestMapping("login") + public AjaxJson login() { +// StpUtil.getTokenSession().logout(); +// StpUtil.logoutByLoginId(10001); + // 循环10次 取平均时间 + List list = new ArrayList<>(); + for (int i = 10; i <= 1; i++) { + System.out.println("\n---------------------第" + i + "轮---------------------"); + Ttime t = new Ttime().start(); + // 每次登录的次数 + for (int j = 1; j <= 10000; j++) { + StpUtil.setLoginId("1000" + j, "PC-" + j); + if(j % 1000 == 0) { + System.out.println("已登录:" + j); + } + } + t.end(); + list.add((t.returnMs() + 0.0) / 1000); + System.out.println("第" + i + "轮" + "用时:" + t.toString()); + } +// System.out.println(((SaTokenDaoDefaultImpl)SaTokenManager.getSaTokenDao()).dataMap.size()); + + System.out.println("\n---------------------测试结果---------------------"); + System.out.println(list.size() + "次测试: " + list); + double ss = 0; + for (int i = 0; i < list.size(); i++) { + ss += list.get(i); + } + System.out.println("平均用时: " + ss / list.size()); + return AjaxJson.getSuccess(); + } + + + + + +} diff --git a/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java b/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java index a45f1f7a..7e3896d2 100644 --- a/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java +++ b/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java @@ -1,6 +1,7 @@ package com.pj.test; import java.util.Date; +import java.util.List; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -8,6 +9,8 @@ import org.springframework.web.bind.annotation.RestController; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.pj.util.AjaxJson; +import com.pj.util.Ttime; import cn.dev33.satoken.annotation.SaCheckLogin; import cn.dev33.satoken.annotation.SaCheckPermission; @@ -191,17 +194,7 @@ public class TestController { // 返回 return AjaxJson.getSuccess(); } - - // 测试 浏览器访问: http://localhost:8081/test/test - @RequestMapping("test") - public AjaxJson test() { -// StpUtil.getTokenSession().logout(); - StpUtil.logoutByLoginId(10001); - return AjaxJson.getSuccess(); - } - - // 测试登录接口, 按照设备登录, 浏览器访问: http://localhost:8081/test/login2 @RequestMapping("login2") public AjaxJson login2(@RequestParam(defaultValue="10001") String id, @RequestParam(defaultValue="PC") String device) { @@ -209,4 +202,30 @@ public class TestController { return AjaxJson.getSuccess(); } + + // 测试 浏览器访问: http://localhost:8081/test/searchSession + // 测试前,请先将 is-read-cookie 配置为 false + @RequestMapping("searchSession") + public AjaxJson searchSession() { + System.out.println("--------------"); + Ttime t = new Ttime().start(); + List tokenValue = StpUtil.searchTokenValue("", 0, 10); + for (String v : tokenValue) { +// SaSession session = StpUtil.getSessionBySessionId(sid); + System.out.println(v); + } + System.out.println("用时:" + t.end().toString()); + return AjaxJson.getSuccess(); + } + + + // 测试 浏览器访问: http://localhost:8081/test/test + @RequestMapping("test") + public AjaxJson test() { + StpUtil.getTokenSession().logout(); + StpUtil.logoutByLoginId(10001); + return AjaxJson.getSuccess(); + } + + } diff --git a/sa-token-demo-springboot/src/main/java/com/pj/test/AjaxJson.java b/sa-token-demo-springboot/src/main/java/com/pj/util/AjaxJson.java similarity index 99% rename from sa-token-demo-springboot/src/main/java/com/pj/test/AjaxJson.java rename to sa-token-demo-springboot/src/main/java/com/pj/util/AjaxJson.java index 1581888d..768d0578 100644 --- a/sa-token-demo-springboot/src/main/java/com/pj/test/AjaxJson.java +++ b/sa-token-demo-springboot/src/main/java/com/pj/util/AjaxJson.java @@ -1,4 +1,4 @@ -package com.pj.test; +package com.pj.util; import java.io.Serializable; import java.util.List; diff --git a/sa-token-demo-springboot/src/main/java/com/pj/util/Ttime.java b/sa-token-demo-springboot/src/main/java/com/pj/util/Ttime.java new file mode 100644 index 00000000..cb17dcaa --- /dev/null +++ b/sa-token-demo-springboot/src/main/java/com/pj/util/Ttime.java @@ -0,0 +1,63 @@ +package com.pj.util; + + +/** + * 用于测试用时 + * @author kong + * + */ +public class Ttime { + + private long start=0; //开始时间 + private long end=0; //结束时间 + + public static Ttime t = new Ttime(); //static快捷使用 + + /** + * 开始计时 + * @return + */ + public Ttime start() { + start=System.currentTimeMillis(); + return this; + } + + + /** + * 结束计时 + */ + public Ttime end() { + end=System.currentTimeMillis(); + return this; + } + + + /** + * 返回所用毫秒数 + */ + public long returnMs() { + return end-start; + } + + /** + * 格式化输出结果 + */ + public void outTime() { + System.out.println(this.toString()); + } + + /** + * 结束并格式化输出结果 + */ + public void endOutTime() { + this.end().outTime(); + } + + @Override + public String toString() { + return (returnMs() + 0.0) / 1000 + "s"; // 格式化为:0.01s + } + + + +} diff --git a/sa-token-demo-springboot/src/main/resources/application.yml b/sa-token-demo-springboot/src/main/resources/application.yml index 118661fb..57c1bcd0 100644 --- a/sa-token-demo-springboot/src/main/resources/application.yml +++ b/sa-token-demo-springboot/src/main/resources/application.yml @@ -18,11 +18,14 @@ spring: # token风格 token-style: uuid + # 是否从cookie里读取token + # is-read-cookie: false + # redis配置 redis: # Redis数据库索引(默认为0) - database: 1 + database: 0 # Redis服务器地址 host: 127.0.0.1 # Redis服务器连接端口 @@ -30,7 +33,7 @@ spring: # Redis服务器连接密码(默认为空) password: # 连接超时时间(毫秒) - timeout: 1000ms + timeout: 10000ms lettuce: pool: # 连接池最大连接数 diff --git a/sa-token-doc/doc/_sidebar.md b/sa-token-doc/doc/_sidebar.md index e76e2dce..f6d1b079 100644 --- a/sa-token-doc/doc/_sidebar.md +++ b/sa-token-doc/doc/_sidebar.md @@ -18,6 +18,7 @@ - [注解式鉴权](/use/at-check) - [花式token](/use/token-style) - [框架配置](/use/config) + - [会话治理](/use/search-session) - **其它** - [常见问题](/more/common-questions) diff --git a/sa-token-doc/doc/use/search-session.md b/sa-token-doc/doc/use/search-session.md new file mode 100644 index 00000000..f5412d06 --- /dev/null +++ b/sa-token-doc/doc/use/search-session.md @@ -0,0 +1,48 @@ +# 会话治理 + +尽管框架将大部分操作提供了简易的封装,但在一些特殊场景下,我们仍需要绕过框架,直达数据底层进行一些操作
+sa-token提供以下API助你直接操作会话列表 + + +--- + +## 具体API + +#### 查询所有token +``` java +StpUtil.searchTokenValue(String keyword, int start, int size); +``` + +#### 查询所有账号Session会话 +``` java +StpUtil.searchSessionId(String keyword, int start, int size); +``` + + +#### 查询所有令牌Session会话 +``` java +StpUtil.searchTokenSessionId(String keyword, int start, int size); +``` + + +#### 参数详解: +- `keyword`: 查询关键字,只有包括这个字符串的token值才会被查询出来 +- `start`: 数据开始处索引, 值为-1时代表一次性取出所有数据 +- `size`: 要获取的数据条数 + +使用示例: +``` java +StpUtil.searchTokenValue("1000", 0, 10); // 查询value包括1000的所有token,结果集从第0条开始,返回10条 +``` + + +
+ +#### 注意事项: +由于会话查询底层采用了遍历方式获取数据,当数据量过大时此操作将会比较耗时,有多耗时呢?这里提供一份参考数据: +- 单机模式下:百万会话取出10条token平均耗时 `0.255s` +- Redis模式下:百万会话取出10条token平均耗时 `3.322s` + +请根据业务实际水平合理调用API + +