CLIENT_CACHE = new ConcurrentHashMap<>();
+ private static final ReentrantLock LOCK = new ReentrantLock();
/**
* 获取默认实例
@@ -39,7 +41,7 @@ public class OssFactory {
/**
* 根据类型获取实例
*/
- public static synchronized OssClient instance(String configKey) {
+ public static OssClient instance(String configKey) {
String json = CacheUtils.get(CacheNames.SYS_OSS_CONFIG, configKey);
if (json == null) {
throw new OssException("系统异常, '" + configKey + "'配置信息不存在!");
@@ -48,16 +50,19 @@ public class OssFactory {
// 使用租户标识避免多个租户相同key实例覆盖
String key = properties.getTenantId() + ":" + configKey;
OssClient client = CLIENT_CACHE.get(key);
- if (client == null) {
- CLIENT_CACHE.put(key, new OssClient(configKey, properties));
- log.info("创建OSS实例 key => {}", configKey);
- return CLIENT_CACHE.get(key);
- }
- // 配置不相同则重新构建
- if (!client.checkPropertiesSame(properties)) {
- CLIENT_CACHE.put(key, new OssClient(configKey, properties));
- log.info("重载OSS实例 key => {}", configKey);
- return CLIENT_CACHE.get(key);
+ // 客户端不存在或配置不相同则重新构建
+ if (client == null || !client.checkPropertiesSame(properties)) {
+ LOCK.lock();
+ try {
+ client = CLIENT_CACHE.get(key);
+ if (client == null || !client.checkPropertiesSame(properties)) {
+ CLIENT_CACHE.put(key, new OssClient(configKey, properties));
+ log.info("创建OSS实例 key => {}", configKey);
+ return CLIENT_CACHE.get(key);
+ }
+ } finally {
+ LOCK.unlock();
+ }
}
return client;
}
diff --git a/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java
index 8f3a5cafb..02735b073 100644
--- a/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java
+++ b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java
@@ -1,29 +1,29 @@
package org.dromara.common.ratelimiter.aspectj;
-import cn.hutool.core.util.ArrayUtil;
-import org.dromara.common.core.constant.GlobalConstants;
-import org.dromara.common.core.exception.ServiceException;
-import org.dromara.common.core.utils.MessageUtils;
-import org.dromara.common.core.utils.ServletUtils;
-import org.dromara.common.core.utils.StringUtils;
-import org.dromara.common.ratelimiter.annotation.RateLimiter;
-import org.dromara.common.ratelimiter.enums.LimitType;
-import org.dromara.common.redis.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
+import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.MessageUtils;
+import org.dromara.common.core.utils.ServletUtils;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.ratelimiter.annotation.RateLimiter;
+import org.dromara.common.ratelimiter.enums.LimitType;
+import org.dromara.common.redis.utils.RedisUtils;
import org.redisson.api.RateType;
+import org.springframework.context.expression.BeanFactoryResolver;
+import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
-import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParserContext;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
-import org.springframework.expression.spel.support.StandardEvaluationContext;
import java.lang.reflect.Method;
@@ -44,21 +44,18 @@ public class RateLimiterAspect {
* 定义spel解析模版
*/
private final ParserContext parserContext = new TemplateParserContext();
- /**
- * 定义spel上下文对象进行解析
- */
- private final EvaluationContext context = new StandardEvaluationContext();
/**
* 方法参数解析器
*/
private final ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer();
+
@Before("@annotation(rateLimiter)")
- public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable {
+ public void doBefore(JoinPoint point, RateLimiter rateLimiter) {
int time = rateLimiter.time();
int count = rateLimiter.count();
- String combineKey = getCombineKey(rateLimiter, point);
try {
+ String combineKey = getCombineKey(rateLimiter, point);
RateType rateType = RateType.OVERALL;
if (rateLimiter.limitType() == LimitType.CLUSTER) {
rateType = RateType.PER_CLIENT;
@@ -76,42 +73,29 @@ public class RateLimiterAspect {
if (e instanceof ServiceException) {
throw e;
} else {
- throw new RuntimeException("服务器限流异常,请稍候再试");
+ throw new RuntimeException("服务器限流异常,请稍候再试", e);
}
}
}
- public String getCombineKey(RateLimiter rateLimiter, JoinPoint point) {
+ private String getCombineKey(RateLimiter rateLimiter, JoinPoint point) {
String key = rateLimiter.key();
- // 获取方法(通过方法签名来获取)
- MethodSignature signature = (MethodSignature) point.getSignature();
- Method method = signature.getMethod();
- Class> targetClass = method.getDeclaringClass();
- // 判断是否是spel格式
- if (StringUtils.containsAny(key, "#")) {
- // 获取参数值
+ if (StringUtils.isNotBlank(key)) {
+ MethodSignature signature = (MethodSignature) point.getSignature();
+ Method targetMethod = signature.getMethod();
Object[] args = point.getArgs();
- // 获取方法上参数的名称
- String[] parameterNames = pnd.getParameterNames(method);
- if (ArrayUtil.isEmpty(parameterNames)) {
- throw new ServiceException("限流key解析异常!请联系管理员!");
- }
- for (int i = 0; i < parameterNames.length; i++) {
- context.setVariable(parameterNames[i], args[i]);
- }
- // 解析返回给key
- try {
- Expression expression;
- if (StringUtils.startsWith(key, parserContext.getExpressionPrefix())
- && StringUtils.endsWith(key, parserContext.getExpressionSuffix())) {
- expression = parser.parseExpression(key, parserContext);
- } else {
- expression = parser.parseExpression(key);
- }
- key = expression.getValue(context, String.class) + ":";
- } catch (Exception e) {
- throw new ServiceException("限流key解析异常!请联系管理员!");
+ //noinspection DataFlowIssue
+ MethodBasedEvaluationContext context =
+ new MethodBasedEvaluationContext(null, targetMethod, args, pnd);
+ context.setBeanResolver(new BeanFactoryResolver(SpringUtils.getBeanFactory()));
+ Expression expression;
+ if (StringUtils.startsWith(key, parserContext.getExpressionPrefix())
+ && StringUtils.endsWith(key, parserContext.getExpressionSuffix())) {
+ expression = parser.parseExpression(key, parserContext);
+ } else {
+ expression = parser.parseExpression(key);
}
+ key = expression.getValue(context, String.class);
}
StringBuilder stringBuffer = new StringBuilder(GlobalConstants.RATE_LIMIT_KEY);
stringBuffer.append(ServletUtils.getRequest().getRequestURI()).append(":");
diff --git a/ruoyi-common/ruoyi-common-ratelimiter/src/main/resources/spel-extension.json b/ruoyi-common/ruoyi-common-ratelimiter/src/main/resources/spel-extension.json
new file mode 100644
index 000000000..b16432b29
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-ratelimiter/src/main/resources/spel-extension.json
@@ -0,0 +1,7 @@
+{
+ "org.dromara.common.ratelimiter.annotation.RateLimiter@key": {
+ "method": {
+ "parameters": true
+ }
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java
index 0833d2b52..f4328f4d4 100644
--- a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java
+++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java
@@ -6,6 +6,7 @@ import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.redis.config.properties.RedissonProperties;
import org.dromara.common.redis.handler.KeyPrefixHandler;
import org.redisson.client.codec.StringCodec;
@@ -16,6 +17,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
+import org.springframework.core.task.VirtualThreadTaskExecutor;
/**
* redis配置
@@ -48,6 +50,9 @@ public class RedisConfig {
// 缓存 Lua 脚本 减少网络传输(redisson 大部分的功能都是基于 Lua 脚本实现)
.setUseScriptCache(true)
.setCodec(codec);
+ if (SpringUtils.isVirtual()) {
+ config.setNettyExecutor(new VirtualThreadTaskExecutor("redisson-"));
+ }
RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig();
if (ObjectUtil.isNotNull(singleServerConfig)) {
// 使用单机模式
diff --git a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java
index 058dee769..21acfb1d1 100644
--- a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java
+++ b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java
@@ -101,13 +101,18 @@ public class LoginHelper {
return Convert.toLong(getExtra(DEPT_KEY));
}
+ /**
+ * 获取当前 Token 的扩展信息
+ *
+ * @param key 键值
+ * @return 对应的扩展数据
+ */
private static Object getExtra(String key) {
try {
return StpUtil.getExtra(key);
} catch (Exception e) {
return null;
}
-
}
/**
@@ -135,12 +140,17 @@ public class LoginHelper {
return UserConstants.SUPER_ADMIN_ID.equals(userId);
}
+ /**
+ * 是否为超级管理员
+ *
+ * @return 结果
+ */
public static boolean isSuperAdmin() {
return isSuperAdmin(getUserId());
}
/**
- * 是否为超级管理员
+ * 是否为租户管理员
*
* @param rolePermission 角色权限标识组
* @return 结果
@@ -149,10 +159,20 @@ public class LoginHelper {
return rolePermission.contains(TenantConstants.TENANT_ADMIN_ROLE_KEY);
}
+ /**
+ * 是否为租户管理员
+ *
+ * @return 结果
+ */
public static boolean isTenantAdmin() {
return Convert.toBool(isTenantAdmin(getLoginUser().getRolePermission()));
}
+ /**
+ * 检查当前用户是否已登录
+ *
+ * @return 结果
+ */
public static boolean isLogin() {
return getLoginUser() != null;
}
diff --git a/ruoyi-common/ruoyi-common-sms/pom.xml b/ruoyi-common/ruoyi-common-sms/pom.xml
index c50f222ac..932cb9d52 100644
--- a/ruoyi-common/ruoyi-common-sms/pom.xml
+++ b/ruoyi-common/ruoyi-common-sms/pom.xml
@@ -20,13 +20,12 @@
org.dromara.sms4j
sms4j-spring-boot-starter
-
-
-
- com.alibaba
- fastjson
-
-
+
+
+
+
+ org.dromara
+ ruoyi-common-redis
diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsAutoConfiguration.java b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsAutoConfiguration.java
index 29f60fc50..1e88407e8 100644
--- a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsAutoConfiguration.java
+++ b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsAutoConfiguration.java
@@ -1,14 +1,24 @@
package org.dromara.common.sms.config;
+import org.dromara.common.sms.core.dao.PlusSmsDao;
+import org.dromara.sms4j.api.dao.SmsDao;
import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Primary;
/**
- * 短信配置类(暂时没用 预留扩展)
+ * 短信配置类
*
- * @author Lion Li
- * @version 4.2.0
+ * @author Feng
*/
-@AutoConfiguration
+@AutoConfiguration(after = {RedisAutoConfiguration.class})
public class SmsAutoConfiguration {
+ @Primary
+ @Bean
+ public SmsDao smsDao() {
+ return new PlusSmsDao();
+ }
+
}
diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/dao/PlusSmsDao.java b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/dao/PlusSmsDao.java
new file mode 100644
index 000000000..91d8d243a
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/dao/PlusSmsDao.java
@@ -0,0 +1,72 @@
+package org.dromara.common.sms.core.dao;
+
+import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.sms4j.api.dao.SmsDao;
+
+import java.time.Duration;
+
+/**
+ * SmsDao缓存配置 (使用框架自带RedisUtils实现 协议统一)
+ * 主要用于短信重试和拦截的缓存
+ *
+ * @author Feng
+ */
+public class PlusSmsDao implements SmsDao {
+
+ /**
+ * 存储
+ *
+ * @param key 键
+ * @param value 值
+ * @param cacheTime 缓存时间(单位:秒)
+ */
+ @Override
+ public void set(String key, Object value, long cacheTime) {
+ RedisUtils.setCacheObject(GlobalConstants.GLOBAL_REDIS_KEY + key, value, Duration.ofSeconds(cacheTime));
+ }
+
+ /**
+ * 存储
+ *
+ * @param key 键
+ * @param value 值
+ */
+ @Override
+ public void set(String key, Object value) {
+ RedisUtils.setCacheObject(GlobalConstants.GLOBAL_REDIS_KEY + key, value, true);
+ }
+
+ /**
+ * 读取
+ *
+ * @param key 键
+ * @return 值
+ */
+ @Override
+ public Object get(String key) {
+ return RedisUtils.getCacheObject(GlobalConstants.GLOBAL_REDIS_KEY + key);
+ }
+
+ /**
+ * remove
+ *
根据key移除缓存
+ *
+ * @param key 缓存键
+ * @return 被删除的value
+ * @author :Wind
+ */
+ @Override
+ public Object remove(String key) {
+ return RedisUtils.deleteObject(GlobalConstants.GLOBAL_REDIS_KEY + key);
+ }
+
+ /**
+ * 清空
+ */
+ @Override
+ public void clean() {
+ RedisUtils.deleteObject(GlobalConstants.GLOBAL_REDIS_KEY + "sms:");
+ }
+
+}
diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialProperties.java b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialProperties.java
index 1beb7d042..1487a6a92 100644
--- a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialProperties.java
+++ b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialProperties.java
@@ -16,11 +16,6 @@ import java.util.Map;
@ConfigurationProperties(prefix = "justauth")
public class SocialProperties {
- /**
- * 是否启用
- */
- private Boolean enabled;
-
/**
* 授权类型
*/
diff --git a/ruoyi-common/ruoyi-common-tenant/pom.xml b/ruoyi-common/ruoyi-common-tenant/pom.xml
index f94340a91..8e1a6ab1e 100644
--- a/ruoyi-common/ruoyi-common-tenant/pom.xml
+++ b/ruoyi-common/ruoyi-common-tenant/pom.xml
@@ -19,6 +19,7 @@
org.dromara
ruoyi-common-mybatis
+ true
diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java
index 282f1bf40..0f7892861 100644
--- a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java
+++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java
@@ -2,9 +2,11 @@ package org.dromara.common.web.config;
import io.undertow.server.DefaultByteBufferPool;
import io.undertow.websockets.jsr.WebSocketDeploymentInfo;
+import org.dromara.common.core.utils.SpringUtils;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
+import org.springframework.core.task.VirtualThreadTaskExecutor;
/**
* Undertow 自定义配置
@@ -24,10 +26,12 @@ public class UndertowConfig implements WebServerFactoryCustomizer sendAliyun(String phones, String templateId) {
LinkedHashMap map = new LinkedHashMap<>(1);
map.put("code", "1234");
- SmsBlend smsBlend = SmsFactory.createSmsBlend(SupplierType.ALIBABA);
+ SmsBlend smsBlend = SmsFactory.getSmsBlend("config1");
SmsResponse smsResponse = smsBlend.sendMessage(phones, templateId, map);
return R.ok(smsResponse);
}
@@ -52,9 +50,33 @@ public class SmsController {
LinkedHashMap map = new LinkedHashMap<>(1);
// map.put("2", "测试测试");
map.put("1", "1234");
- SmsBlend smsBlend = SmsFactory.createSmsBlend(SupplierType.TENCENT);
+ SmsBlend smsBlend = SmsFactory.getSmsBlend("config2");
SmsResponse smsResponse = smsBlend.sendMessage(phones, templateId, map);
return R.ok(smsResponse);
}
+ /**
+ * 添加黑名单
+ *
+ * @param phone 手机号
+ */
+ @GetMapping("/addBlacklist")
+ public R