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 8cb3f6ea..4338c530 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 @@ -15,7 +15,6 @@ */ package cn.dev33.satoken.dao; -import cn.dev33.satoken.SaManager; import cn.dev33.satoken.session.SaSession; import java.util.List; @@ -95,10 +94,7 @@ public interface SaTokenDao { * @param key 键名称 * @return object */ - default Object getObject(String key) { - String jsonString = get(key); - return SaManager.getSaJsonTemplate().jsonToObject(jsonString); - } + Object getObject(String key); /** * 写入 Object,并设定存活时间 (单位: 秒) @@ -107,46 +103,34 @@ public interface SaTokenDao { * @param object 值 * @param timeout 存活时间(值大于0时限时存储,值=-1时永久存储,值=0或小于-2时不存储) */ - default void setObject(String key, Object object, long timeout) { - String jsonString = SaManager.getSaJsonTemplate().objectToJson(object); - set(key, jsonString, timeout); - } + void setObject(String key, Object object, long timeout); /** * 更新 Object (过期时间不变) * @param key 键名称 * @param object 值 */ - default void updateObject(String key, Object object) { - String jsonString = SaManager.getSaJsonTemplate().objectToJson(object); - update(key, jsonString); - } + void updateObject(String key, Object object); /** * 删除 Object * @param key 键名称 */ - default void deleteObject(String key) { - delete(key); - } + void deleteObject(String key); /** * 获取 Object 的剩余存活时间 (单位: 秒) * @param key 指定 key * @return 这个 key 的剩余存活时间 */ - default long getObjectTimeout(String key) { - return getTimeout(key); - } + long getObjectTimeout(String key); /** * 修改 Object 的剩余存活时间(单位: 秒) * @param key 指定 key * @param timeout 剩余存活时间 */ - default void updateObjectTimeout(String key, long timeout) { - updateTimeout(key, timeout); - } + void updateObjectTimeout(String key, long timeout); // --------------------- SaSession 读写 (默认复用 Object 读写方法) --------------------- @@ -156,52 +140,40 @@ public interface SaTokenDao { * @param sessionId sessionId * @return SaSession */ - default SaSession getSession(String sessionId) { - return (SaSession)getObject(sessionId); - } + SaSession getSession(String sessionId); /** * 写入 SaSession,并设定存活时间(单位: 秒) * @param session 要保存的 SaSession 对象 * @param timeout 过期时间(单位: 秒) */ - default void setSession(SaSession session, long timeout) { - setObject(session.getId(), session, timeout); - } + void setSession(SaSession session, long timeout); /** * 更新 SaSession * @param session 要更新的 SaSession 对象 */ - default void updateSession(SaSession session) { - updateObject(session.getId(), session); - } + void updateSession(SaSession session); /** * 删除 SaSession * @param sessionId sessionId */ - default void deleteSession(String sessionId) { - deleteObject(sessionId); - } + void deleteSession(String sessionId); /** * 获取 SaSession 剩余存活时间(单位: 秒) * @param sessionId 指定 SaSession * @return 这个 SaSession 的剩余存活时间 */ - default long getSessionTimeout(String sessionId) { - return getObjectTimeout(sessionId); - } + long getSessionTimeout(String sessionId); /** * 修改 SaSession 剩余存活时间(单位: 秒) * @param sessionId 指定 SaSession * @param timeout 剩余存活时间 */ - default void updateSessionTimeout(String sessionId, long timeout) { - updateObjectTimeout(sessionId, timeout); - } + void updateSessionTimeout(String sessionId, long timeout); // --------------------- 会话管理 --------------------- 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 c4be1998..6a1cb6df 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 @@ -16,250 +16,71 @@ package cn.dev33.satoken.dao; -import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.dao.auto.SaTokenDaoByStringFollowObject; +import cn.dev33.satoken.dao.timedcache.SaTimedCache; import cn.dev33.satoken.util.SaFoxUtil; import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; /** - * Sa-Token 持久层接口,默认实现类(基于内存 Map,系统重启后数据丢失) + * Sa-Token 持久层接口,默认实现类,基于 SaTimedCache (内存 Map,系统重启后数据丢失) * * @author click33 * @since 1.10.0 */ -public class SaTokenDaoDefaultImpl implements SaTokenDao { - - /** - * 存储数据的集合 - */ - public Map dataMap = new ConcurrentHashMap<>(); - - /** - * 存储数据过期时间的集合(单位: 毫秒), 记录所有 key 的到期时间 (注意存储的是到期时间,不是剩余存活时间) - */ - public Map expireMap = new ConcurrentHashMap<>(); - - // ------------------------ String 读写操作 - - @Override - public String get(String key) { - clearKeyByTimeout(key); - return (String)dataMap.get(key); - } - - @Override - public void set(String key, String value, long timeout) { - if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) { - return; - } - dataMap.put(key, value); - expireMap.put(key, (timeout == SaTokenDao.NEVER_EXPIRE) ? (SaTokenDao.NEVER_EXPIRE) : (System.currentTimeMillis() + timeout * 1000)); - } - - @Override - public void update(String key, String value) { - if(getKeyTimeout(key) == SaTokenDao.NOT_VALUE_EXPIRE) { - return; - } - dataMap.put(key, value); - } - - @Override - public void delete(String key) { - dataMap.remove(key); - expireMap.remove(key); - } - - @Override - public long getTimeout(String key) { - return getKeyTimeout(key); - } - - @Override - public void updateTimeout(String key, long timeout) { - expireMap.put(key, (timeout == SaTokenDao.NEVER_EXPIRE) ? (SaTokenDao.NEVER_EXPIRE) : (System.currentTimeMillis() + timeout * 1000)); - } +public class SaTokenDaoDefaultImpl implements SaTokenDaoByStringFollowObject { + public SaTimedCache timedCache = new SaTimedCache(); // ------------------------ Object 读写操作 @Override public Object getObject(String key) { - clearKeyByTimeout(key); - return dataMap.get(key); + return timedCache.getObject(key); } @Override public void setObject(String key, Object object, long timeout) { - if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) { - return; - } - dataMap.put(key, object); - expireMap.put(key, (timeout == SaTokenDao.NEVER_EXPIRE) ? (SaTokenDao.NEVER_EXPIRE) : (System.currentTimeMillis() + timeout * 1000)); + timedCache.setObject(key, object, timeout); } @Override public void updateObject(String key, Object object) { - if(getKeyTimeout(key) == SaTokenDao.NOT_VALUE_EXPIRE) { - return; - } - dataMap.put(key, object); + timedCache.updateObject(key, object); } @Override public void deleteObject(String key) { - dataMap.remove(key); - expireMap.remove(key); + timedCache.deleteObject(key); } @Override public long getObjectTimeout(String key) { - return getKeyTimeout(key); + return timedCache.getObjectTimeout(key); } @Override public void updateObjectTimeout(String key, long timeout) { - expireMap.put(key, (timeout == SaTokenDao.NEVER_EXPIRE) ? (SaTokenDao.NEVER_EXPIRE) : (System.currentTimeMillis() + timeout * 1000)); + timedCache.updateObjectTimeout(key, timeout); } - - - // ------------------------ Session 读写操作 - // 使用接口默认实现 // --------- 会话管理 @Override public List searchData(String prefix, String keyword, int start, int size, boolean sortType) { - return SaFoxUtil.searchList(expireMap.keySet(), prefix, keyword, start, size, sortType); + return SaFoxUtil.searchList(timedCache.expireMap.keySet(), prefix, keyword, start, size, sortType); } - // ------------------------ 以下是一个定时缓存的简单实现,采用:惰性检查 + 异步循环扫描 - - // --------- 过期时间相关操作 - - /** - * 如果指定的 key 已经过期,则立即清除它 - * @param key 指定 key - */ - void clearKeyByTimeout(String key) { - Long expirationTime = expireMap.get(key); - // 清除条件: - // 1、数据存在。 - // 2、不是 [ 永不过期 ]。 - // 3、已经超过过期时间。 - if(expirationTime != null && expirationTime != SaTokenDao.NEVER_EXPIRE && expirationTime < System.currentTimeMillis()) { - dataMap.remove(key); - expireMap.remove(key); - } - } - - /** - * 获取指定 key 的剩余存活时间 (单位:秒) - * @param key 指定 key - * @return 这个 key 的剩余存活时间 - */ - long getKeyTimeout(String key) { - // 由于数据过期检测属于惰性扫描,很可能此时这个 key 已经是过期状态了,所以这里需要先检查一下 - clearKeyByTimeout(key); - - // 获取这个 key 的过期时间 - Long expire = expireMap.get(key); - - // 如果 expire 数据不存在,说明框架没有存储这个 key,此时返回 NOT_VALUE_EXPIRE - if(expire == null) { - return SaTokenDao.NOT_VALUE_EXPIRE; - } - - // 如果 expire 被标注为永不过期,则返回 NEVER_EXPIRE - if(expire == SaTokenDao.NEVER_EXPIRE) { - return SaTokenDao.NEVER_EXPIRE; - } - - // ---- 代码至此,说明这个 key 是有过期时间的,且未过期,那么: - - // 计算剩余时间并返回 (过期时间戳 - 当前时间戳) / 1000 转秒 - long timeout = (expire - System.currentTimeMillis()) / 1000; - - // 小于零时,视为不存在 - if(timeout < 0) { - dataMap.remove(key); - expireMap.remove(key); - return SaTokenDao.NOT_VALUE_EXPIRE; - } - return timeout; - } - - // --------- 定时清理过期数据 - - /** - * 执行数据清理的线程引用 - */ - public Thread refreshThread; - - /** - * 是否继续执行数据清理的线程标记 - */ - public volatile boolean refreshFlag; - - /** - * 清理所有已经过期的 key - */ - public void refreshDataMap() { - for (String s : expireMap.keySet()) { - clearKeyByTimeout(s); - } - } - - /** - * 初始化定时任务,定时清理过期数据 - */ - public void initRefreshThread() { - - // 如果开发者配置了 <=0 的值,则不启动定时清理 - if(SaManager.getConfig().getDataRefreshPeriod() <= 0) { - return; - } - - // 启动定时刷新 - this.refreshFlag = true; - this.refreshThread = new Thread(() -> { - for (;;) { - try { - try { - // 如果已经被标记为结束 - if( ! refreshFlag) { - return; - } - // 执行清理 - refreshDataMap(); - } catch (Exception e) { - e.printStackTrace(); - } - // 休眠N秒 - int dataRefreshPeriod = SaManager.getConfig().getDataRefreshPeriod(); - if(dataRefreshPeriod <= 0) { - dataRefreshPeriod = 1; - } - Thread.sleep(dataRefreshPeriod * 1000L); - } catch (Exception e) { - e.printStackTrace(); - } - } - }); - this.refreshThread.start(); - } - + // --------- 组件生命周期 /** * 组件被安装时,开始刷新数据线程 */ @Override public void init() { - initRefreshThread(); + timedCache.initRefreshThread(); } /** @@ -267,6 +88,6 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao { */ @Override public void destroy() { - this.refreshFlag = false; + timedCache.endRefreshThread(); } } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/dao/auto/SaTokenDaoByObjectFollowStringUseJsonSerializer.java b/sa-token-core/src/main/java/cn/dev33/satoken/dao/auto/SaTokenDaoByObjectFollowStringUseJsonSerializer.java new file mode 100644 index 00000000..dce09e7c --- /dev/null +++ b/sa-token-core/src/main/java/cn/dev33/satoken/dao/auto/SaTokenDaoByObjectFollowStringUseJsonSerializer.java @@ -0,0 +1,95 @@ +/* + * Copyright 2020-2099 sa-token.cc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.dev33.satoken.dao.auto; + +import cn.dev33.satoken.SaManager; + +/** + * SaTokenDao 次级实现,以 JSON 序列化方式实现 Object 读写相关操作 + * + * @author click33 + * @since 1.41.0 + */ +public interface SaTokenDaoByObjectFollowStringUseJsonSerializer extends SaTokenDaoBySessionFollowObject { + + // --------------------- Object 读写 --------------------- + + /** + * 获取 Object,如无返空 + * + * @param key 键名称 + * @return object + */ + @Override + default Object getObject(String key) { + String jsonString = get(key); + return SaManager.getSaJsonTemplate().jsonToObject(jsonString); + } + + /** + * 写入 Object,并设定存活时间 (单位: 秒) + * + * @param key 键名称 + * @param object 值 + * @param timeout 存活时间(值大于0时限时存储,值=-1时永久存储,值=0或小于-2时不存储) + */ + @Override + default void setObject(String key, Object object, long timeout) { + String jsonString = SaManager.getSaJsonTemplate().objectToJson(object); + set(key, jsonString, timeout); + } + + /** + * 更新 Object (过期时间不变) + * @param key 键名称 + * @param object 值 + */ + @Override + default void updateObject(String key, Object object) { + String jsonString = SaManager.getSaJsonTemplate().objectToJson(object); + update(key, jsonString); + } + + /** + * 删除 Object + * @param key 键名称 + */ + @Override + default void deleteObject(String key) { + delete(key); + } + + /** + * 获取 Object 的剩余存活时间 (单位: 秒) + * @param key 指定 key + * @return 这个 key 的剩余存活时间 + */ + @Override + default long getObjectTimeout(String key) { + return getTimeout(key); + } + + /** + * 修改 Object 的剩余存活时间(单位: 秒) + * @param key 指定 key + * @param timeout 剩余存活时间 + */ + @Override + default void updateObjectTimeout(String key, long timeout) { + updateTimeout(key, timeout); + } + +} diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/dao/auto/SaTokenDaoBySessionFollowObject.java b/sa-token-core/src/main/java/cn/dev33/satoken/dao/auto/SaTokenDaoBySessionFollowObject.java new file mode 100644 index 00000000..a02dba31 --- /dev/null +++ b/sa-token-core/src/main/java/cn/dev33/satoken/dao/auto/SaTokenDaoBySessionFollowObject.java @@ -0,0 +1,83 @@ +/* + * Copyright 2020-2099 sa-token.cc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.dev33.satoken.dao.auto; + +import cn.dev33.satoken.dao.SaTokenDao; +import cn.dev33.satoken.session.SaSession; + +/** + * SaTokenDao 次级实现:SaSession 读写跟随 Object 读写 + * + * @author click33 + * @since 1.41.0 + */ +public interface SaTokenDaoBySessionFollowObject extends SaTokenDao { + + // --------------------- SaSession 读写 (默认复用 Object 读写方法) --------------------- + + /** + * 获取 SaSession,如无返空 + * @param sessionId sessionId + * @return SaSession + */ + default SaSession getSession(String sessionId) { + return (SaSession)getObject(sessionId); + } + + /** + * 写入 SaSession,并设定存活时间(单位: 秒) + * @param session 要保存的 SaSession 对象 + * @param timeout 过期时间(单位: 秒) + */ + default void setSession(SaSession session, long timeout) { + setObject(session.getId(), session, timeout); + } + + /** + * 更新 SaSession + * @param session 要更新的 SaSession 对象 + */ + default void updateSession(SaSession session) { + updateObject(session.getId(), session); + } + + /** + * 删除 SaSession + * @param sessionId sessionId + */ + default void deleteSession(String sessionId) { + deleteObject(sessionId); + } + + /** + * 获取 SaSession 剩余存活时间(单位: 秒) + * @param sessionId 指定 SaSession + * @return 这个 SaSession 的剩余存活时间 + */ + default long getSessionTimeout(String sessionId) { + return getObjectTimeout(sessionId); + } + + /** + * 修改 SaSession 剩余存活时间(单位: 秒) + * @param sessionId 指定 SaSession + * @param timeout 剩余存活时间 + */ + default void updateSessionTimeout(String sessionId, long timeout) { + updateObjectTimeout(sessionId, timeout); + } + +} diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/dao/auto/SaTokenDaoByStringFollowObject.java b/sa-token-core/src/main/java/cn/dev33/satoken/dao/auto/SaTokenDaoByStringFollowObject.java new file mode 100644 index 00000000..145f58b3 --- /dev/null +++ b/sa-token-core/src/main/java/cn/dev33/satoken/dao/auto/SaTokenDaoByStringFollowObject.java @@ -0,0 +1,58 @@ +/* + * Copyright 2020-2099 sa-token.cc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.dev33.satoken.dao.auto; + +/** + * SaTokenDao 次级实现:String 读写跟随 Object 读写 + * + * @author click33 + * @since 1.41.0 + */ +public interface SaTokenDaoByStringFollowObject extends SaTokenDaoBySessionFollowObject { + + // --------------------- String 读写 --------------------- + + @Override + default String get(String key) { + return (String) getObject(key); + } + + @Override + default void set(String key, String value, long timeout) { + setObject(key, value, timeout); + } + + @Override + default void update(String key, String value) { + updateObject(key, value); + } + + @Override + default void delete(String key) { + deleteObject(key); + } + + @Override + default long getTimeout(String key) { + return getObjectTimeout(key); + } + + @Override + default void updateTimeout(String key, long timeout) { + updateObjectTimeout(key, timeout); + } + +} diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/dao/timedcache/SaTimedCache.java b/sa-token-core/src/main/java/cn/dev33/satoken/dao/timedcache/SaTimedCache.java new file mode 100644 index 00000000..fcdb5c40 --- /dev/null +++ b/sa-token-core/src/main/java/cn/dev33/satoken/dao/timedcache/SaTimedCache.java @@ -0,0 +1,201 @@ +/* + * Copyright 2020-2099 sa-token.cc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.dev33.satoken.dao.timedcache; + + +import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.dao.SaTokenDao; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 一个定时缓存的简单实现,采用:惰性检查 + 异步循环扫描 + * + * @author click33 + * @since 1.41.0 + */ +public class SaTimedCache { + + /** + * 存储数据的集合 + */ + public Map dataMap = new ConcurrentHashMap<>(); + + /** + * 存储数据过期时间的集合(单位: 毫秒), 记录所有 key 的到期时间 (注意存储的是到期时间,不是剩余存活时间) + */ + public Map expireMap = new ConcurrentHashMap<>(); + + + // ------------------------ 基础 API 读写操作 + + public Object getObject(String key) { + clearKeyByTimeout(key); + return dataMap.get(key); + } + + public void setObject(String key, Object object, long timeout) { + if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } + dataMap.put(key, object); + expireMap.put(key, (timeout == SaTokenDao.NEVER_EXPIRE) ? (SaTokenDao.NEVER_EXPIRE) : (System.currentTimeMillis() + timeout * 1000)); + } + + public void updateObject(String key, Object object) { + if(getKeyTimeout(key) == SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } + dataMap.put(key, object); + } + + public void deleteObject(String key) { + dataMap.remove(key); + expireMap.remove(key); + } + + public long getObjectTimeout(String key) { + return getKeyTimeout(key); + } + + public void updateObjectTimeout(String key, long timeout) { + expireMap.put(key, (timeout == SaTokenDao.NEVER_EXPIRE) ? (SaTokenDao.NEVER_EXPIRE) : (System.currentTimeMillis() + timeout * 1000)); + } + + + // --------- 过期时间相关操作 + + /** + * 如果指定的 key 已经过期,则立即清除它 + * @param key 指定 key + */ + void clearKeyByTimeout(String key) { + Long expirationTime = expireMap.get(key); + // 清除条件: + // 1、数据存在。 + // 2、不是 [ 永不过期 ]。 + // 3、已经超过过期时间。 + if(expirationTime != null && expirationTime != SaTokenDao.NEVER_EXPIRE && expirationTime < System.currentTimeMillis()) { + dataMap.remove(key); + expireMap.remove(key); + } + } + + /** + * 获取指定 key 的剩余存活时间 (单位:秒) + * @param key 指定 key + * @return 这个 key 的剩余存活时间 + */ + long getKeyTimeout(String key) { + // 由于数据过期检测属于惰性扫描,很可能此时这个 key 已经是过期状态了,所以这里需要先检查一下 + clearKeyByTimeout(key); + + // 获取这个 key 的过期时间 + Long expire = expireMap.get(key); + + // 如果 expire 数据不存在,说明框架没有存储这个 key,此时返回 NOT_VALUE_EXPIRE + if(expire == null) { + return SaTokenDao.NOT_VALUE_EXPIRE; + } + + // 如果 expire 被标注为永不过期,则返回 NEVER_EXPIRE + if(expire == SaTokenDao.NEVER_EXPIRE) { + return SaTokenDao.NEVER_EXPIRE; + } + + // ---- 代码至此,说明这个 key 是有过期时间的,且未过期,那么: + + // 计算剩余时间并返回 (过期时间戳 - 当前时间戳) / 1000 转秒 + long timeout = (expire - System.currentTimeMillis()) / 1000; + + // 小于零时,视为不存在 + if(timeout < 0) { + dataMap.remove(key); + expireMap.remove(key); + return SaTokenDao.NOT_VALUE_EXPIRE; + } + return timeout; + } + + // --------- 定时清理过期数据 + + /** + * 执行数据清理的线程引用 + */ + public Thread refreshThread; + + /** + * 是否继续执行数据清理的线程标记 + */ + public volatile boolean refreshFlag; + + /** + * 清理所有已经过期的 key + */ + public void refreshDataMap() { + for (String s : expireMap.keySet()) { + clearKeyByTimeout(s); + } + } + + /** + * 初始化定时任务,定时清理过期数据 + */ + public void initRefreshThread() { + + // 如果开发者配置了 <=0 的值,则不启动定时清理 + if(SaManager.getConfig().getDataRefreshPeriod() <= 0) { + return; + } + + // 启动定时刷新 + this.refreshFlag = true; + this.refreshThread = new Thread(() -> { + for (;;) { + try { + try { + // 如果已经被标记为结束 + if( ! refreshFlag) { + return; + } + // 执行清理 + refreshDataMap(); + } catch (Exception e) { + e.printStackTrace(); + } + // 休眠N秒 + int dataRefreshPeriod = SaManager.getConfig().getDataRefreshPeriod(); + if(dataRefreshPeriod <= 0) { + dataRefreshPeriod = 1; + } + Thread.sleep(dataRefreshPeriod * 1000L); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + this.refreshThread.start(); + } + + /** + * 结束定时任务 + */ + public void endRefreshThread() { + this.refreshFlag = false; + } + +} diff --git a/sa-token-dependencies/pom.xml b/sa-token-dependencies/pom.xml index d7230ac4..44e1c424 100644 --- a/sa-token-dependencies/pom.xml +++ b/sa-token-dependencies/pom.xml @@ -37,6 +37,7 @@ 1.2.83 2.0.15 3.19.0 + 5.8.36 @@ -257,6 +258,13 @@ ${jjwt.version} + + + cn.hutool + hutool-cache + ${hutool-cache.version} + + cn.dev33 diff --git a/sa-token-plugin/pom.xml b/sa-token-plugin/pom.xml index 62c1cab9..a036b008 100644 --- a/sa-token-plugin/pom.xml +++ b/sa-token-plugin/pom.xml @@ -24,12 +24,12 @@ sa-token-redis-jackson sa-token-fastjson sa-token-fastjson2 + sa-token-hutool-timed-cache sa-token-redisson-jackson sa-token-redisson-jackson2 sa-token-redisx sa-token-alone-redis - sa-token-hutool-timed-cache sa-token-dialect-thymeleaf sa-token-freemarker sa-token-sso diff --git a/sa-token-plugin/sa-token-fastjson/src/main/java/cn/dev33/satoken/plugin/SaTokenPluginFastjson.java b/sa-token-plugin/sa-token-fastjson/src/main/java/cn/dev33/satoken/plugin/SaTokenPluginForFastjson.java similarity index 94% rename from sa-token-plugin/sa-token-fastjson/src/main/java/cn/dev33/satoken/plugin/SaTokenPluginFastjson.java rename to sa-token-plugin/sa-token-fastjson/src/main/java/cn/dev33/satoken/plugin/SaTokenPluginForFastjson.java index ff40b972..ba48baee 100644 --- a/sa-token-plugin/sa-token-fastjson/src/main/java/cn/dev33/satoken/plugin/SaTokenPluginFastjson.java +++ b/sa-token-plugin/sa-token-fastjson/src/main/java/cn/dev33/satoken/plugin/SaTokenPluginForFastjson.java @@ -26,7 +26,7 @@ import cn.dev33.satoken.strategy.SaStrategy; * @author click33 * @since 1.41.0 */ -public class SaTokenPluginFastjson implements SaTokenPlugin { +public class SaTokenPluginForFastjson implements SaTokenPlugin { @Override public void setup() { diff --git a/sa-token-plugin/sa-token-fastjson/src/main/resources/META-INF/services/cn.dev33.satoken.plugin.SaTokenPlugin b/sa-token-plugin/sa-token-fastjson/src/main/resources/META-INF/services/cn.dev33.satoken.plugin.SaTokenPlugin index 1199cedf..9eddc672 100644 --- a/sa-token-plugin/sa-token-fastjson/src/main/resources/META-INF/services/cn.dev33.satoken.plugin.SaTokenPlugin +++ b/sa-token-plugin/sa-token-fastjson/src/main/resources/META-INF/services/cn.dev33.satoken.plugin.SaTokenPlugin @@ -1 +1 @@ -cn.dev33.satoken.plugin.SaTokenPluginFastjson \ No newline at end of file +cn.dev33.satoken.plugin.SaTokenPluginForFastjson \ No newline at end of file diff --git a/sa-token-plugin/sa-token-fastjson2/src/main/java/cn/dev33/satoken/plugin/SaTokenPluginFastjson2.java b/sa-token-plugin/sa-token-fastjson2/src/main/java/cn/dev33/satoken/plugin/SaTokenPluginForFastjson2.java similarity index 94% rename from sa-token-plugin/sa-token-fastjson2/src/main/java/cn/dev33/satoken/plugin/SaTokenPluginFastjson2.java rename to sa-token-plugin/sa-token-fastjson2/src/main/java/cn/dev33/satoken/plugin/SaTokenPluginForFastjson2.java index d84f8c28..9ec2059b 100644 --- a/sa-token-plugin/sa-token-fastjson2/src/main/java/cn/dev33/satoken/plugin/SaTokenPluginFastjson2.java +++ b/sa-token-plugin/sa-token-fastjson2/src/main/java/cn/dev33/satoken/plugin/SaTokenPluginForFastjson2.java @@ -26,7 +26,7 @@ import cn.dev33.satoken.strategy.SaStrategy; * @author click33 * @since 1.41.0 */ -public class SaTokenPluginFastjson2 implements SaTokenPlugin { +public class SaTokenPluginForFastjson2 implements SaTokenPlugin { @Override public void setup() { diff --git a/sa-token-plugin/sa-token-fastjson2/src/main/resources/META-INF/services/cn.dev33.satoken.plugin.SaTokenPlugin b/sa-token-plugin/sa-token-fastjson2/src/main/resources/META-INF/services/cn.dev33.satoken.plugin.SaTokenPlugin index f2234ee7..26c68f75 100644 --- a/sa-token-plugin/sa-token-fastjson2/src/main/resources/META-INF/services/cn.dev33.satoken.plugin.SaTokenPlugin +++ b/sa-token-plugin/sa-token-fastjson2/src/main/resources/META-INF/services/cn.dev33.satoken.plugin.SaTokenPlugin @@ -1 +1 @@ -cn.dev33.satoken.plugin.SaTokenPluginFastjson2 \ No newline at end of file +cn.dev33.satoken.plugin.SaTokenPluginForFastjson2 \ No newline at end of file diff --git a/sa-token-plugin/sa-token-hutool-timed-cache/pom.xml b/sa-token-plugin/sa-token-hutool-timed-cache/pom.xml index a1e3e4fb..a7423870 100644 --- a/sa-token-plugin/sa-token-hutool-timed-cache/pom.xml +++ b/sa-token-plugin/sa-token-hutool-timed-cache/pom.xml @@ -17,19 +17,14 @@ sa-token integrate hutool-TimedCache - cn.dev33 sa-token-core - cn.hutool hutool-cache - 5.8.27 - - diff --git a/sa-token-plugin/sa-token-hutool-timed-cache/src/main/java/cn/dev33/satoken/dao/SaTokenDaoForHutoolTimedCache.java b/sa-token-plugin/sa-token-hutool-timed-cache/src/main/java/cn/dev33/satoken/dao/SaTokenDaoForHutoolTimedCache.java index f63ba937..61ed7dfe 100644 --- a/sa-token-plugin/sa-token-hutool-timed-cache/src/main/java/cn/dev33/satoken/dao/SaTokenDaoForHutoolTimedCache.java +++ b/sa-token-plugin/sa-token-hutool-timed-cache/src/main/java/cn/dev33/satoken/dao/SaTokenDaoForHutoolTimedCache.java @@ -17,6 +17,7 @@ package cn.dev33.satoken.dao; import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.dao.auto.SaTokenDaoByStringFollowObject; import cn.dev33.satoken.util.SaFoxUtil; import cn.hutool.cache.CacheUtil; import cn.hutool.cache.impl.CacheObj; @@ -31,7 +32,7 @@ import java.util.List; * @author click33 * @since 1.38.0 */ -public class SaTokenDaoForHutoolTimedCache implements SaTokenDao { +public class SaTokenDaoForHutoolTimedCache implements SaTokenDaoByStringFollowObject { // /** @@ -41,39 +42,6 @@ public class SaTokenDaoForHutoolTimedCache implements SaTokenDao { public TimedCache timedCache = CacheUtil.newTimedCache(1000); - // ------------------------ String 读写操作 - - @Override - public String get(String key) { - return (String) getObject(key); - } - - @Override - public void set(String key, String value, long timeout) { - setObject(key, value, timeout); - } - - @Override - public void update(String key, String value) { - updateObject(key, value); - } - - @Override - public void delete(String key) { - deleteObject(key); - } - - @Override - public long getTimeout(String key) { - return getObjectTimeout(key); - } - - @Override - public void updateTimeout(String key, long timeout) { - updateObjectTimeout(key, timeout); - } - - // ------------------------ Object 读写操作 @Override diff --git a/sa-token-plugin/sa-token-hutool-timed-cache/src/main/java/cn/dev33/satoken/plugin/SaTokenPluginForHutoolCache.java b/sa-token-plugin/sa-token-hutool-timed-cache/src/main/java/cn/dev33/satoken/plugin/SaTokenPluginForHutoolCache.java new file mode 100644 index 00000000..4bbeb28f --- /dev/null +++ b/sa-token-plugin/sa-token-hutool-timed-cache/src/main/java/cn/dev33/satoken/plugin/SaTokenPluginForHutoolCache.java @@ -0,0 +1,36 @@ +/* + * Copyright 2020-2099 sa-token.cc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.dev33.satoken.plugin; + +import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.dao.SaTokenDaoForHutoolTimedCache; + +/** + * SaToken 插件安装:DAO 扩展 - Hutool-TimedCache 版 + * + * @author click33 + * @since 1.41.0 + */ +public class SaTokenPluginForHutoolCache implements SaTokenPlugin { + + @Override + public void setup() { + + SaManager.setSaTokenDao(new SaTokenDaoForHutoolTimedCache()); + + } + +} \ No newline at end of file diff --git a/sa-token-plugin/sa-token-hutool-timed-cache/src/main/resources/META-INF/services/cn.dev33.satoken.plugin.SaTokenPlugin b/sa-token-plugin/sa-token-hutool-timed-cache/src/main/resources/META-INF/services/cn.dev33.satoken.plugin.SaTokenPlugin new file mode 100644 index 00000000..c0673e0e --- /dev/null +++ b/sa-token-plugin/sa-token-hutool-timed-cache/src/main/resources/META-INF/services/cn.dev33.satoken.plugin.SaTokenPlugin @@ -0,0 +1 @@ +cn.dev33.satoken.plugin.SaTokenPluginForHutoolCache \ No newline at end of file diff --git a/sa-token-plugin/sa-token-hutool-timed-cache/src/main/resources/META-INF/spring.factories b/sa-token-plugin/sa-token-hutool-timed-cache/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 80dfde47..00000000 --- a/sa-token-plugin/sa-token-hutool-timed-cache/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1 +0,0 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.dev33.satoken.dao.SaTokenDaoForHutoolTimedCache \ No newline at end of file diff --git a/sa-token-plugin/sa-token-hutool-timed-cache/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/sa-token-plugin/sa-token-hutool-timed-cache/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index 9fa612e9..00000000 --- a/sa-token-plugin/sa-token-hutool-timed-cache/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1 +0,0 @@ -cn.dev33.satoken.dao.SaTokenDaoForHutoolTimedCache \ No newline at end of file diff --git a/sa-token-plugin/sa-token-redis-template/src/main/java/cn/dev33/satoken/dao/impl/SaTokenDaoForRedisTemplate.java b/sa-token-plugin/sa-token-redis-template/src/main/java/cn/dev33/satoken/dao/impl/SaTokenDaoForRedisTemplate.java index dfd2d01c..a0c92938 100644 --- a/sa-token-plugin/sa-token-redis-template/src/main/java/cn/dev33/satoken/dao/impl/SaTokenDaoForRedisTemplate.java +++ b/sa-token-plugin/sa-token-redis-template/src/main/java/cn/dev33/satoken/dao/impl/SaTokenDaoForRedisTemplate.java @@ -16,6 +16,7 @@ package cn.dev33.satoken.dao.impl; import cn.dev33.satoken.dao.SaTokenDao; +import cn.dev33.satoken.dao.auto.SaTokenDaoByObjectFollowStringUseJsonSerializer; import cn.dev33.satoken.util.SaFoxUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.connection.RedisConnectionFactory; @@ -34,7 +35,7 @@ import java.util.concurrent.TimeUnit; * @since 1.34.0 */ @Component -public class SaTokenDaoForRedisTemplate implements SaTokenDao { +public class SaTokenDaoForRedisTemplate implements SaTokenDaoByObjectFollowStringUseJsonSerializer { public StringRedisTemplate stringRedisTemplate; diff --git a/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/core/json/SaJsonTemplateDefaultImplTest.java b/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/core/json/SaJsonTemplateDefaultImplTest.java index f3cff0ce..fcbb45f3 100644 --- a/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/core/json/SaJsonTemplateDefaultImplTest.java +++ b/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/core/json/SaJsonTemplateDefaultImplTest.java @@ -15,12 +15,11 @@ */ package cn.dev33.satoken.core.json; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - import cn.dev33.satoken.exception.NotImplException; import cn.dev33.satoken.json.SaJsonTemplateDefaultImpl; import cn.dev33.satoken.util.SoMap; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; /** * json默认实现类测试 @@ -35,11 +34,11 @@ public class SaJsonTemplateDefaultImplTest { SaJsonTemplateDefaultImpl saJsonTemplate = new SaJsonTemplateDefaultImpl(); // 组件未实现 Assertions.assertThrows(NotImplException.class, () -> { - saJsonTemplate.parseJsonToMap("{}"); + saJsonTemplate.jsonToMap("{}"); }); // 组件未实现 Assertions.assertThrows(NotImplException.class, () -> { - saJsonTemplate.toJsonString(SoMap.getSoMap("name", "zhangsan")); + saJsonTemplate.objectToJson(SoMap.getSoMap("name", "zhangsan")); }); } diff --git a/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/integrate/annotation/SaAnnotationControllerTest.java b/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/integrate/annotation/SaAnnotationControllerTest.java index 53a1fbed..05660f1c 100644 --- a/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/integrate/annotation/SaAnnotationControllerTest.java +++ b/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/integrate/annotation/SaAnnotationControllerTest.java @@ -163,7 +163,7 @@ public class SaAnnotationControllerTest { // 转 Map String content = mvcResult.getResponse().getContentAsString(); - Map map = SaManager.getSaJsonTemplate().parseJsonToMap(content); + Map map = SaManager.getSaJsonTemplate().jsonToMap(content); // 转 SaResult 对象 return new SaResult().setMap(map); diff --git a/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/integrate/more/MoreControllerTest.java b/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/integrate/more/MoreControllerTest.java index 309f65ea..008a9997 100644 --- a/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/integrate/more/MoreControllerTest.java +++ b/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/integrate/more/MoreControllerTest.java @@ -96,7 +96,7 @@ public class MoreControllerTest { // 转 Map String content = mvcResult.getResponse().getContentAsString(); - Map map = SaManager.getSaJsonTemplate().parseJsonToMap(content); + Map map = SaManager.getSaJsonTemplate().jsonToMap(content); // 转 SaResult 对象 SaResult res = new SaResult().setMap(map); Assertions.assertEquals(res.getCode(), 903); @@ -117,7 +117,7 @@ public class MoreControllerTest { // 转 Map String content2 = mvcResult2.getResponse().getContentAsString(); - Map map2 = SaManager.getSaJsonTemplate().parseJsonToMap(content2); + Map map2 = SaManager.getSaJsonTemplate().jsonToMap(content2); // 转 SaResult 对象 SaResult res2 = new SaResult().setMap(map2); Assertions.assertEquals(res2.getCode(), 200); @@ -139,7 +139,7 @@ public class MoreControllerTest { // 转 Map String content = mvcResult.getResponse().getContentAsString(); - Map map = SaManager.getSaJsonTemplate().parseJsonToMap(content); + Map map = SaManager.getSaJsonTemplate().jsonToMap(content); // 转 SaResult 对象 return new SaResult().setMap(map); diff --git a/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/integrate/router/RouterControllerTest.java b/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/integrate/router/RouterControllerTest.java index 9e67759a..0fece559 100644 --- a/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/integrate/router/RouterControllerTest.java +++ b/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/integrate/router/RouterControllerTest.java @@ -202,7 +202,7 @@ public class RouterControllerTest { // 转 Map String content = mvcResult.getResponse().getContentAsString(); - Map map = SaManager.getSaJsonTemplate().parseJsonToMap(content); + Map map = SaManager.getSaJsonTemplate().jsonToMap(content); // 转 SaResult 对象 SaResult res = new SaResult().setMap(map); @@ -261,7 +261,7 @@ public class RouterControllerTest { // 转 Map String content = mvcResult.getResponse().getContentAsString(); - Map map = SaManager.getSaJsonTemplate().parseJsonToMap(content); + Map map = SaManager.getSaJsonTemplate().jsonToMap(content); // 转 SaResult 对象 return new SaResult().setMap(map); diff --git a/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/integrate/same/SaSameTokenControllerTest.java b/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/integrate/same/SaSameTokenControllerTest.java index 280ee74a..2ca6f0c7 100644 --- a/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/integrate/same/SaSameTokenControllerTest.java +++ b/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/integrate/same/SaSameTokenControllerTest.java @@ -132,7 +132,7 @@ public class SaSameTokenControllerTest { // 转 Map String content = mvcResult.getResponse().getContentAsString(); - Map map = SaManager.getSaJsonTemplate().parseJsonToMap(content); + Map map = SaManager.getSaJsonTemplate().jsonToMap(content); // 转 SaResult 对象 return new SaResult().setMap(map); diff --git a/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/springboot/BasicsTest.java b/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/springboot/BasicsTest.java index 52df6f49..e096b3c2 100644 --- a/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/springboot/BasicsTest.java +++ b/sa-token-test/sa-token-springboot-test/src/test/java/cn/dev33/satoken/springboot/BasicsTest.java @@ -743,18 +743,18 @@ public class BasicsTest { // map 转 json SoMap map = SoMap.getSoMap("name", "zhangsan"); - String jsonString = saJsonTemplate.toJsonString(map); + String jsonString = saJsonTemplate.objectToJson(map); Assertions.assertEquals(jsonString, "{\"name\":\"zhangsan\"}"); // 抛异常 - Assertions.assertThrows(SaJsonConvertException.class, () -> saJsonTemplate.toJsonString(new Object())); + Assertions.assertThrows(SaJsonConvertException.class, () -> saJsonTemplate.objectToJson(new Object())); // json 转 map - Map map2 = saJsonTemplate.parseJsonToMap("{\"name\":\"zhangsan\"}"); + Map map2 = saJsonTemplate.jsonToMap("{\"name\":\"zhangsan\"}"); Assertions.assertEquals(map2.get("name"), "zhangsan"); // 抛异常 - Assertions.assertThrows(SaJsonConvertException.class, () -> saJsonTemplate.parseJsonToMap("")); + Assertions.assertThrows(SaJsonConvertException.class, () -> saJsonTemplate.jsonToMap("")); } // 测试过滤器、拦截器 基础API