diff --git a/sa-token-plugin/sa-token-dao-redis-fastjson2/.gitignore b/sa-token-plugin/sa-token-dao-redis-fastjson2/.gitignore new file mode 100644 index 00000000..8122f47c --- /dev/null +++ b/sa-token-plugin/sa-token-dao-redis-fastjson2/.gitignore @@ -0,0 +1,13 @@ +target/ + +node_modules/ +bin/ +.settings/ +unpackage/ +.classpath +.project + +.factorypath + +.idea/ +.iml \ No newline at end of file diff --git a/sa-token-plugin/sa-token-dao-redis-fastjson2/pom.xml b/sa-token-plugin/sa-token-dao-redis-fastjson2/pom.xml new file mode 100644 index 00000000..7dd9f34d --- /dev/null +++ b/sa-token-plugin/sa-token-dao-redis-fastjson2/pom.xml @@ -0,0 +1,35 @@ + + + + sa-token-plugin + cn.dev33 + ${revision} + ../pom.xml + + 4.0.0 + + sa-token-dao-redis-fastjson2 + + + + + cn.dev33 + sa-token-core + ${revision} + + + + org.springframework.boot + spring-boot-starter-data-redis + 2.3.3.RELEASE + + + + com.alibaba.fastjson2 + fastjson2 + 2.0.15 + + + \ No newline at end of file diff --git a/sa-token-plugin/sa-token-dao-redis-fastjson2/src/main/java/cn/dev33/satoken/dao/SaSessionForFastjson2Customized.java b/sa-token-plugin/sa-token-dao-redis-fastjson2/src/main/java/cn/dev33/satoken/dao/SaSessionForFastjson2Customized.java new file mode 100644 index 00000000..8ea39cf2 --- /dev/null +++ b/sa-token-plugin/sa-token-dao-redis-fastjson2/src/main/java/cn/dev33/satoken/dao/SaSessionForFastjson2Customized.java @@ -0,0 +1,76 @@ +package cn.dev33.satoken.dao; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.annotation.JSONField; + +import cn.dev33.satoken.session.SaSession; +import cn.dev33.satoken.util.SaFoxUtil; + +/** + * Fastjson 定制版 SaSession,重写类型转换API + * + * @author kong + * @since 2022-10-19 + */ +public class SaSessionForFastjson2Customized extends SaSession { + + private static final long serialVersionUID = -7600983549653130681L; + + public SaSessionForFastjson2Customized() { + super(); + } + + /** + * 构建一个 SaSession 对象 + * @param id Session 的 id + */ + public SaSessionForFastjson2Customized(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 JSON.parseObject(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 JSON.parseObject(getString(key), cs); + } + + /** + * 忽略 timeout 字段的序列化 + */ + @Override + @JSONField(serialize = false) + public long getTimeout() { + return super.getTimeout(); + } + +} diff --git a/sa-token-plugin/sa-token-dao-redis-fastjson2/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisFastjson2.java b/sa-token-plugin/sa-token-dao-redis-fastjson2/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisFastjson2.java new file mode 100644 index 00000000..0ae0a8b1 --- /dev/null +++ b/sa-token-plugin/sa-token-dao-redis-fastjson2/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisFastjson2.java @@ -0,0 +1,246 @@ +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; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.stereotype.Component; + +import com.alibaba.fastjson2.JSON; + +import cn.dev33.satoken.session.SaSession; +import cn.dev33.satoken.strategy.SaStrategy; +import cn.dev33.satoken.util.SaFoxUtil; + +/** + * Sa-Token持久层接口 [Redis版 (使用JSON字符串进行序列化)] + * + * @author sikadai + * + */ +@Component +public class SaTokenDaoRedisFastjson2 implements SaTokenDao { + + /** + * String专用 + */ + public StringRedisTemplate stringRedisTemplate; + + /** + * Object专用 + */ + public StringRedisTemplate objectRedisTemplate; + + /** + * 标记:是否已初始化成功 + */ + public boolean isInit; + + @Autowired + public void init(RedisConnectionFactory connectionFactory) { + // 不重复初始化 + if(this.isInit) { + return; + } + + // 重写 SaSession 生成策略 + SaStrategy.me.createSession = (sessionId) -> new SaSessionForFastjson2Customized(sessionId); + System.out.println("------------------ 执行了"); + + // 指定相应的序列化方案 + StringRedisSerializer keySerializer = new StringRedisSerializer(); + StringRedisSerializer valueSerializer = new StringRedisSerializer(); + // 构建StringRedisTemplate + StringRedisTemplate stringTemplate = new StringRedisTemplate(); + stringTemplate.setConnectionFactory(connectionFactory); + stringTemplate.afterPropertiesSet(); + // 构建RedisTemplate + StringRedisTemplate template = new StringRedisTemplate(); + template.setConnectionFactory(connectionFactory); + template.setKeySerializer(keySerializer); + template.setHashKeySerializer(keySerializer); + template.setValueSerializer(valueSerializer); + template.setHashValueSerializer(valueSerializer); + template.afterPropertiesSet(); + + // 开始初始化相关组件 + this.stringRedisTemplate = stringTemplate; + this.objectRedisTemplate = template; + this.isInit = true; + } + + + /** + * 获取Value,如无返空 + */ + @Override + public String get(String key) { + return stringRedisTemplate.opsForValue().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) { + stringRedisTemplate.opsForValue().set(key, value); + } else { + stringRedisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS); + } + } + + /** + * 修改指定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) { + stringRedisTemplate.delete(key); + } + + /** + * 获取Value的剩余存活时间 (单位: 秒) + */ + @Override + public long getTimeout(String key) { + return stringRedisTemplate.getExpire(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; + } + stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS); + } + + + /** + * 获取Object,如无返空 + */ + @Override + public Object getObject(String key) { + return objectRedisTemplate.opsForValue().get(key); + } + + @Override + public SaSession getSession(String sessionId) { + Object obj = getObject(sessionId); + if (obj == null) { + return null; + } + return JSON.parseObject(obj.toString(), SaSessionForFastjson2Customized.class); + } + + /** + * 写入Object,并设定存活时间 (单位: 秒) + */ + @Override + public void setObject(String key, Object object, long timeout) { + if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } + String toValue = JSON.toJSONString(object); + // 判断是否为永不过期 + if(timeout == SaTokenDao.NEVER_EXPIRE) { + objectRedisTemplate.opsForValue().set(key, toValue); + } else { + objectRedisTemplate.opsForValue().set(key, toValue, timeout, TimeUnit.SECONDS); + } + } + + /** + * 更新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) { + objectRedisTemplate.delete(key); + } + + /** + * 获取Object的剩余存活时间 (单位: 秒) + */ + @Override + public long getObjectTimeout(String key) { + return objectRedisTemplate.getExpire(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; + } + objectRedisTemplate.expire(key, timeout, TimeUnit.SECONDS); + } + + + + /** + * 搜索数据 + */ + @Override + public List searchData(String prefix, String keyword, int start, int size, boolean sortType) { + Set keys = stringRedisTemplate.keys(prefix + "*" + keyword + "*"); + List list = new ArrayList(keys); + return SaFoxUtil.searchList(list, start, size, sortType); + } + + +} diff --git a/sa-token-plugin/sa-token-dao-redis-fastjson2/src/main/resources/META-INF/spring.factories b/sa-token-plugin/sa-token-dao-redis-fastjson2/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..8774edc6 --- /dev/null +++ b/sa-token-plugin/sa-token-dao-redis-fastjson2/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.dev33.satoken.dao.SaTokenDaoRedisFastjson2 \ No newline at end of file