Pre Merge pull request !326 from 西东/dev

This commit is contained in:
西东 2025-03-03 12:51:16 +00:00 committed by Gitee
commit e6da2823da
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
17 changed files with 209 additions and 1087 deletions

View File

@ -129,6 +129,11 @@
<artifactId>sa-token-fastjson2</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-snack3</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redis-jackson</artifactId>

View File

@ -25,8 +25,8 @@
<thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
<freemarker.version>2.3.34</freemarker.version>
<solon.version>3.0.1</solon.version>
<noear-redisx.version>1.6.2</noear-redisx.version>
<noear-snack3.version>3.2.88</noear-snack3.version>
<noear-redisx.version>1.6.9</noear-redisx.version>
<noear-snack3.version>3.2.127</noear-snack3.version>
<jfinal.version>4.9.17</jfinal.version>
<jboot.version>3.14.4</jboot.version>
<commons-pool2.version>2.5.0</commons-pool2.version>

View File

@ -22,6 +22,7 @@
<module>sa-token-jackson</module>
<module>sa-token-fastjson</module>
<module>sa-token-fastjson2</module>
<module>sa-token-snack3</module>
<module>sa-token-hutool-timed-cache</module>
<module>sa-token-thymeleaf</module>
<module>sa-token-freemarker</module>
@ -32,6 +33,7 @@
<module>sa-token-sso</module>
<module>sa-token-oauth2</module>
<module>sa-token-redisson</module>
<module>sa-token-redisx</module>
<module>sa-token-serializer-features</module>
<!-- SpringBoot 环境插件 -->
@ -44,10 +46,6 @@
<module>sa-token-grpc</module>
<module>sa-token-quick-login</module>
<module>sa-token-redisson-spring-boot-starter</module>
<!-- Solon 环境插件 -->
<module>sa-token-redisx</module>
</modules>
<dependencies>

View File

@ -28,12 +28,6 @@
<artifactId>redisx</artifactId>
</dependency>
<dependency>
<groupId>org.noear</groupId>
<artifactId>snack3</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-test</artifactId>

View File

@ -1,89 +0,0 @@
/*
* 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;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.util.SaFoxUtil;
import org.noear.snack.ONode;
/**
* Snack3 定制版 SaSession重写类型转换API
*
* @author noear
* @since 1.34.0
*/
@Deprecated
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 <T> 泛型
* @param key key
* @param cs 指定转换类型
* @return
*/
@Override
public <T> T getModel(String key, Class<T> cs) {
if(SaFoxUtil.isBasicType(cs)) {
return SaFoxUtil.getValueByType(get(key), cs);
}
return ONode.deserialize(getString(key), cs);
}
/**
* 取值 (指定转换类型, 并指定值为Null时返回的默认值)
* @param <T> 泛型
* @param key key
* @param cs 指定转换类型
* @param defaultValue 值为Null时返回的默认值
* @return
*/
@Override
@SuppressWarnings("unchecked")
public <T> T getModel(String key, Class<T> 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 timeout() {
return super.timeout();
}
}

View File

@ -15,11 +15,10 @@
*/
package cn.dev33.satoken.dao;
import cn.dev33.satoken.dao.auto.SaTokenDaoBySessionFollowObject;
import cn.dev33.satoken.dao.auto.SaTokenDaoByObjectFollowString;
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;
@ -31,20 +30,17 @@ import java.util.Set;
*
* @author noear
* @since 1.34.0
* @since 1.41.0
*/
public class SaTokenDaoOfRedisJson implements SaTokenDaoBySessionFollowObject {
public class SaTokenDaoForRedisx implements SaTokenDaoByObjectFollowString {
private final RedisBucket redisBucket;
public SaTokenDaoOfRedisJson(Properties props) {
public SaTokenDaoForRedisx(Properties props) {
this(new RedisClient(props));
}
public SaTokenDaoOfRedisJson(RedisClient redisClient) {
public SaTokenDaoForRedisx(RedisClient redisClient) {
redisBucket = redisClient.getBucket();
// 重写 SaSession 生成策略
//SaStrategy.instance.createSession = (sessionId) -> new SaSessionForJson(sessionId);
}
/**
@ -60,7 +56,14 @@ public class SaTokenDaoOfRedisJson implements SaTokenDaoBySessionFollowObject {
*/
@Override
public void set(String key, String value, long timeout) {
if (timeout > 0 || timeout == SaTokenDao.NEVER_EXPIRE) {
if (timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) {
return;
}
// 判断是否为永不过期
if (timeout == SaTokenDao.NEVER_EXPIRE) {
redisBucket.store(key, value);
} else {
redisBucket.store(key, value, (int) timeout);
}
}
@ -71,6 +74,11 @@ public class SaTokenDaoOfRedisJson implements SaTokenDaoBySessionFollowObject {
@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);
}
@ -95,74 +103,22 @@ public class SaTokenDaoOfRedisJson implements SaTokenDaoBySessionFollowObject {
*/
@Override
public void updateTimeout(String key, long timeout) {
if (redisBucket.exists(key)) {
redisBucket.delay(key, (int) 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) {
String value = get(key);
return ONode.deserialize(value);
}
@Override
public <T> T getObject(String key, Class<T> classType) {
String value = get(key);
return ONode.deserialize(value, classType);
}
/**
* 写入Object并设定存活时间 (单位: )
*/
@Override
public void setObject(String key, Object object, long timeout) {
if (timeout > 0 || timeout == SaTokenDao.NEVER_EXPIRE) {
String value = ONode.serialize(object);
set(key, value, timeout);
}
}
/**
* 更新Object (过期时间不变)
*/
@Override
public void updateObject(String key, Object object) {
long expire = getObjectTimeout(key);
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 (redisBucket.exists(key)) {
redisBucket.delay(key, (int) timeout);
}
}
/**
* 搜索数据
*/

View File

@ -1,168 +0,0 @@
/*
* 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;
import cn.dev33.satoken.dao.auto.SaTokenDaoBySessionFollowObject;
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.34.0
*/
public class SaTokenDaoOfRedisBase64 implements SaTokenDaoBySessionFollowObject {
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.NEVER_EXPIRE) {
redisBucket.store(key, value, (int) timeout);
}
}
/**
* 修改指定key-value键值对 (过期时间不变)
*/
@Override
public void update(String key, String value) {
long expire = getTimeout(key);
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 (redisBucket.exists(key)) {
redisBucket.delay(key, (int) timeout);
}
}
/**
* 获取Object如无返空
*/
@Override
public Object getObject(String key) {
return redisBucket.getAndDeserialize(key);
}
@Override
public <T> T getObject(String key, Class<T> classType) {
return redisBucket.getAndDeserialize(key, classType);
}
/**
* 写入Object并设定存活时间 (单位: )
*/
@Override
public void setObject(String key, Object object, long timeout) {
if (timeout > 0 || timeout == SaTokenDao.NEVER_EXPIRE) {
redisBucket.storeAndSerialize(key, object, (int) timeout);
}
}
/**
* 更新Object (过期时间不变)
*/
@Override
public void updateObject(String key, Object object) {
long expire = getObjectTimeout(key);
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 (redisBucket.exists(key)) {
redisBucket.delay(key, (int) timeout);
}
}
/**
* 搜索数据
*/
@Override
public List<String> searchData(String prefix, String keyword, int start, int size, boolean sortType) {
Set<String> keys = redisBucket.keys(prefix + "*" + keyword + "*");
List<String> list = new ArrayList<String>(keys);
return SaFoxUtil.searchList(list, start, size, sortType);
}
}

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>sa-token-plugin</artifactId>
<groupId>cn.dev33</groupId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sa-token-snack3</artifactId>
<dependencies>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-core</artifactId>
</dependency>
<dependency>
<groupId>org.noear</groupId>
<artifactId>snack3</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -13,25 +13,32 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.dao;
package cn.dev33.satoken.json;
import org.noear.redisx.RedisClient;
import java.util.Properties;
import org.noear.snack.ONode;
/**
* SaTokenDao redis 适配
*
* JSON 转换器 Snack3 版实现
*
* @author click33
* @author noear
* @since 1.34.0
* @since 1.41.0
*/
public class SaTokenDaoOfRedis extends SaTokenDaoOfRedisBase64 {
public class SaJsonTemplateForSnack3 implements SaJsonTemplate {
public SaTokenDaoOfRedis(Properties props) {
super(props);
}
/**
* 序列化对象 -> json 字符串
*/
@Override
public String objectToJson(Object obj) {
return ONode.stringify(obj);
}
public SaTokenDaoOfRedis(RedisClient redisClient) {
super(redisClient);
}
}
/**
* 反序列化json 字符串 对象
*/
@Override
public <T> T jsonToObject(String jsonStr, Class<T> type) {
return ONode.deserialize(jsonStr, type);
}
}

View File

@ -0,0 +1,46 @@
/*
* 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.json.SaJsonTemplateForSnack3;
import cn.dev33.satoken.session.SaSessionForSnack3Customized;
import cn.dev33.satoken.strategy.SaStrategy;
/**
* SaToken 插件安装JSON 转换器 - Snack3
*
* @author click33
* @author noear
* @since 1.41.0
*/
public class SaTokenPluginForSnack3 implements SaTokenPlugin {
@Override
public void install() {
// 设置JSON转换器Fastjson
SaManager.setSaJsonTemplate(new SaJsonTemplateForSnack3());
// 重写 SaSession 生成策略
SaStrategy.instance.createSession = SaSessionForSnack3Customized::new;
// 指定 SaSession 类型
SaStrategy.instance.sessionClassType = SaSessionForSnack3Customized.class;
}
}

View File

@ -0,0 +1,75 @@
/*
* 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.session;
import cn.dev33.satoken.util.SaFoxUtil;
import org.noear.snack.ONode;
/**
* Fastjson 定制版 SaSession重写类型转换API
*
* @author click33
* @author noear
* @since 1.34.0
*/
public class SaSessionForSnack3Customized extends SaSession {
private static final long serialVersionUID = -7600983549653130681L;
/**
* 构建一个 SaSession 对象
*/
public SaSessionForSnack3Customized() {
super();
}
/**
* 构建一个 SaSession 对象
*
* @param id Session id
*/
public SaSessionForSnack3Customized(String id) {
super(id);
}
/**
* 取值 (指定转换类型)
*
* @param <T> 泛型
* @param key key
* @param cs 指定转换类型
* @return
*/
@Override
public <T> T getModel(String key, Class<T> cs) {
// 如果是想取出为基础类型
Object value = get(key);
if (SaFoxUtil.isBasicType(cs)) {
return SaFoxUtil.getValueByType(value, cs);
}
// 为空提前返回
if (valueIsNull(value)) {
return null;
}
// 如果是 JSONObject 类型直接转否则先转为 String 再转
if (value instanceof ONode) {
ONode jo = (ONode) value;
return jo.toObject(cs);
} else {
return ONode.deserialize(value.toString(), cs);
}
}
}

View File

@ -0,0 +1 @@
cn.dev33.satoken.plugin.SaTokenPluginForSnack3

View File

@ -1,47 +0,0 @@
/*
* 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.solon.dao;
import cn.dev33.satoken.session.SaSession;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
/**
* Jackson定制版SaSession忽略 timeout 等属性的序列化
*
* @author click33
* @since 1.34.0
*/
@JsonIgnoreProperties({"timeout"})
public class SaSessionForJacksonCustomized extends SaSession {
/**
*
*/
private static final long serialVersionUID = -7600983549653130681L;
public SaSessionForJacksonCustomized() {
super();
}
/**
* 构建一个Session对象
* @param id Session的id
*/
public SaSessionForJacksonCustomized(String id) {
super(id);
}
}

View File

@ -1,38 +0,0 @@
/*
* 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.solon.dao;
import org.noear.redisx.RedisClient;
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);
}
}

View File

@ -1,169 +0,0 @@
/*
* 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.solon.dao;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.dao.auto.SaTokenDaoBySessionFollowObject;
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 SaTokenDaoBySessionFollowObject {
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.NEVER_EXPIRE) {
redisBucket.store(key, value, (int) timeout);
}
}
/**
* 修改指定key-value键值对 (过期时间不变)
*/
@Override
public void update(String key, String value) {
long expire = getTimeout(key);
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 (redisBucket.exists(key)) {
redisBucket.delay(key, (int) timeout);
}
}
/**
* 获取Object如无返空
*/
@Override
public Object getObject(String key) {
return redisBucket.getAndDeserialize(key);
}
@Override
public <T> T getObject(String key, Class<T> classType) {
return redisBucket.getAndDeserialize(key, classType);
}
/**
* 写入Object并设定存活时间 (单位: )
*/
@Override
public void setObject(String key, Object object, long timeout) {
if (timeout > 0 || timeout == SaTokenDao.NEVER_EXPIRE) {
redisBucket.storeAndSerialize(key, object, (int) timeout);
}
}
/**
* 更新Object (过期时间不变)
*/
@Override
public void updateObject(String key, Object object) {
long expire = getObjectTimeout(key);
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 (redisBucket.exists(key)) {
redisBucket.delay(key, (int) timeout);
}
}
/**
* 搜索数据
*/
@Override
public List<String> searchData(String prefix, String keyword, int start, int size, boolean sortType) {
Set<String> keys = redisBucket.keys(prefix + "*" + keyword + "*");
List<String> list = new ArrayList<String>(keys);
return SaFoxUtil.searchList(list, start, size, sortType);
}
}

View File

@ -1,176 +0,0 @@
/*
* 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.solon.dao;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.dao.auto.SaTokenDaoBySessionFollowObject;
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 SaTokenDaoBySessionFollowObject {
private final RedisBucket redisBucket;
public SaTokenDaoOfRedisJson(Properties props) {
this(new RedisClient(props));
}
public SaTokenDaoOfRedisJson(RedisClient redisClient) {
redisBucket = redisClient.getBucket();
// 重写 SaSession 生成策略
//SaStrategy.instance.createSession = (sessionId) -> new SaSessionForJson(sessionId);
}
/**
* 获取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.NEVER_EXPIRE) {
redisBucket.store(key, value, (int) timeout);
}
}
/**
* 修改指定key-value键值对 (过期时间不变)
*/
@Override
public void update(String key, String value) {
long expire = getTimeout(key);
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 (redisBucket.exists(key)) {
redisBucket.delay(key, (int) timeout);
}
}
/**
* 获取Object如无返空
*/
@Override
public Object getObject(String key) {
String value = get(key);
return ONode.deserialize(value);
}
@Override
public <T> T getObject(String key, Class<T> classType) {
String value = get(key);
return ONode.deserialize(value, classType);
}
/**
* 写入Object并设定存活时间 (单位: )
*/
@Override
public void setObject(String key, Object object, long timeout) {
if (timeout > 0 || timeout == SaTokenDao.NEVER_EXPIRE) {
String value = ONode.serialize(object);
set(key, value, timeout);
}
}
/**
* 更新Object (过期时间不变)
*/
@Override
public void updateObject(String key, Object object) {
long expire = getObjectTimeout(key);
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 (redisBucket.exists(key)) {
redisBucket.delay(key, (int) timeout);
}
}
/**
* 搜索数据
*/
@Override
public List<String> searchData(String prefix, String keyword, int start, int size, boolean sortType) {
Set<String> keys = redisBucket.keys(prefix + "*" + keyword + "*");
List<String> list = new ArrayList<>(keys);
return SaFoxUtil.searchList(list, start, size, sortType);
}
}

View File

@ -1,298 +0,0 @@
/*
* 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.solon.dao;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.dao.auto.SaTokenDaoBySessionFollowObject;
import cn.dev33.satoken.strategy.SaStrategy;
import cn.dev33.satoken.util.SaFoxUtil;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.redisson.api.RBatch;
import org.redisson.api.RBucket;
import org.redisson.api.RBucketAsync;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.Codec;
import org.redisson.codec.JsonJacksonCodec;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Sa-Token 持久层实现 [ Redisson客户端Redis存储Jackson序列化 ]
*
* @author 疯狂的狮子Li
* @author noear
* @since 1.34.0
*/
public class SaTokenDaoOfRedissonJackson implements SaTokenDaoBySessionFollowObject {
public static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
public static final String DATE_PATTERN = "yyyy-MM-dd";
public static final String TIME_PATTERN = "HH:mm:ss";
public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(DATE_TIME_PATTERN);
public static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern(DATE_PATTERN);
public static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern(TIME_PATTERN);
/**
* ObjectMapper 对象 ( public 作用域暴露出此对象方便开发者二次更改配置)
*
* <p> 例如
* <pre>
* SaTokenDaoRedisJackson redisJackson = (SaTokenDaoRedisJackson) SaManager.getSaTokenDao();
* redisJackson.objectMapper.xxx = xxx;
* </pre>
* </p>
*/
public final ObjectMapper objectMapper;
/**
* 序列化方式
*/
public final Codec codec;
/**
* redisson 客户端
*/
public final RedissonClient redissonClient;
public SaTokenDaoOfRedissonJackson(RedissonClient redissonClient) {
this.objectMapper = new ObjectMapper();
this.objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
// 配置[忽略未知字段]
this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 配置[时间类型转换]
JavaTimeModule timeModule = new JavaTimeModule();
// LocalDateTime序列化与反序列化
timeModule.addSerializer(new LocalDateTimeSerializer(DATE_TIME_FORMATTER));
timeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DATE_TIME_FORMATTER));
// LocalDate序列化与反序列化
timeModule.addSerializer(new LocalDateSerializer(DATE_FORMATTER));
timeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DATE_FORMATTER));
// LocalTime序列化与反序列化
timeModule.addSerializer(new LocalTimeSerializer(TIME_FORMATTER));
timeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(TIME_FORMATTER));
this.objectMapper.registerModule(timeModule);
// 重写 SaSession 生成策略
SaStrategy.instance.createSession = (sessionId) -> new SaSessionForJacksonCustomized(sessionId);
// 开始初始化相关组件
this.codec = new JsonJacksonCodec(objectMapper);
this.redissonClient = redissonClient;
}
/**
* 获取Value如无返空
*/
@Override
public String get(String key) {
RBucket<String> rBucket = redissonClient.getBucket(key, codec);
return rBucket.get();
}
/**
* 写入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) {
RBucket<String> bucket = redissonClient.getBucket(key, codec);
bucket.set(value);
} else {
RBatch batch = redissonClient.createBatch();
RBucketAsync<String> bucket = batch.getBucket(key, codec);
bucket.setAsync(value);
bucket.expireAsync(Duration.ofSeconds(timeout));
batch.execute();
}
}
/**
* 修修改指定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) {
redissonClient.getBucket(key, codec).delete();
}
/**
* 获取Value的剩余存活时间 (单位: )
*/
@Override
public long getTimeout(String key) {
RBucket<String> rBucket = redissonClient.getBucket(key, codec);
long timeout = rBucket.remainTimeToLive();
return timeout < 0 ? timeout : timeout / 1000;
}
/**
* 修改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;
}
RBucket<String> rBucket = redissonClient.getBucket(key, codec);
rBucket.expire(Duration.ofSeconds(timeout));
}
/**
* 获取Object如无返空
*/
@Override
public Object getObject(String key) {
RBucket<Object> rBucket = redissonClient.getBucket(key, codec);
return rBucket.get();
}
@Override
public <T> T getObject(String key, Class<T> classType) {
// TODO 待实现
return null;
}
/**
* 写入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) {
RBucket<Object> bucket = redissonClient.getBucket(key, codec);
bucket.set(object);
} else {
RBatch batch = redissonClient.createBatch();
RBucketAsync<Object> bucket = batch.getBucket(key, codec);
bucket.setAsync(object);
bucket.expireAsync(Duration.ofSeconds(timeout));
batch.execute();
}
}
/**
* 更新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) {
redissonClient.getBucket(key, codec).delete();
}
/**
* 获取Object的剩余存活时间 (单位: )
*/
@Override
public long getObjectTimeout(String key) {
RBucket<String> rBucket = redissonClient.getBucket(key, codec);
long timeout = rBucket.remainTimeToLive();
return timeout < 0 ? timeout : timeout / 1000;
}
/**
* 修改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;
}
RBucket<Object> rBucket = redissonClient.getBucket(key, codec);
rBucket.expire(Duration.ofSeconds(timeout));
}
/**
* 搜索数据
*/
@Override
public List<String> searchData(String prefix, String keyword, int start, int size, boolean sortType) {
Stream<String> stream = redissonClient.getKeys().getKeysStreamByPattern(prefix + "*" + keyword + "*");
List<String> list = stream.collect(Collectors.toList());
return SaFoxUtil.searchList(list, start, size, sortType);
}
}