diff --git a/sa-token-starter/sa-token-jboot-plugin/pom.xml b/sa-token-starter/sa-token-jboot-plugin/pom.xml
index 4e6fdc6f..576476b3 100644
--- a/sa-token-starter/sa-token-jboot-plugin/pom.xml
+++ b/sa-token-starter/sa-token-jboot-plugin/pom.xml
@@ -16,13 +16,14 @@
8
8
+ 3.8.0
io.jboot
jboot
- 3.14.2
+ 3.14.4
provided
@@ -35,6 +36,12 @@
sa-token-servlet
${sa-token-version}
+
+ redis.clients
+ jedis
+ ${jedis.version}
+ provided
+
diff --git a/sa-token-starter/sa-token-jboot-plugin/src/main/java/cn/dev33/satoken/jboot/SaRedisCache.java b/sa-token-starter/sa-token-jboot-plugin/src/main/java/cn/dev33/satoken/jboot/SaRedisCache.java
new file mode 100644
index 00000000..982e6158
--- /dev/null
+++ b/sa-token-starter/sa-token-jboot-plugin/src/main/java/cn/dev33/satoken/jboot/SaRedisCache.java
@@ -0,0 +1,257 @@
+package cn.dev33.satoken.jboot;
+
+import com.jfinal.plugin.ehcache.IDataLoader;
+import io.jboot.Jboot;
+import io.jboot.components.cache.JbootCache;
+import io.jboot.components.cache.JbootCacheConfig;
+import io.jboot.core.spi.JbootSpi;
+import io.jboot.exception.JbootIllegalConfigException;
+import io.jboot.support.redis.JbootRedisConfig;
+import io.jboot.support.redis.RedisScanResult;
+import io.jboot.utils.StrUtil;
+import redis.clients.jedis.*;
+import redis.clients.jedis.exceptions.JedisConnectionException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * sa 缓存处理
+ */
+@JbootSpi("sacache")
+public class SaRedisCache implements JbootCache {
+ protected JbootRedisConfig config;
+ protected JedisPool jedisPool;
+ protected JbootCacheConfig cacheConfig;
+ private ThreadLocal CACHE_NAME_PREFIX_TL = new ThreadLocal<>();
+
+ public SaRedisCache(JbootCacheConfig cacheConfig) {
+ this.cacheConfig = cacheConfig;
+
+ config = Jboot.config(JbootRedisConfig.class);
+ String host = config.getHost();
+ Integer port = config.getPort();
+ Integer timeout = config.getTimeout();
+ String password = config.getPassword();
+ Integer database = config.getDatabase();
+ String clientName = config.getClientName();
+
+ if (host.contains(":")) {
+ port = Integer.valueOf(host.split(":")[1]);
+ }
+
+
+ JedisPoolConfig poolConfig = new JedisPoolConfig();
+
+ if (StrUtil.isNotBlank(config.getTestWhileIdle())) {
+ poolConfig.setTestWhileIdle(config.getTestWhileIdle());
+ }
+
+ if (StrUtil.isNotBlank(config.getTestOnBorrow())) {
+ poolConfig.setTestOnBorrow(config.getTestOnBorrow());
+ }
+
+ if (StrUtil.isNotBlank(config.getTestOnCreate())) {
+ poolConfig.setTestOnCreate(config.getTestOnCreate());
+ }
+
+ if (StrUtil.isNotBlank(config.getTestOnReturn())) {
+ poolConfig.setTestOnReturn(config.getTestOnReturn());
+ }
+
+ if (StrUtil.isNotBlank(config.getMinEvictableIdleTimeMillis())) {
+ poolConfig.setMinEvictableIdleTimeMillis(config.getMinEvictableIdleTimeMillis());
+ }
+
+ if (StrUtil.isNotBlank(config.getTimeBetweenEvictionRunsMillis())) {
+ poolConfig.setTimeBetweenEvictionRunsMillis(config.getTimeBetweenEvictionRunsMillis());
+ }
+
+ if (StrUtil.isNotBlank(config.getNumTestsPerEvictionRun())) {
+ poolConfig.setNumTestsPerEvictionRun(config.getNumTestsPerEvictionRun());
+ }
+
+ if (StrUtil.isNotBlank(config.getMaxTotal())) {
+ poolConfig.setMaxTotal(config.getMaxTotal());
+ }
+
+ if (StrUtil.isNotBlank(config.getMaxIdle())) {
+ poolConfig.setMaxIdle(config.getMaxIdle());
+ }
+
+ if (StrUtil.isNotBlank(config.getMinIdle())) {
+ poolConfig.setMinIdle(config.getMinIdle());
+ }
+
+ if (StrUtil.isNotBlank(config.getMaxWaitMillis())) {
+ poolConfig.setMaxWaitMillis(config.getMaxWaitMillis());
+ }
+
+ this.jedisPool = new JedisPool(poolConfig, host, port, timeout, timeout, password, database, clientName);
+ }
+
+ public SaRedisCache(JedisPool jedisPool) {
+ this.jedisPool = jedisPool;
+ }
+
+ @Override
+ public JbootCache setCurrentCacheNamePrefix(String cacheNamePrefix) {
+ if (StrUtil.isNotBlank(cacheNamePrefix)) {
+ CACHE_NAME_PREFIX_TL.set(cacheNamePrefix);
+ } else {
+ CACHE_NAME_PREFIX_TL.remove();
+ }
+ return this;
+ }
+
+ @Override
+ public void removeCurrentCacheNamePrefix() {
+ CACHE_NAME_PREFIX_TL.remove();
+ }
+
+ @Override
+ public JbootCacheConfig getConfig() {
+ return cacheConfig;
+ }
+
+ @Override
+ public T get(String cacheName, Object key) {
+ Jedis jedis = getJedis();
+ try {
+ return (T) (jedis.get(key.toString()));
+ } finally {
+ returnResource(jedis);
+ }
+ }
+
+ @Override
+ public void put(String cacheName, Object key, Object value) {
+ Jedis jedis = getJedis();
+ try {
+ jedis.set(key.toString(), value.toString());
+ } finally {
+ returnResource(jedis);
+ }
+ }
+
+ @Override
+ public void put(String cacheName, Object key, Object value, int liveSeconds) {
+ Jedis jedis = getJedis();
+ try {
+ jedis.setex(key.toString(), Long.parseLong(liveSeconds + ""), value.toString());
+ } finally {
+ returnResource(jedis);
+ }
+ }
+
+ @Override
+ public void remove(String cacheName, Object key) {
+ Jedis jedis = getJedis();
+ try {
+ jedis.del(key.toString());
+ } finally {
+ returnResource(jedis);
+ }
+ }
+
+ @Override
+ public void removeAll(String cacheName) {
+
+ }
+
+ @Override
+ public T get(String cacheName, Object key, IDataLoader dataLoader) {
+ return null;
+ }
+
+ @Override
+ public T get(String cacheName, Object key, IDataLoader dataLoader, int liveSeconds) {
+ return null;
+ }
+
+ @Override
+ public Integer getTtl(String cacheName, Object key) {
+ Jedis jedis = getJedis();
+ try {
+ return jedis.ttl(key.toString()).intValue();
+ } finally {
+ returnResource(jedis);
+ }
+ }
+
+ @Override
+ public void setTtl(String cacheName, Object key, int seconds) {
+ Jedis jedis = getJedis();
+ try {
+ jedis.expire(key.toString(), Long.parseLong(seconds + ""));
+ } finally {
+ returnResource(jedis);
+ }
+ }
+
+ @Override
+ public void refresh(String cacheName, Object key) {
+
+ }
+
+ @Override
+ public void refresh(String cacheName) {
+
+ }
+
+ @Override
+ public List getNames() {
+ return null;
+ }
+
+ @Override
+ public List getKeys(String cacheName) {
+ List keys = new ArrayList<>();
+ String cursor = "0";
+ int scanCount = 1000;
+ boolean continueState = true;
+ do {
+ RedisScanResult redisScanResult = this.scan("*", cursor, scanCount);
+ List scanKeys = redisScanResult.getResults();
+ cursor = redisScanResult.getCursor();
+
+ if (scanKeys != null && scanKeys.size() > 0) {
+ for (String key : scanKeys) {
+ keys.add(key.substring(3));
+ }
+ }
+
+ if (redisScanResult.isCompleteIteration()) {
+ continueState = false;
+ }
+ } while (continueState);
+
+ return keys;
+ }
+
+ public Jedis getJedis() {
+ try {
+ return jedisPool.getResource();
+ } catch (JedisConnectionException e) {
+ throw new JbootIllegalConfigException("can not connect to redis host " + config.getHost() + ":" + config.getPort() + " ," +
+ " cause : " + e.toString(), e);
+ }
+ }
+
+ public void returnResource(Jedis jedis) {
+ if (jedis != null) {
+ jedis.close();
+ }
+ }
+
+ public RedisScanResult scan(String pattern, String cursor, int scanCount) {
+ ScanParams params = new ScanParams();
+ params.match(pattern).count(scanCount);
+ try (Jedis jedis = getJedis()) {
+ ScanResult scanResult = jedis.scan(cursor, params);
+ return new RedisScanResult<>(scanResult.getCursor(), scanResult.getResult());
+ }
+ }
+
+
+}
diff --git a/sa-token-starter/sa-token-jboot-plugin/src/main/java/cn/dev33/satoken/jboot/SaTokenCacheDao.java b/sa-token-starter/sa-token-jboot-plugin/src/main/java/cn/dev33/satoken/jboot/SaTokenCacheDao.java
index 0765119e..3baad822 100644
--- a/sa-token-starter/sa-token-jboot-plugin/src/main/java/cn/dev33/satoken/jboot/SaTokenCacheDao.java
+++ b/sa-token-starter/sa-token-jboot-plugin/src/main/java/cn/dev33/satoken/jboot/SaTokenCacheDao.java
@@ -3,88 +3,186 @@ package cn.dev33.satoken.jboot;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.util.SaFoxUtil;
+import io.jboot.components.serializer.JbootSerializer;
import io.jboot.utils.CacheUtil;
-import io.jboot.utils.StrUtil;
+import redis.clients.jedis.Jedis;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
/**
- * 使用jBoot的缓存方法存取Token数据
+ * 使用Jboot的缓存方法存取Token数据
*/
public class SaTokenCacheDao implements SaTokenDao {
- private final String cacheName;
+ protected SaRedisCache saRedisCache;
+ protected JbootSerializer serializer;
/**
* 调用的Cache名称
- *
* @param cacheName 使用的缓存配置名,默认为 default
*/
public SaTokenCacheDao(String cacheName) {
- if (StrUtil.isBlank(cacheName)) {
- cacheName = "default";
+ saRedisCache = (SaRedisCache) CacheUtil.use(cacheName);
+ serializer = new SaJdkSerializer();
+ }
+
+
+ @Override
+ public String get(String key) {
+ Jedis jedis = saRedisCache.getJedis();
+ try {
+ return jedis.get(key);
+ } finally {
+ saRedisCache.returnResource(jedis);
}
- this.cacheName = cacheName;
}
@Override
- public String get(String s) {
- return CacheUtil.use(cacheName).get("SA", s);
+ public void set(String key, String value, long timeout) {
+ if (timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) {
+ return;
+ }
+ Jedis jedis = saRedisCache.getJedis();
+ try {
+ if (timeout == SaTokenDao.NEVER_EXPIRE) {
+ jedis.set(key, value);
+ } else {
+ jedis.setex(key, timeout, value);
+ }
+ } finally {
+ saRedisCache.returnResource(jedis);
+ }
}
@Override
- public void set(String s, String s1, long l) {
- CacheUtil.use(cacheName).put("SA", s, s1, Integer.parseInt(l + ""));
+ public void update(String key, String value) {
+ long expire = getTimeout(key);
+ // -2 = 无此键
+ if (expire == SaTokenDao.NOT_VALUE_EXPIRE) {
+ return;
+ }
+ this.set(key, value, expire);
}
@Override
- public void update(String s, String s1) {
- CacheUtil.use(cacheName).put("SA", s, s1);
+ public void delete(String key) {
+ Jedis jedis = saRedisCache.getJedis();
+ try {
+ jedis.del(key);
+ } finally {
+ saRedisCache.returnResource(jedis);
+ }
}
@Override
- public void delete(String s) {
- CacheUtil.use(cacheName).remove("SA", s);
+ public long getTimeout(String key) {
+ Jedis jedis = saRedisCache.getJedis();
+ try {
+ return jedis.ttl(key);
+ } finally {
+ saRedisCache.returnResource(jedis);
+ }
}
@Override
- public long getTimeout(String s) {
- return CacheUtil.use(cacheName).getTtl("SA", s);
+ public void updateTimeout(String key, long timeout) {
+ //判断是否想要设置为永久
+ if (timeout == SaTokenDao.NEVER_EXPIRE) {
+ long expire = getTimeout(key);
+ if (expire == SaTokenDao.NEVER_EXPIRE) {
+ // 如果其已经被设置为永久,则不作任何处理
+ } else {
+ // 如果尚未被设置为永久,那么再次set一次
+ this.set(key, this.get(key), timeout);
+ }
+ return;
+ }
+ Jedis jedis = saRedisCache.getJedis();
+ try {
+ jedis.expire(key, timeout);
+ } finally {
+ saRedisCache.returnResource(jedis);
+ }
}
@Override
- public void updateTimeout(String s, long l) {
- CacheUtil.use(cacheName).setTtl("SA", s, Integer.parseInt(l + ""));
+ public Object getObject(String key) {
+ Jedis jedis = saRedisCache.getJedis();
+ try {
+ return valueFromBytes(jedis.get(keyToBytes(key)));
+ } finally {
+ saRedisCache.returnResource(jedis);
+ }
}
@Override
- public Object getObject(String s) {
- return CacheUtil.use(cacheName).get("SA", s);
+ public void setObject(String key, Object object, long timeout) {
+ if (timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) {
+ return;
+ }
+ Jedis jedis = saRedisCache.getJedis();
+ try {
+ if (timeout == SaTokenDao.NEVER_EXPIRE) {
+ jedis.set(keyToBytes(key), valueToBytes(object));
+ } else {
+ jedis.setex(keyToBytes(key), timeout, valueToBytes(object));
+ }
+ } finally {
+ saRedisCache.returnResource(jedis);
+ }
}
@Override
- public void setObject(String s, Object o, long l) {
- CacheUtil.use(cacheName).put("SA", s, o, Integer.parseInt(l + ""));
+ public void updateObject(String key, Object object) {
+ long expire = getObjectTimeout(key);
+ // -2 = 无此键
+ if (expire == SaTokenDao.NOT_VALUE_EXPIRE) {
+ return;
+ }
+ this.setObject(key, object, expire);
}
@Override
- public void updateObject(String s, Object o) {
- CacheUtil.use(cacheName).put("SA", s, o);
+ public void deleteObject(String key) {
+ Jedis jedis = saRedisCache.getJedis();
+ try {
+ jedis.del(keyToBytes(key));
+ } finally {
+ saRedisCache.returnResource(jedis);
+ }
}
@Override
- public void deleteObject(String s) {
- CacheUtil.use(cacheName).remove("SA", s);
+ public long getObjectTimeout(String key) {
+ Jedis jedis = saRedisCache.getJedis();
+ try {
+ return jedis.ttl(keyToBytes(key));
+ } finally {
+ saRedisCache.returnResource(jedis);
+ }
}
@Override
- public long getObjectTimeout(String s) {
- return CacheUtil.use(cacheName).getTtl("SA", s);
- }
-
- @Override
- public void updateObjectTimeout(String s, long l) {
- CacheUtil.use(cacheName).setTtl("SA", s, Integer.parseInt(l + ""));
+ public void updateObjectTimeout(String key, long timeout) {
+ //判断是否想要设置为永久
+ if (timeout == SaTokenDao.NEVER_EXPIRE) {
+ long expire = getObjectTimeout(key);
+ if (expire == SaTokenDao.NEVER_EXPIRE) {
+ // 如果其已经被设置为永久,则不作任何处理
+ } else {
+ // 如果尚未被设置为永久,那么再次set一次
+ this.setObject(key, this.getObject(key), timeout);
+ }
+ return;
+ }
+ Jedis jedis = saRedisCache.getJedis();
+ try {
+ jedis.expire(keyToBytes(key), timeout);
+ } finally {
+ saRedisCache.returnResource(jedis);
+ }
}
@Override
@@ -119,7 +217,29 @@ public class SaTokenCacheDao implements SaTokenDao {
@Override
public List searchData(String prefix, String keyword, int start, int size) {
- List list = CacheUtil.use(cacheName).getKeys(prefix + "*" + keyword + "*");
- return SaFoxUtil.searchList(list, start, size);
+ Jedis jedis = saRedisCache.getJedis();
+ try {
+ Set keys = jedis.keys(prefix + "*" + keyword + "*");
+ List list = new ArrayList(keys);
+ return SaFoxUtil.searchList(list, start, size);
+ } finally {
+ saRedisCache.returnResource(jedis);
+ }
+ }
+
+
+ protected byte[] keyToBytes(Object key) {
+ return key.toString().getBytes();
+ }
+
+ protected byte[] valueToBytes(Object value) {
+ return serializer.serialize(value);
+ }
+
+ protected Object valueFromBytes(byte[] bytes) {
+ if (bytes == null || bytes.length == 0) {
+ return null;
+ }
+ return serializer.deserialize(bytes);
}
}