From eb4bd150c3cf65fb1d7aa17617ec94670acdd5c1 Mon Sep 17 00:00:00 2001 From: lihao Date: Wed, 14 Aug 2024 18:16:37 +0800 Subject: [PATCH] =?UTF-8?q?=E9=9B=86=E6=88=90MongoDB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-doc/up/integ-redis.md | 239 +++++++++++++++++++++++++++++++++ 1 file changed, 239 insertions(+) diff --git a/sa-token-doc/up/integ-redis.md b/sa-token-doc/up/integ-redis.md index b01ec4de..bea24453 100644 --- a/sa-token-doc/up/integ-redis.md +++ b/sa-token-doc/up/integ-redis.md @@ -141,6 +141,245 @@ spring.redis.lettuce.pool.min-idle=0 **4. 集成包版本问题**
Sa-Token-Redis 集成包的版本尽量与 Sa-Token-Starter 集成包的版本一致,否则可能出现兼容性问题。 +### 示例:在 Spring Boot 下集成 MongoDB: + + + +``` xml + + + org.springframework.boot + spring-boot-starter-data-mongodb + +``` + +``` gradle +// 提供MongoDB依赖 +implementation 'org.springframework.boot:spring-boot-starter-data-mongodb' +``` + + +1. 创建一个 `MySaSession` 并继承 `SaSession` +```java +public class MySaSession extends SaSession { + public MySaSession(String id) { + super(id); + } + + public void setDataMap(Map dataMap) { + refreshDataMap(dataMap); + } +} +``` +原因:由于 `SaSession` 中的 `dataMap` 字段没有 `setter` 方法,当 `spring-data-mongodb` 反序列化 `SaSession` 时会报 `Cannot set property dataMap because no setter, no wither and it's not part of the persistence constructor public cn.dev33.satoken.session.SaSession()` 错误 + +2. 在 `SpringBoot` 启动方法中重写 `SaStrategy.instance.createSession` 方法,使我们自定义的 `MySaSession` 生效 +```java +@SpringBootApplication +public class SpringApplication { + + public static void main(String[] args) { + + // 重写 SaStrategy.instance.createSession 方法 + SaStrategy.instance.createSession = (sessionId) -> { + return new MySaSession(sessionId); + }; + + SpringApplication.run(SpringApplication.class, args); + } +} +``` + +3. 实现 SaTokenDao 接口 +```java +//定义一个类用于保存SaSession +@Document +public class SaTokenWrap { + private String id; + private String value; + private Object object; + // 这里利用MongoDB的TTL索引,当过期时MongoDB会自动删除过期的数据,同时如果timeout如果为null那么视为永不删除 + @Indexed(expireAfterSeconds = 1, background = true) + private Date timeout; + + + public boolean live() { + return getTimeout() == null || getTimeout().after(new Date()); + } +} +``` +```java +// SaTokenDao 实现 +@Component +public class SaTokenDaoMongo implements SaTokenDao { + + + private final MongoTemplate mongoTemplate; + + public SaTokenDaoMongo(MongoTemplate mongoTemplate) { + this.mongoTemplate = mongoTemplate; + } + + + Optional getByKey(String key) { + SaTokenWrap tokenWrap = mongoTemplate.findById(key, SaTokenWrap.class); + + return Optional.ofNullable(tokenWrap).filter(SaTokenWrap::live); + } + + Date timeoutToDate(long timeout) { + + return new Date(timeout * 1000 + System.currentTimeMillis()); + } + + void upsertByPath(String key, String path, Object value, long timeout) { + if (timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } + Update update = Update.update(path, value); + + if (timeout != SaTokenDao.NEVER_EXPIRE) { + update.set("timeout", timeoutToDate(timeout)); + } else { + update.unset("timeout"); + } + + mongoTemplate.upsert( + Query.query(Criteria.where("id").is(key)), + update, + SaTokenWrap.class + ); + } + + void updateByPath(String key, String path, Object value) { + mongoTemplate.updateFirst( + Query.query(Criteria.where("id").is(key).and("timeout").gte(new Date())), + Update.update(path, value), + SaTokenWrap.class + ); + } + + // ------------------------ String 读写操作 + + @Override + public String get(String key) { + + return getByKey(key).map(SaTokenWrap::getValue).orElse(null); + } + + @Override + public void set(String key, String value, long timeout) { + upsertByPath(key, "value", value, timeout); + } + + @Override + public void update(String key, String value) { + updateByPath(key, "value", value); + } + + @Override + public void delete(String key) { + mongoTemplate.remove(Query.query(Criteria.where("id").is(key))); + } + + @Override + public long getTimeout(String key) { + + SaTokenWrap tokenWrap = mongoTemplate.findById(key, SaTokenWrap.class); + + if (tokenWrap == null) { + return SaTokenDao.NOT_VALUE_EXPIRE; + } + + if (tokenWrap.getTimeout() == null) { + return SaTokenDao.NEVER_EXPIRE; + } + + long expire = tokenWrap.getTimeout().getTime(); + long timeout = (expire - System.currentTimeMillis()) / 1000; + + // 小于零时,视为不存在 + if (timeout < 0) { + mongoTemplate.remove(Query.query(Criteria.where("id").is(key))); + return SaTokenDao.NOT_VALUE_EXPIRE; + } + return timeout; + } + + @Override + public void updateTimeout(String key, long timeout) { + + Update update = new Update(); + + if (timeout == SaTokenDao.NEVER_EXPIRE) { + update.unset("timeout"); + } else { + update.set("timeout", timeoutToDate(timeout)); + } + + mongoTemplate.upsert( + Query.query(Criteria.where("id").is(key)), + update, + SaTokenWrap.class + ); + } + + + // ------------------------ Object 读写操作 + + @Override + public Object getObject(String key) { + return getByKey(key).map(SaTokenWrap::getObject).orElse(null); + } + + @Override + public void setObject(String key, Object object, long timeout) { + upsertByPath(key, "object", object, timeout); + } + + @Override + public void updateObject(String key, Object object) { + updateByPath(key, "object", object); + } + + @Override + public void deleteObject(String key) { + delete(key); + } + + @Override + public long getObjectTimeout(String key) { + return getTimeout(key); + } + + @Override + public void updateObjectTimeout(String key, long timeout) { + updateTimeout(key, timeout); + } + + + // ------------------------ Session 读写操作 + // 使用接口默认实现 + + + // --------- 会话管理 + + @Override + public List searchData(String prefix, String keyword, int start, int size, boolean sortType) { + + List wrapList = mongoTemplate.find( + Query.query(Criteria.where("id").regex(prefix + "*" + keyword + "*").and("timeout").gte(new Date())), + SaTokenWrap.class + ); + + List list = wrapList.stream().map(SaTokenWrap::getValue).filter(StringUtils::hasText).collect(Collectors.toList()); + + return SaFoxUtil.searchList(list, start, size, sortType); + } + + +} +```

更多框架的集成方案正在更新中...