From 9d251f4d58b34d62be187d90dac2a27397facb0f Mon Sep 17 00:00:00 2001 From: noear Date: Sun, 5 Mar 2023 10:22:05 +0800 Subject: [PATCH] =?UTF-8?q?sa-token-solon-plugin:=20=E6=B7=BB=E5=8A=A0=20d?= =?UTF-8?q?ao=20=E5=92=8C=20json=20=E7=9A=84=E5=AE=9E=E7=8E=B0=E7=B1=BB?= =?UTF-8?q?=EF=BC=88=E5=8F=AF=E9=80=89=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sa-token-solon-plugin/pom.xml | 12 ++ .../satoken/solon/dao/SaSessionForJson.java | 73 +++++++ .../satoken/solon/dao/SaTokenDaoOfRedis.java | 23 ++ .../solon/dao/SaTokenDaoOfRedisBase64.java | 186 ++++++++++++++++ .../solon/dao/SaTokenDaoOfRedisJson.java | 199 ++++++++++++++++++ .../solon/json/SaJsonTemplateForSnack3.java | 22 ++ 6 files changed, 515 insertions(+) create mode 100644 sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaSessionForJson.java create mode 100644 sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaTokenDaoOfRedis.java create mode 100644 sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaTokenDaoOfRedisBase64.java create mode 100644 sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaTokenDaoOfRedisJson.java create mode 100644 sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/json/SaJsonTemplateForSnack3.java diff --git a/sa-token-starter/sa-token-solon-plugin/pom.xml b/sa-token-starter/sa-token-solon-plugin/pom.xml index 1827ce72..01471578 100644 --- a/sa-token-starter/sa-token-solon-plugin/pom.xml +++ b/sa-token-starter/sa-token-solon-plugin/pom.xml @@ -41,5 +41,17 @@ true + + org.noear + snack3 + provided + + + + org.noear + redisx + provided + + \ No newline at end of file diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaSessionForJson.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaSessionForJson.java new file mode 100644 index 00000000..9e7bc042 --- /dev/null +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaSessionForJson.java @@ -0,0 +1,73 @@ +package cn.dev33.satoken.solon.dao; + +import cn.dev33.satoken.session.SaSession; +import cn.dev33.satoken.util.SaFoxUtil; +import org.noear.snack.ONode; + +/** + * Snack3 定制版 SaSession,重写类型转换API + * + * @author noear + * @since 1.12 + */ +public class SaSessionForJson extends SaSession { + + private static final long serialVersionUID = -7600983549653130681L; + + public SaSessionForJson() { + super(); + } + + /** + * 构建一个 SaSession 对象 + * @param id Session 的 id + */ + public SaSessionForJson(String id) { + super(id); + } + + /** + * 取值 (指定转换类型) + * @param 泛型 + * @param key key + * @param cs 指定转换类型 + * @return 值 + */ + @Override + public T getModel(String key, Class cs) { + if(SaFoxUtil.isBasicType(cs)) { + return SaFoxUtil.getValueByType(get(key), cs); + } + return ONode.deserialize(getString(key), cs); + } + + /** + * 取值 (指定转换类型, 并指定值为Null时返回的默认值) + * @param 泛型 + * @param key key + * @param cs 指定转换类型 + * @param defaultValue 值为Null时返回的默认值 + * @return 值 + */ + @Override + @SuppressWarnings("unchecked") + public T getModel(String key, Class cs, Object defaultValue) { + Object value = get(key); + if(valueIsNull(value)) { + return (T)defaultValue; + } + if(SaFoxUtil.isBasicType(cs)) { + return SaFoxUtil.getValueByType(get(key), cs); + } + return ONode.deserialize(getString(key), cs); + } + + /** + * 忽略 timeout 字段的序列化 + */ + @Override + public long getTimeout() { + return super.getTimeout(); + } + +} diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaTokenDaoOfRedis.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaTokenDaoOfRedis.java new file mode 100644 index 00000000..805b5f4b --- /dev/null +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaTokenDaoOfRedis.java @@ -0,0 +1,23 @@ +package cn.dev33.satoken.solon.dao; + +import org.noear.redisx.RedisClient; +import org.noear.solon.annotation.Note; + +import java.util.Properties; + +/** + * SaTokenDao 的 redis 适配 + * + * @author noear + * @since 1.6 + */ +public class SaTokenDaoOfRedis extends SaTokenDaoOfRedisBase64 { + + public SaTokenDaoOfRedis(Properties props) { + super(props); + } + + public SaTokenDaoOfRedis(RedisClient redisClient) { + super(redisClient); + } +} \ No newline at end of file diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaTokenDaoOfRedisBase64.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaTokenDaoOfRedisBase64.java new file mode 100644 index 00000000..bca0e62f --- /dev/null +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaTokenDaoOfRedisBase64.java @@ -0,0 +1,186 @@ +package cn.dev33.satoken.solon.dao; + +import cn.dev33.satoken.dao.SaTokenDao; +import cn.dev33.satoken.util.SaFoxUtil; +import org.noear.redisx.RedisClient; +import org.noear.redisx.plus.RedisBucket; + +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.Set; + +/** + * SaTokenDao 的 redis 适配(可以完全精准还原所有序列化类型) + * + * @author noear + * @since 1.6 + */ +public class SaTokenDaoOfRedisBase64 implements SaTokenDao { + private final RedisBucket redisBucket; + + public SaTokenDaoOfRedisBase64(Properties props) { + this(new RedisClient(props)); + } + + public SaTokenDaoOfRedisBase64(RedisClient redisClient) { + redisBucket = redisClient.getBucket(); + } + + + /** + * 获取Value,如无返空 + */ + @Override + public String get(String key) { + return redisBucket.get(key); + } + + /** + * 写入Value,并设定存活时间 (单位: 秒) + */ + @Override + public void set(String key, String value, long timeout) { + if (timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } + // 判断是否为永不过期 + if (timeout == SaTokenDao.NEVER_EXPIRE) { + redisBucket.store(key, value, (int) SaTokenDao.NEVER_EXPIRE); + } else { + redisBucket.store(key, value, (int) timeout); + } + } + + /** + * 修改指定key-value键值对 (过期时间不变) + */ + @Override + public void update(String key, String value) { + long expire = getTimeout(key); + // -2 = 无此键 + if (expire == SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } + this.set(key, value, expire); + } + + /** + * 删除Value + */ + @Override + public void delete(String key) { + redisBucket.remove(key); + } + + /** + * 获取Value的剩余存活时间 (单位: 秒) + */ + @Override + public long getTimeout(String key) { + return redisBucket.ttl(key); + } + + /** + * 修改Value的剩余存活时间 (单位: 秒) + */ + @Override + 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; + } + redisBucket.delay(key, (int) timeout); + } + + + /** + * 获取Object,如无返空 + */ + @Override + public Object getObject(String key) { + return redisBucket.getAndDeserialize(key); + } + + /** + * 写入Object,并设定存活时间 (单位: 秒) + */ + @Override + public void setObject(String key, Object object, long timeout) { + if (timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } + // 判断是否为永不过期 + if (timeout == SaTokenDao.NEVER_EXPIRE) { + redisBucket.storeAndSerialize(key, object); + } else { + redisBucket.storeAndSerialize(key, object, (int) timeout); + } + } + + /** + * 更新Object (过期时间不变) + */ + @Override + public void updateObject(String key, Object object) { + long expire = getObjectTimeout(key); + // -2 = 无此键 + if (expire == SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } + this.setObject(key, object, expire); + } + + /** + * 删除Object + */ + @Override + public void deleteObject(String key) { + redisBucket.remove(key); + } + + /** + * 获取Object的剩余存活时间 (单位: 秒) + */ + @Override + public long getObjectTimeout(String key) { + return redisBucket.ttl(key); + } + + /** + * 修改Object的剩余存活时间 (单位: 秒) + */ + @Override + 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; + } + redisBucket.delay(key, (int) timeout); + } + + + /** + * 搜索数据 + */ + @Override + public List searchData(String prefix, String keyword, int start, int size, boolean sortType) { + Set keys = redisBucket.keys(prefix + "*" + keyword + "*"); + List list = new ArrayList(keys); + return SaFoxUtil.searchList(list, start, size, sortType); + } +} \ No newline at end of file diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaTokenDaoOfRedisJson.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaTokenDaoOfRedisJson.java new file mode 100644 index 00000000..fdddbb03 --- /dev/null +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/dao/SaTokenDaoOfRedisJson.java @@ -0,0 +1,199 @@ +package cn.dev33.satoken.solon.dao; + +import cn.dev33.satoken.dao.SaTokenDao; +import cn.dev33.satoken.session.SaSession; +import cn.dev33.satoken.strategy.SaStrategy; +import cn.dev33.satoken.util.SaFoxUtil; +import org.noear.redisx.RedisClient; +import org.noear.redisx.plus.RedisBucket; +import org.noear.snack.ONode; + +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.Set; + +/** + * SaTokenDao 的 redis 适配(基于json序列化,不能完全精准还原所有类型) + * + * @author noear + * @since 1.6 + */ +public class SaTokenDaoOfRedisJson implements SaTokenDao { + private final RedisBucket redisBucket; + + public SaTokenDaoOfRedisJson(Properties props) { + this(new RedisClient(props)); + } + + public SaTokenDaoOfRedisJson(RedisClient redisClient) { + redisBucket = redisClient.getBucket(); + + // 重写 SaSession 生成策略 + SaStrategy.me.createSession = (sessionId) -> new SaSessionForJson(sessionId); + + } + + @Override + public SaSession getSession(String sessionId) { + Object obj = getObject(sessionId); + if (obj == null) { + return null; + } + return ONode.deserialize(obj.toString(), SaSessionForJson.class); + } + + + /** + * 获取Value,如无返空 + */ + @Override + public String get(String key) { + return redisBucket.get(key); + } + + /** + * 写入Value,并设定存活时间 (单位: 秒) + */ + @Override + public void set(String key, String value, long timeout) { + if (timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } + // 判断是否为永不过期 + if (timeout == SaTokenDao.NEVER_EXPIRE) { + redisBucket.store(key, value, (int) SaTokenDao.NEVER_EXPIRE); + } else { + redisBucket.store(key, value, (int) timeout); + } + } + + /** + * 修改指定key-value键值对 (过期时间不变) + */ + @Override + public void update(String key, String value) { + long expire = getTimeout(key); + // -2 = 无此键 + if (expire == SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } + this.set(key, value, expire); + } + + /** + * 删除Value + */ + @Override + public void delete(String key) { + redisBucket.remove(key); + } + + /** + * 获取Value的剩余存活时间 (单位: 秒) + */ + @Override + public long getTimeout(String key) { + return redisBucket.ttl(key); + } + + /** + * 修改Value的剩余存活时间 (单位: 秒) + */ + @Override + 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; + } + redisBucket.delay(key, (int) timeout); + } + + + /** + * 获取Object,如无返空 + */ + @Override + public Object getObject(String key) { + return get(key); + } + + /** + * 写入Object,并设定存活时间 (单位: 秒) + */ + @Override + public void setObject(String key, Object object, long timeout) { + if (timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } + + String value = ONode.serialize(object); + set(key, value, timeout); + } + + /** + * 更新Object (过期时间不变) + */ + @Override + public void updateObject(String key, Object object) { + long expire = getObjectTimeout(key); + // -2 = 无此键 + if (expire == SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } + this.setObject(key, object, expire); + } + + /** + * 删除Object + */ + @Override + public void deleteObject(String key) { + redisBucket.remove(key); + } + + /** + * 获取Object的剩余存活时间 (单位: 秒) + */ + @Override + public long getObjectTimeout(String key) { + return redisBucket.ttl(key); + } + + /** + * 修改Object的剩余存活时间 (单位: 秒) + */ + @Override + 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; + } + redisBucket.delay(key, (int) timeout); + } + + + /** + * 搜索数据 + */ + @Override + public List searchData(String prefix, String keyword, int start, int size, boolean sortType) { + Set keys = redisBucket.keys(prefix + "*" + keyword + "*"); + List list = new ArrayList(keys); + return SaFoxUtil.searchList(list, start, size, sortType); + } +} \ No newline at end of file diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/json/SaJsonTemplateForSnack3.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/json/SaJsonTemplateForSnack3.java new file mode 100644 index 00000000..122c055f --- /dev/null +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/json/SaJsonTemplateForSnack3.java @@ -0,0 +1,22 @@ +package cn.dev33.satoken.solon.json; + +import cn.dev33.satoken.json.SaJsonTemplate; +import org.noear.snack.ONode; + +import java.util.Map; + +/** + * @author noear + * @since 2.0 + */ +public class SaJsonTemplateForSnack3 implements SaJsonTemplate { + @Override + public String toJsonString(Object o) { + return ONode.stringify(o); + } + + @Override + public Map parseJsonToMap(String s) { + return ONode.deserialize(s, Map.class); + } +}