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