From 30f01ab638d86c4bef692541440c40465e9b2fad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90li?= <15040126243@163.com> Date: Tue, 14 Feb 2023 18:07:44 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E9=87=8D=E6=9E=84=20=E5=85=A8?= =?UTF-8?q?=E5=B1=80=E7=BC=93=E5=AD=98KEY=20=E4=B8=8E=20=E5=B8=B8=E7=94=A8?= =?UTF-8?q?=E7=BC=93=E5=AD=98KEY=E5=81=9A=E5=8C=BA=E5=88=86=20update=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96=20=E5=A4=9A=E7=A7=9F=E6=88=B7=E6=94=AF?= =?UTF-8?q?=E6=8C=81=20SpringCache=20=E4=B8=8E=20SaToken?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/controller/CaptchaController.java | 6 +- .../ruoyi/web/service/SysLoginService.java | 8 +- .../ruoyi/web/service/SysRegisterService.java | 4 +- .../common/core/constant/CacheConstants.java | 26 +--- .../common/core/constant/CacheNames.java | 2 +- .../common/core/constant/GlobalConstants.java | 39 ++++++ .../common/core/constant/TenantConstants.java | 2 - .../aspectj/RepeatSubmitAspect.java | 4 +- .../ratelimiter/annotation/RateLimiter.java | 4 +- .../common/tenant/config/TenantConfig.java | 23 ++++ .../common/tenant/core/TenantSaTokenDao.java | 114 ++++++++++++++++++ .../tenant/handle/TenantKeyPrefixHandler.java | 22 +++- .../common/tenant/helper/TenantHelper.java | 61 ++++++++-- .../manager/TenantSpringCacheManager.java | 32 +++++ .../controller/monitor/CacheController.java | 11 +- .../monitor/SysLogininforController.java | 12 +- .../monitor/SysUserOnlineController.java | 11 +- .../service/impl/SysOssConfigServiceImpl.java | 47 ++++---- 18 files changed, 327 insertions(+), 101 deletions(-) create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/GlobalConstants.java create mode 100644 ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/core/TenantSaTokenDao.java create mode 100644 ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/manager/TenantSpringCacheManager.java diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/CaptchaController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/CaptchaController.java index 58f806678..bfb127a8e 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/CaptchaController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/CaptchaController.java @@ -5,8 +5,8 @@ import cn.hutool.captcha.AbstractCaptcha; import cn.hutool.captcha.generator.CodeGenerator; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.RandomUtil; -import com.ruoyi.common.core.constant.CacheConstants; import com.ruoyi.common.core.constant.Constants; +import com.ruoyi.common.core.constant.GlobalConstants; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.utils.SpringUtils; import com.ruoyi.common.core.utils.StringUtils; @@ -58,7 +58,7 @@ public class CaptchaController { if (!smsProperties.getEnabled()) { return R.fail("当前系统没有开启短信功能!"); } - String key = CacheConstants.CAPTCHA_CODE_KEY + phonenumber; + String key = GlobalConstants.CAPTCHA_CODE_KEY + phonenumber; String code = RandomUtil.randomNumbers(4); RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); // 验证码模板id 自行处理 (查数据库或写死均可) @@ -87,7 +87,7 @@ public class CaptchaController { } // 保存验证码信息 String uuid = IdUtil.simpleUUID(); - String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid; + String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + uuid; // 生成验证码 CaptchaType captchaType = captchaProperties.getType(); boolean isMath = CaptchaType.MATH == captchaType; diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysLoginService.java b/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysLoginService.java index 1922c0f96..22795124c 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysLoginService.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysLoginService.java @@ -6,8 +6,8 @@ import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.ruoyi.common.core.constant.CacheConstants; import com.ruoyi.common.core.constant.Constants; +import com.ruoyi.common.core.constant.GlobalConstants; import com.ruoyi.common.core.domain.dto.RoleDTO; import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.core.domain.model.XcxLoginUser; @@ -171,7 +171,7 @@ public class SysLoginService { * 校验短信验证码 */ private boolean validateSmsCode(String tenantId, String phonenumber, String smsCode) { - String code = RedisUtils.getCacheObject(CacheConstants.CAPTCHA_CODE_KEY + phonenumber); + String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + phonenumber); if (StringUtils.isBlank(code)) { recordLogininfor(tenantId, phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); throw new CaptchaExpireException(); @@ -187,7 +187,7 @@ public class SysLoginService { * @param uuid 唯一标识 */ public void validateCaptcha(String tenantId, String username, String code, String uuid, HttpServletRequest request) { - String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, ""); + String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, ""); String captcha = RedisUtils.getCacheObject(verifyKey); RedisUtils.deleteObject(verifyKey); if (captcha == null) { @@ -280,7 +280,7 @@ public class SysLoginService { * 登录校验 */ private void checkLogin(LoginType loginType, String tenantId, String username, Supplier supplier) { - String errorKey = CacheConstants.PWD_ERR_CNT_KEY + username; + String errorKey = GlobalConstants.PWD_ERR_CNT_KEY + username; String loginFail = Constants.LOGIN_FAIL; // 获取用户登录错误次数(可自定义限制策略 例如: key + username + ip) diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysRegisterService.java b/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysRegisterService.java index f695255cb..3f23c21e1 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysRegisterService.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysRegisterService.java @@ -1,8 +1,8 @@ package com.ruoyi.web.service; import cn.dev33.satoken.secure.BCrypt; -import com.ruoyi.common.core.constant.CacheConstants; import com.ruoyi.common.core.constant.Constants; +import com.ruoyi.common.core.constant.GlobalConstants; import com.ruoyi.common.core.constant.UserConstants; import com.ruoyi.common.core.domain.model.RegisterBody; import com.ruoyi.common.core.enums.UserType; @@ -75,7 +75,7 @@ public class SysRegisterService { * @return 结果 */ public void validateCaptcha(String tenantId, String username, String code, String uuid, HttpServletRequest request) { - String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, ""); + String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, ""); String captcha = RedisUtils.getCacheObject(verifyKey); RedisUtils.deleteObject(verifyKey); if (captcha == null) { diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheConstants.java index 9e49ae9a9..c5e8707c5 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheConstants.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheConstants.java @@ -3,25 +3,15 @@ package com.ruoyi.common.core.constant; /** * 缓存的key 常量 * - * @author ruoyi + * @author Lion Li */ public interface CacheConstants { - /** - * 登录用户 redis key - */ - String LOGIN_TOKEN_KEY = "Authorization:login:token:"; - /** * 在线用户 redis key */ String ONLINE_TOKEN_KEY = "online_tokens:"; - /** - * 验证码 redis key - */ - String CAPTCHA_CODE_KEY = TenantConstants.GLOBAL_REDIS_KEY + "captcha_codes:"; - /** * 参数管理 cache key */ @@ -32,18 +22,4 @@ public interface CacheConstants { */ String SYS_DICT_KEY = "sys_dict:"; - /** - * 防重提交 redis key - */ - String REPEAT_SUBMIT_KEY = "repeat_submit:"; - - /** - * 限流 redis key - */ - String RATE_LIMIT_KEY = "rate_limit:"; - - /** - * 登录账户密码错误次数 redis key - */ - String PWD_ERR_CNT_KEY = "pwd_err_cnt:"; } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheNames.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheNames.java index 32596f94e..81e92f58d 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheNames.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheNames.java @@ -33,7 +33,7 @@ public interface CacheNames { /** * 租户 */ - String SYS_TENANT = TenantConstants.GLOBAL_REDIS_KEY + "sys_tenant#30d"; + String SYS_TENANT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_tenant#30d"; /** * 用户账户 diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/GlobalConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/GlobalConstants.java new file mode 100644 index 000000000..7fcdad118 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/GlobalConstants.java @@ -0,0 +1,39 @@ +package com.ruoyi.common.core.constant; + +/** + * 全局的key常量 (业务无关的key) + * + * @author Lion Li + */ +public interface GlobalConstants { + + /** + * 全局 redis key (业务无关的key) + */ + String GLOBAL_REDIS_KEY = "global:"; + + /** + * 登录用户 redis key + */ + String LOGIN_TOKEN_KEY = GLOBAL_REDIS_KEY + "Authorization:login:token:"; + + /** + * 验证码 redis key + */ + String CAPTCHA_CODE_KEY = GLOBAL_REDIS_KEY + "captcha_codes:"; + + /** + * 防重提交 redis key + */ + String REPEAT_SUBMIT_KEY = GLOBAL_REDIS_KEY + "repeat_submit:"; + + /** + * 限流 redis key + */ + String RATE_LIMIT_KEY = GLOBAL_REDIS_KEY + "rate_limit:"; + + /** + * 登录账户密码错误次数 redis key + */ + String PWD_ERR_CNT_KEY = GLOBAL_REDIS_KEY + "pwd_err_cnt:"; +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/TenantConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/TenantConstants.java index 2adff276a..30a649b40 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/TenantConstants.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/TenantConstants.java @@ -48,6 +48,4 @@ public interface TenantConstants { */ String DEFAULT_TENANT_ID = "000000"; - String GLOBAL_REDIS_KEY = "global:"; - } diff --git a/ruoyi-common/ruoyi-common-idempotent/src/main/java/com/ruoyi/common/idempotent/aspectj/RepeatSubmitAspect.java b/ruoyi-common/ruoyi-common-idempotent/src/main/java/com/ruoyi/common/idempotent/aspectj/RepeatSubmitAspect.java index 1d8bcf44e..37824d5d7 100644 --- a/ruoyi-common/ruoyi-common-idempotent/src/main/java/com/ruoyi/common/idempotent/aspectj/RepeatSubmitAspect.java +++ b/ruoyi-common/ruoyi-common-idempotent/src/main/java/com/ruoyi/common/idempotent/aspectj/RepeatSubmitAspect.java @@ -3,7 +3,7 @@ package com.ruoyi.common.idempotent.aspectj; import cn.dev33.satoken.SaManager; import cn.hutool.core.util.ObjectUtil; import cn.hutool.crypto.SecureUtil; -import com.ruoyi.common.core.constant.CacheConstants; +import com.ruoyi.common.core.constant.GlobalConstants; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.exception.ServiceException; import com.ruoyi.common.core.utils.MessageUtils; @@ -57,7 +57,7 @@ public class RepeatSubmitAspect { submitKey = SecureUtil.md5(submitKey + ":" + nowParams); // 唯一标识(指定key + url + 消息头) - String cacheRepeatKey = CacheConstants.REPEAT_SUBMIT_KEY + url + submitKey; + String cacheRepeatKey = GlobalConstants.REPEAT_SUBMIT_KEY + url + submitKey; String key = RedisUtils.getCacheObject(cacheRepeatKey); if (key == null) { RedisUtils.setCacheObject(cacheRepeatKey, "", Duration.ofMillis(interval)); diff --git a/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/com/ruoyi/common/ratelimiter/annotation/RateLimiter.java b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/com/ruoyi/common/ratelimiter/annotation/RateLimiter.java index b5bd284f1..9fe9b0aa0 100644 --- a/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/com/ruoyi/common/ratelimiter/annotation/RateLimiter.java +++ b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/com/ruoyi/common/ratelimiter/annotation/RateLimiter.java @@ -1,6 +1,6 @@ package com.ruoyi.common.ratelimiter.annotation; -import com.ruoyi.common.core.constant.CacheConstants; +import com.ruoyi.common.core.constant.GlobalConstants; import com.ruoyi.common.ratelimiter.enums.LimitType; import java.lang.annotation.*; @@ -17,7 +17,7 @@ public @interface RateLimiter { /** * 限流key */ - String key() default CacheConstants.RATE_LIMIT_KEY; + String key() default GlobalConstants.RATE_LIMIT_KEY; /** * 限流时间,单位秒 diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/config/TenantConfig.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/config/TenantConfig.java index 58c3a069c..373e77c64 100644 --- a/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/config/TenantConfig.java +++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/config/TenantConfig.java @@ -1,5 +1,6 @@ package com.ruoyi.common.tenant.config; +import cn.dev33.satoken.dao.SaTokenDao; import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; @@ -8,8 +9,10 @@ import com.ruoyi.common.core.utils.reflect.ReflectUtils; import com.ruoyi.common.mybatis.config.MybatisPlusConfig; import com.ruoyi.common.redis.config.RedisConfig; import com.ruoyi.common.redis.config.properties.RedissonProperties; +import com.ruoyi.common.tenant.core.TenantSaTokenDao; import com.ruoyi.common.tenant.handle.PlusTenantLineHandler; import com.ruoyi.common.tenant.handle.TenantKeyPrefixHandler; +import com.ruoyi.common.tenant.manager.TenantSpringCacheManager; import com.ruoyi.common.tenant.properties.TenantProperties; import org.redisson.config.ClusterServersConfig; import org.redisson.config.SingleServerConfig; @@ -17,7 +20,9 @@ import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cache.CacheManager; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; import java.util.ArrayList; import java.util.List; @@ -74,4 +79,22 @@ public class TenantConfig { }; } + /** + * 多租户缓存管理器 + */ + @Primary + @Bean + public CacheManager tenantCacheManager() { + return new TenantSpringCacheManager(); + } + + /** + * 多租户鉴权dao实现 + */ + @Primary + @Bean + public SaTokenDao tenantSaTokenDao() { + return new TenantSaTokenDao(); + } + } diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/core/TenantSaTokenDao.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/core/TenantSaTokenDao.java new file mode 100644 index 000000000..db9c0258c --- /dev/null +++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/core/TenantSaTokenDao.java @@ -0,0 +1,114 @@ +package com.ruoyi.common.tenant.core; + +import com.ruoyi.common.core.constant.GlobalConstants; +import com.ruoyi.common.satoken.core.dao.PlusSaTokenDao; + +import java.util.List; + +/** + * SaToken 认证数据持久层 适配多租户 + * + * @author Lion Li + */ +public class TenantSaTokenDao extends PlusSaTokenDao { + + @Override + public String get(String key) { + return super.get(GlobalConstants.GLOBAL_REDIS_KEY + key); + } + + @Override + public void set(String key, String value, long timeout) { + super.set(GlobalConstants.GLOBAL_REDIS_KEY + key, value, timeout); + } + + /** + * 修修改指定key-value键值对 (过期时间不变) + */ + @Override + public void update(String key, String value) { + super.update(GlobalConstants.GLOBAL_REDIS_KEY + key, value); + } + + /** + * 删除Value + */ + @Override + public void delete(String key) { + super.delete(GlobalConstants.GLOBAL_REDIS_KEY + key); + } + + /** + * 获取Value的剩余存活时间 (单位: 秒) + */ + @Override + public long getTimeout(String key) { + return super.getTimeout(GlobalConstants.GLOBAL_REDIS_KEY + key); + } + + /** + * 修改Value的剩余存活时间 (单位: 秒) + */ + @Override + public void updateTimeout(String key, long timeout) { + super.updateTimeout(GlobalConstants.GLOBAL_REDIS_KEY + key, timeout); + } + + + /** + * 获取Object,如无返空 + */ + @Override + public Object getObject(String key) { + return super.getObject(GlobalConstants.GLOBAL_REDIS_KEY + key); + } + + /** + * 写入Object,并设定存活时间 (单位: 秒) + */ + @Override + public void setObject(String key, Object object, long timeout) { + super.setObject(GlobalConstants.GLOBAL_REDIS_KEY + key, object, timeout); + } + + /** + * 更新Object (过期时间不变) + */ + @Override + public void updateObject(String key, Object object) { + super.updateObject(GlobalConstants.GLOBAL_REDIS_KEY + key, object); + } + + /** + * 删除Object + */ + @Override + public void deleteObject(String key) { + super.deleteObject(GlobalConstants.GLOBAL_REDIS_KEY + key); + } + + /** + * 获取Object的剩余存活时间 (单位: 秒) + */ + @Override + public long getObjectTimeout(String key) { + return super.getObjectTimeout(GlobalConstants.GLOBAL_REDIS_KEY + key); + } + + /** + * 修改Object的剩余存活时间 (单位: 秒) + */ + @Override + public void updateObjectTimeout(String key, long timeout) { + super.updateObjectTimeout(GlobalConstants.GLOBAL_REDIS_KEY + key, timeout); + } + + + /** + * 搜索数据 + */ + @Override + public List searchData(String prefix, String keyword, int start, int size, boolean sortType) { + return super.searchData(GlobalConstants.GLOBAL_REDIS_KEY + prefix, keyword, start, size, sortType); + } +} diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/handle/TenantKeyPrefixHandler.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/handle/TenantKeyPrefixHandler.java index b4685a3c5..729702da9 100644 --- a/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/handle/TenantKeyPrefixHandler.java +++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/handle/TenantKeyPrefixHandler.java @@ -1,9 +1,9 @@ package com.ruoyi.common.tenant.handle; -import com.ruoyi.common.core.constant.TenantConstants; +import com.ruoyi.common.core.constant.GlobalConstants; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.redis.handler.KeyPrefixHandler; -import com.ruoyi.common.satoken.utils.LoginHelper; +import com.ruoyi.common.tenant.helper.TenantHelper; /** * 多租户redis缓存key前缀处理 @@ -24,10 +24,15 @@ public class TenantKeyPrefixHandler extends KeyPrefixHandler { if (StringUtils.isBlank(name)) { return null; } - if (StringUtils.contains(name, TenantConstants.GLOBAL_REDIS_KEY)) { + if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) { return super.map(name); } - return super.map(LoginHelper.getTenantId() + ":" + name); + String tenantId = TenantHelper.getTenantId(); + if (StringUtils.startsWith(name, tenantId)) { + // 如果存在则直接返回 + return super.map(name); + } + return super.map(tenantId + ":" + name); } /** @@ -39,10 +44,15 @@ public class TenantKeyPrefixHandler extends KeyPrefixHandler { if (StringUtils.isBlank(unmap)) { return null; } - if (StringUtils.contains(name, TenantConstants.GLOBAL_REDIS_KEY)) { + if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) { return super.unmap(name); } - return unmap.substring((LoginHelper.getTenantId() + ":").length()); + String tenantId = TenantHelper.getTenantId(); + if (StringUtils.startsWith(unmap, tenantId)) { + // 如果存在则删除 + return unmap.substring((tenantId + ":").length()); + } + return unmap; } } diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/helper/TenantHelper.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/helper/TenantHelper.java index 9d472001b..f9815be9d 100644 --- a/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/helper/TenantHelper.java +++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/helper/TenantHelper.java @@ -1,27 +1,34 @@ package com.ruoyi.common.tenant.helper; import cn.dev33.satoken.context.SaHolder; -import cn.dev33.satoken.stp.StpUtil; +import cn.dev33.satoken.spring.SpringMVCUtil; +import com.alibaba.ttl.TransmittableThreadLocal; import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy; import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; -import com.ruoyi.common.core.constant.TenantConstants; +import com.ruoyi.common.core.constant.GlobalConstants; import com.ruoyi.common.core.utils.SpringUtils; import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.redis.utils.RedisUtils; +import com.ruoyi.common.satoken.utils.LoginHelper; import com.ruoyi.common.tenant.properties.TenantProperties; import lombok.AccessLevel; import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; /** * 租户助手 * * @author Lion Li */ +@Slf4j @NoArgsConstructor(access = AccessLevel.PRIVATE) public class TenantHelper { private static final TenantProperties PROPERTIES = SpringUtils.getBean(TenantProperties.class); - private static final String DYNAMIC_TENANT_KEY = TenantConstants.GLOBAL_REDIS_KEY + "dynamicTenant"; + private static final String DYNAMIC_TENANT_KEY = GlobalConstants.GLOBAL_REDIS_KEY + "dynamicTenant"; + + private static final ThreadLocal TEMP_DYNAMIC_TENANT = new TransmittableThreadLocal<>(); /** * 租户功能是否启用 @@ -45,31 +52,61 @@ public class TenantHelper { } /** - * 设置动态租户(一直有效) + * 设置动态租户(一直有效 需要手动清理) + *

+ * 如果为非web环境 那么只在当前线程内生效 */ public static void setDynamic(String tenantId) { - StpUtil.getTokenSession().set(DYNAMIC_TENANT_KEY, tenantId); + if (!SpringMVCUtil.isWeb()) { + TEMP_DYNAMIC_TENANT.set(tenantId); + return; + } + String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getTenantId(); + RedisUtils.setCacheObject(cacheKey, tenantId); + SaHolder.getStorage().set(cacheKey, tenantId); } /** - * 获取动态租户(一直有效) + * 获取动态租户(一直有效 需要手动清理) + *

+ * 如果为非web环境 那么只在当前线程内生效 */ public static String getDynamic() { - String tenantId = (String) SaHolder.getStorage().get(DYNAMIC_TENANT_KEY); + if (!SpringMVCUtil.isWeb()) { + return TEMP_DYNAMIC_TENANT.get(); + } + String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getTenantId(); + String tenantId = (String) SaHolder.getStorage().get(cacheKey); if (StringUtils.isNotBlank(tenantId)) { return tenantId; } - tenantId = (String) StpUtil.getTokenSession().get(DYNAMIC_TENANT_KEY); - SaHolder.getStorage().set(DYNAMIC_TENANT_KEY, tenantId); + tenantId = RedisUtils.getCacheObject(cacheKey); + SaHolder.getStorage().set(cacheKey, tenantId); return tenantId; } /** - * 清除动态租户(一直有效) + * 清除动态租户 */ public static void clearDynamic() { - SaHolder.getStorage().delete(DYNAMIC_TENANT_KEY); - StpUtil.getTokenSession().delete(DYNAMIC_TENANT_KEY); + if (!SpringMVCUtil.isWeb()) { + TEMP_DYNAMIC_TENANT.remove(); + return; + } + String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getTenantId(); + RedisUtils.deleteObject(cacheKey); + SaHolder.getStorage().delete(cacheKey); + } + + /** + * 获取当前租户id(动态租户优先) + */ + public static String getTenantId() { + String tenantId = TenantHelper.getDynamic(); + if (StringUtils.isBlank(tenantId)) { + tenantId = LoginHelper.getTenantId(); + } + return tenantId; } } diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/manager/TenantSpringCacheManager.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/manager/TenantSpringCacheManager.java new file mode 100644 index 000000000..83402b76f --- /dev/null +++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/manager/TenantSpringCacheManager.java @@ -0,0 +1,32 @@ +package com.ruoyi.common.tenant.manager; + +import com.ruoyi.common.core.constant.GlobalConstants; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.redis.manager.PlusSpringCacheManager; +import com.ruoyi.common.tenant.helper.TenantHelper; +import org.springframework.cache.Cache; + +/** + * 重写 cacheName 处理方法 支持多租户 + * + * @author Lion Li + */ +public class TenantSpringCacheManager extends PlusSpringCacheManager { + + public TenantSpringCacheManager() { + } + + @Override + public Cache getCache(String name) { + if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) { + return super.getCache(name); + } + String tenantId = TenantHelper.getTenantId(); + if (StringUtils.startsWith(name, tenantId)) { + // 如果存在则直接返回 + return super.getCache(name); + } + return super.getCache(tenantId + ":" + name); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/CacheController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/CacheController.java index 03fc761ad..2d99a7a8c 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/CacheController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/CacheController.java @@ -4,6 +4,7 @@ import cn.dev33.satoken.annotation.SaCheckPermission; import cn.hutool.core.collection.CollUtil; import com.ruoyi.common.core.constant.CacheConstants; import com.ruoyi.common.core.constant.CacheNames; +import com.ruoyi.common.core.constant.GlobalConstants; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.utils.StreamUtils; import com.ruoyi.common.core.utils.StringUtils; @@ -34,15 +35,15 @@ public class CacheController { private final static List CACHES = new ArrayList<>(); static { - CACHES.add(new SysCache(CacheConstants.LOGIN_TOKEN_KEY, "用户信息")); + CACHES.add(new SysCache(GlobalConstants.LOGIN_TOKEN_KEY, "用户信息")); CACHES.add(new SysCache(CacheConstants.ONLINE_TOKEN_KEY, "在线用户")); CACHES.add(new SysCache(CacheNames.SYS_CONFIG, "配置信息")); CACHES.add(new SysCache(CacheNames.SYS_DICT, "数据字典")); - CACHES.add(new SysCache(CacheConstants.CAPTCHA_CODE_KEY, "验证码")); - CACHES.add(new SysCache(CacheConstants.REPEAT_SUBMIT_KEY, "防重提交")); - CACHES.add(new SysCache(CacheConstants.RATE_LIMIT_KEY, "限流处理")); + CACHES.add(new SysCache(GlobalConstants.CAPTCHA_CODE_KEY, "验证码")); + CACHES.add(new SysCache(GlobalConstants.REPEAT_SUBMIT_KEY, "防重提交")); + CACHES.add(new SysCache(GlobalConstants.RATE_LIMIT_KEY, "限流处理")); CACHES.add(new SysCache(CacheNames.SYS_OSS_CONFIG, "OSS配置")); - CACHES.add(new SysCache(CacheConstants.PWD_ERR_CNT_KEY, "密码错误次数")); + CACHES.add(new SysCache(GlobalConstants.PWD_ERR_CNT_KEY, "密码错误次数")); } /** diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/SysLogininforController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/SysLogininforController.java index 7e9d08368..1ef7f7fbe 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/SysLogininforController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/SysLogininforController.java @@ -1,23 +1,23 @@ package com.ruoyi.system.controller.monitor; import cn.dev33.satoken.annotation.SaCheckPermission; -import com.ruoyi.common.core.constant.CacheConstants; -import com.ruoyi.common.mybatis.core.page.PageQuery; +import com.ruoyi.common.core.constant.GlobalConstants; import com.ruoyi.common.core.domain.R; -import com.ruoyi.common.mybatis.core.page.TableDataInfo; -import com.ruoyi.common.web.core.BaseController; import com.ruoyi.common.excel.utils.ExcelUtil; import com.ruoyi.common.log.annotation.Log; import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.mybatis.core.page.PageQuery; +import com.ruoyi.common.mybatis.core.page.TableDataInfo; import com.ruoyi.common.redis.utils.RedisUtils; +import com.ruoyi.common.web.core.BaseController; import com.ruoyi.system.domain.bo.SysLogininforBo; import com.ruoyi.system.domain.vo.SysLogininforVo; import com.ruoyi.system.service.ISysLogininforService; +import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import jakarta.servlet.http.HttpServletResponse; import java.util.List; /** @@ -79,7 +79,7 @@ public class SysLogininforController extends BaseController { @Log(title = "账户解锁", businessType = BusinessType.OTHER) @GetMapping("/unlock/{userName}") public R unlock(@PathVariable("userName") String userName) { - String loginName = CacheConstants.PWD_ERR_CNT_KEY + userName; + String loginName = GlobalConstants.PWD_ERR_CNT_KEY + userName; if (RedisUtils.hasKey(loginName)) { RedisUtils.deleteObject(loginName); } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/SysUserOnlineController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/SysUserOnlineController.java index bebfad251..9daa394d7 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/SysUserOnlineController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/SysUserOnlineController.java @@ -4,16 +4,17 @@ import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.exception.NotLoginException; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.bean.BeanUtil; -import com.ruoyi.common.log.annotation.Log; import com.ruoyi.common.core.constant.CacheConstants; -import com.ruoyi.common.web.core.BaseController; +import com.ruoyi.common.core.constant.GlobalConstants; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.domain.dto.UserOnlineDTO; -import com.ruoyi.common.mybatis.core.page.TableDataInfo; -import com.ruoyi.common.log.enums.BusinessType; import com.ruoyi.common.core.utils.StreamUtils; import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.mybatis.core.page.TableDataInfo; import com.ruoyi.common.redis.utils.RedisUtils; +import com.ruoyi.common.web.core.BaseController; import com.ruoyi.system.domain.SysUserOnline; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; @@ -45,7 +46,7 @@ public class SysUserOnlineController extends BaseController { List keys = StpUtil.searchTokenValue("", 0, -1, false); List userOnlineDTOList = new ArrayList<>(); for (String key : keys) { - String token = key.replace(CacheConstants.LOGIN_TOKEN_KEY, ""); + String token = key.replace(GlobalConstants.LOGIN_TOKEN_KEY, ""); // 如果已经过期则跳过 if (StpUtil.stpLogic.getTokenActivityTimeoutByToken(token) < -1) { continue; diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssConfigServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssConfigServiceImpl.java index fe97a9eff..61e5c8d0f 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssConfigServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssConfigServiceImpl.java @@ -10,15 +10,16 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.common.core.constant.CacheNames; import com.ruoyi.common.core.constant.UserConstants; import com.ruoyi.common.core.exception.ServiceException; -import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.common.core.utils.StreamUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.json.utils.JsonUtils; import com.ruoyi.common.mybatis.core.page.PageQuery; import com.ruoyi.common.mybatis.core.page.TableDataInfo; import com.ruoyi.common.oss.constant.OssConstant; -import com.ruoyi.common.oss.factory.OssFactory; import com.ruoyi.common.redis.utils.CacheUtils; import com.ruoyi.common.redis.utils.RedisUtils; +import com.ruoyi.common.tenant.core.TenantEntity; +import com.ruoyi.common.tenant.helper.TenantHelper; import com.ruoyi.system.domain.SysOssConfig; import com.ruoyi.system.domain.bo.SysOssConfigBo; import com.ruoyi.system.domain.vo.SysOssConfigVo; @@ -26,12 +27,12 @@ import com.ruoyi.system.mapper.SysOssConfigMapper; import com.ruoyi.system.service.ISysOssConfigService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Collection; import java.util.List; +import java.util.Map; /** * 对象存储配置Service业务层处理 @@ -52,17 +53,23 @@ public class SysOssConfigServiceImpl implements ISysOssConfigService { */ @Override public void init() { - List list = baseMapper.selectList(); - // 加载OSS初始化配置 - for (SysOssConfig config : list) { - String configKey = config.getConfigKey(); - if ("0".equals(config.getStatus())) { - RedisUtils.setCacheObject(OssConstant.DEFAULT_CONFIG_KEY, configKey); + TenantHelper.enableIgnore(); + List list = baseMapper.selectList( + new LambdaQueryWrapper().orderByAsc(TenantEntity::getTenantId)); + TenantHelper.disableIgnore(); + Map> map = StreamUtils.groupByKey(list, SysOssConfig::getTenantId); + for (String tenantId : map.keySet()) { + TenantHelper.setDynamic(tenantId); + // 加载OSS初始化配置 + for (SysOssConfig config : map.get(tenantId)) { + String configKey = config.getConfigKey(); + if ("0".equals(config.getStatus())) { + RedisUtils.setCacheObject(OssConstant.DEFAULT_CONFIG_KEY, configKey); + } + CacheUtils.put(CacheNames.SYS_OSS_CONFIG, config.getConfigKey(), JsonUtils.toJsonString(config)); } - SpringUtils.context().publishEvent(config); } - // 初始化OSS工厂 - OssFactory.init(); + TenantHelper.clearDynamic(); } @Override @@ -92,7 +99,7 @@ public class SysOssConfigServiceImpl implements ISysOssConfigService { validEntityBeforeSave(config); boolean flag = baseMapper.insert(config) > 0; if (flag) { - SpringUtils.context().publishEvent(config); + CacheUtils.put(CacheNames.SYS_OSS_CONFIG, config.getConfigKey(), JsonUtils.toJsonString(config)); } return flag; } @@ -109,7 +116,7 @@ public class SysOssConfigServiceImpl implements ISysOssConfigService { luw.eq(SysOssConfig::getOssConfigId, config.getOssConfigId()); boolean flag = baseMapper.update(config, luw) > 0; if (flag) { - SpringUtils.context().publishEvent(config); + CacheUtils.put(CacheNames.SYS_OSS_CONFIG, config.getConfigKey(), JsonUtils.toJsonString(config)); } return flag; } @@ -174,16 +181,4 @@ public class SysOssConfigServiceImpl implements ISysOssConfigService { return row; } - /** - * 更新配置缓存 - * - * @param config 配置 - */ - @EventListener - public void updateConfigCache(SysOssConfig config) { - CacheUtils.put(CacheNames.SYS_OSS_CONFIG, config.getConfigKey(), JsonUtils.toJsonString(config)); - RedisUtils.publish(OssConstant.DEFAULT_CONFIG_KEY, config.getConfigKey(), msg -> { - log.info("发布刷新OSS配置 => " + msg); - }); - } }