剥离redis依赖

This commit is contained in:
D 2024-04-24 14:22:15 +08:00
parent 1c768d6607
commit b48206dc80
22 changed files with 302 additions and 201 deletions

View File

@ -17,7 +17,7 @@
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>17</java.version> <java.version>17</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version> <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<spring-boot.version>3.2.4</spring-boot.version> <spring-boot.version>3.2.5</spring-boot.version>
<druid.version>1.2.21</druid.version> <druid.version>1.2.21</druid.version>
<shardingsphere.version>4.1.1</shardingsphere.version> <shardingsphere.version>4.1.1</shardingsphere.version>
<dynamic.version>3.5.2</dynamic.version> <dynamic.version>3.5.2</dynamic.version>

View File

@ -71,7 +71,7 @@
<artifactId>ruoyi-mybatis-jpa</artifactId> <artifactId>ruoyi-mybatis-jpa</artifactId>
</dependency> </dependency>
<!-- minio --> <!-- 中间件 -->
<dependency> <dependency>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-middleware-starter</artifactId> <artifactId>ruoyi-middleware-starter</artifactId>

View File

@ -1,15 +1,10 @@
package com.ruoyi.web.controller.monitor; package com.ruoyi.web.controller.monitor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set; import java.util.Set;
import org.springframework.cache.Cache.ValueWrapper; import org.springframework.cache.Cache.ValueWrapper;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
@ -52,32 +47,6 @@ public class CacheController
caches.add(new SysCache(CacheConstants.PWD_ERR_CNT_KEY, "密码错误次数")); caches.add(new SysCache(CacheConstants.PWD_ERR_CNT_KEY, "密码错误次数"));
} }
@Operation(summary = "获取缓存信息")
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@GetMapping()
public AjaxResult getInfo() throws Exception
{
Map<String, Object> result = new HashMap<>(3);
if (CacheUtils.getCacheManager() instanceof RedisCacheManager)
{
Properties info = (Properties) CacheUtils.getRedisTemplate().execute((RedisCallback<Object>) connection -> connection.info());
Properties commandStats = (Properties) CacheUtils.getRedisTemplate().execute((RedisCallback<Object>) connection -> connection.info("commandstats"));
Object dbSize = CacheUtils.getRedisTemplate().execute((RedisCallback<Object>) connection -> connection.dbSize());
result.put("info", info);
result.put("dbSize", dbSize);
List<Map<String, String>> pieList = new ArrayList<>();
commandStats.stringPropertyNames().forEach(key -> {
Map<String, String> data = new HashMap<>(2);
String property = commandStats.getProperty(key);
data.put("name", StringUtils.removeStart(key, "cmdstat_"));
data.put("value", StringUtils.substringBetween(property, "calls=", ",usec"));
pieList.add(data);
});
result.put("commandStats", pieList);
}
return AjaxResult.success(result);
}
@Operation(summary = "获取缓存名列表") @Operation(summary = "获取缓存名列表")
@PreAuthorize("@ss.hasPermi('monitor:cache:list')") @PreAuthorize("@ss.hasPermi('monitor:cache:list')")

View File

@ -0,0 +1,31 @@
spring:
data:
# redis 配置
redis:
# 地址
host: localhost
# 端口默认为6379
port: 6379
# 数据库索引
database: 0
# 密码
password:
# 连接超时时间
timeout: 10s
lettuce:
pool:
# 连接池中的最小空闲连接
min-idle: 0
# 连接池中的最大空闲连接
max-idle: 8
# 连接池的最大数据库连接数
max-active: 8
# #连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
# Minio配置
minio:
url: http://localhost:9000
accessKey: minioadmin
secretKey: minioadmin
bucketName: ruoyi

View File

@ -1,6 +0,0 @@
# Minio配置
minio:
url: http://localhost:9000
accessKey: minioadmin
secretKey: minioadmin
bucketName: ruoyi

View File

@ -49,7 +49,7 @@ user:
spring: spring:
cache: cache:
# 指定缓存类型 jcache 本地缓存 redis 缓存 # 指定缓存类型 jcache 本地缓存 redis 缓存
type: jcache type: redis
redis: redis:
# 指定存活时间ms # 指定存活时间ms
time-to-live: 86400000 time-to-live: 86400000
@ -65,7 +65,7 @@ spring:
# 国际化资源文件路径 # 国际化资源文件路径
basename: i18n/messages basename: i18n/messages
profiles: profiles:
active: druid,mybatis,oauth,pay,minio active: druid,mybatis,oauth,pay,middleware
# 文件上传 # 文件上传
servlet: servlet:
multipart: multipart:
@ -78,29 +78,6 @@ spring:
restart: restart:
# 热部署开关 # 热部署开关
enabled: true enabled: true
data:
# redis 配置
redis:
# 地址
host: localhost
# 端口默认为6379
port: 6379
# 数据库索引
database: 0
# 密码
password:
# 连接超时时间
timeout: 10s
lettuce:
pool:
# 连接池中的最小空闲连接
min-idle: 0
# 连接池中的最大空闲连接
max-idle: 8
# 连接池的最大数据库连接数
max-active: 8
# #连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
# token配置 # token配置
token: token:

View File

@ -111,12 +111,6 @@
<version>2.3.0.1</version> <version>2.3.0.1</version>
</dependency> </dependency>
<!-- redis 缓存操作 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- pool 对象池 --> <!-- pool 对象池 -->
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>

View File

@ -0,0 +1,14 @@
package com.ruoyi.common.core.cache;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.springframework.cache.Cache;
public interface CacheSpecialUtils {
public Set<String> getKeys(Cache cache);
default public <T> void set(String string, T value, long timeout, TimeUnit unit){}
default public <T> void set(String string, T value){};
}

View File

@ -1,34 +1,19 @@
package com.ruoyi.common.utils; package com.ruoyi.common.utils;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.ehcache.core.EhcacheBase;
import org.ehcache.impl.internal.concurrent.ConcurrentHashMap;
import org.ehcache.impl.internal.store.heap.OnHeapStore;
import org.springframework.cache.Cache; import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager; import org.springframework.cache.CacheManager;
import org.springframework.cache.jcache.JCacheCache; import org.springframework.cache.jcache.JCacheCache;
import org.springframework.cache.transaction.TransactionAwareCacheDecorator; import org.springframework.cache.transaction.TransactionAwareCacheDecorator;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
import com.ruoyi.common.core.cache.CacheSpecialUtils;
import com.ruoyi.common.utils.spring.SpringUtils; import com.ruoyi.common.utils.spring.SpringUtils;
public class CacheUtils { public class CacheUtils {
/**
* 使用redis时对redis进行单独特殊操作需要使用
*
* @param <K>
* @param <V>
* @return
*/
public static <K, V> RedisTemplate<K, V> getRedisTemplate() {
return SpringUtils.getBean("redisTemplate");
}
/** /**
* 获取CacheManager * 获取CacheManager
@ -58,38 +43,8 @@ public class CacheUtils {
@SuppressWarnings(value = { "unchecked", "rawtypes" }) @SuppressWarnings(value = { "unchecked", "rawtypes" })
public static Set<String> getkeys(String cacheName) { public static Set<String> getkeys(String cacheName) {
Cache cache = getCacheManager().getCache(cacheName); Cache cache = getCacheManager().getCache(cacheName);
Set<String> keyset = new HashSet<>(); CacheSpecialUtils cacheGetKets = SpringUtils.getBean(CacheSpecialUtils.class);
if (cache instanceof JCacheCache) { return cacheGetKets.getKeys(cache);
try {
JCacheCache jehcache = (JCacheCache) cache;
// org.ehcache.jsr107.Eh107Cache 不公开
Object nativeCache = jehcache.getNativeCache();
Class<?> nativeCacheClass = nativeCache.getClass();
Field ehCacheField = nativeCacheClass.getDeclaredField("ehCache");
ehCacheField.setAccessible(true);
EhcacheBase ehcache = (EhcacheBase) ehCacheField.get(nativeCache);
Field storeField = EhcacheBase.class.getDeclaredField("store");
storeField.setAccessible(true);
OnHeapStore store = (OnHeapStore) storeField.get(ehcache);
Field mapField = OnHeapStore.class.getDeclaredField("map");
mapField.setAccessible(true);
// org.ehcache.impl.internal.store.heap.Backend 不公开
Object map = mapField.get(store);
Class<?> mapClass = map.getClass();
Field realMapField = mapClass.getDeclaredField("realMap");
realMapField.setAccessible(true);
ConcurrentHashMap<String, ?> realMap = (ConcurrentHashMap<String, ?>) realMapField.get(map);
keyset = realMap.keySet();
} catch (Exception e) {
}
} else if (cache instanceof TransactionAwareCacheDecorator) {
Set<Object> keysets = getRedisTemplate().keys(cache.getName() + "*");
for (Object s : keysets) {
keyset.add(StringUtils.replace(s.toString(), cache.getName() + ":", ""));
}
}
return keyset;
} }
/** /**
@ -118,6 +73,10 @@ public class CacheUtils {
} }
} }
public static boolean hasKey(String cacheName, String key){
return ObjectUtils.isEmpty(get(cacheName, key));
}
/** /**
* 根据cacheName,key和缓存过期时间进行缓存数据,使用各种不同缓存可以单独进行操作 * 根据cacheName,key和缓存过期时间进行缓存数据,使用各种不同缓存可以单独进行操作
* *
@ -134,10 +93,11 @@ public class CacheUtils {
JCacheCache ehcache = (JCacheCache) cache; JCacheCache ehcache = (JCacheCache) cache;
ehcache.put(key, value); ehcache.put(key, value);
} else if (cache instanceof TransactionAwareCacheDecorator) { } else if (cache instanceof TransactionAwareCacheDecorator) {
CacheSpecialUtils cacheSet = SpringUtils.getBean(CacheSpecialUtils.class);
if (timeout != 0 && unit != null) { if (timeout != 0 && unit != null) {
getRedisTemplate().opsForValue().set(cacheName + ":" + key, value, timeout, unit); cacheSet.set(cacheName + ":" + key, value, timeout, unit);
} else { } else {
getRedisTemplate().opsForValue().set(cacheName + ":" + key, value); cacheSet.set(cacheName + ":" + key, value);
} }
} else { } else {
cache.put(key, value); cache.put(key, value);

View File

@ -1,5 +1,8 @@
package com.ruoyi.framework.config; package com.ruoyi.framework.config;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.cache.CacheManager; import javax.cache.CacheManager;
@ -8,19 +11,61 @@ import javax.cache.configuration.MutableConfiguration;
import javax.cache.expiry.CreatedExpiryPolicy; import javax.cache.expiry.CreatedExpiryPolicy;
import javax.cache.expiry.Duration; import javax.cache.expiry.Duration;
import org.ehcache.core.EhcacheBase;
import org.ehcache.impl.internal.concurrent.ConcurrentHashMap;
import org.ehcache.impl.internal.store.heap.OnHeapStore;
import org.ehcache.jsr107.EhcacheCachingProvider; import org.ehcache.jsr107.EhcacheCachingProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.Cache;
import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.jcache.JCacheCache;
import org.springframework.cache.jcache.JCacheCacheManager;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import com.ruoyi.common.core.cache.CacheSpecialUtils;
@Configuration @Configuration
@EnableCaching @EnableCaching
@ConditionalOnProperty(prefix = "spring.cache", name = { "type" }, havingValue = "jcache", matchIfMissing = false) @ConditionalOnProperty(prefix = "spring.cache", name = { "type" }, havingValue = "jcache", matchIfMissing = false)
public class Ehcache3Config { public class Ehcache3Config {
@Bean @Bean
public CacheManager ehcacheManager() { @SuppressWarnings(value = { "unchecked", "rawtypes" })
public CacheSpecialUtils cacheGetKets() {
return new CacheSpecialUtils() {
@Override
public Set<String> getKeys(Cache cache) {
Set<String> keyset = new HashSet<>();
try {
JCacheCache jehcache = (JCacheCache) cache;
// org.ehcache.jsr107.Eh107Cache 不公开
Object nativeCache = jehcache.getNativeCache();
Class<?> nativeCacheClass = nativeCache.getClass();
Field ehCacheField = nativeCacheClass.getDeclaredField("ehCache");
ehCacheField.setAccessible(true);
EhcacheBase ehcache = (EhcacheBase) ehCacheField.get(nativeCache);
Field storeField = EhcacheBase.class.getDeclaredField("store");
storeField.setAccessible(true);
OnHeapStore store = (OnHeapStore) storeField.get(ehcache);
Field mapField = OnHeapStore.class.getDeclaredField("map");
mapField.setAccessible(true);
// org.ehcache.impl.internal.store.heap.Backend 不公开
Object map = mapField.get(store);
Class<?> mapClass = map.getClass();
Field realMapField = mapClass.getDeclaredField("realMap");
realMapField.setAccessible(true);
ConcurrentHashMap<String, ?> realMap = (ConcurrentHashMap<String, ?>) realMapField.get(map);
keyset = realMap.keySet();
} catch (Exception e) {
}
return keyset;
}
};
}
@Bean
public JCacheCacheManager ehcacheManager() {
EhcacheCachingProvider cachingProvider = (EhcacheCachingProvider) Caching.getCachingProvider(); EhcacheCachingProvider cachingProvider = (EhcacheCachingProvider) Caching.getCachingProvider();
CacheManager cacheManager = (CacheManager) cachingProvider.getCacheManager(); CacheManager cacheManager = (CacheManager) cachingProvider.getCacheManager();
@ -30,7 +75,7 @@ public class Ehcache3Config {
mutableConfiguration.setManagementEnabled(true); // 启用管理功能可选 mutableConfiguration.setManagementEnabled(true); // 启用管理功能可选
mutableConfiguration.setStatisticsEnabled(true); // 启用统计功能可选 mutableConfiguration.setStatisticsEnabled(true); // 启用统计功能可选
// 设置缓存过期策略 timeToIdle 为例根据实际需求调整 // 设置缓存过期策略 timeToIdle 为例根据实际需求调整
mutableConfiguration.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(new Duration(TimeUnit.HOURS,1))); mutableConfiguration.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(new Duration(TimeUnit.HOURS, 1)));
cacheManager.createCache("temp_cache", mutableConfiguration); cacheManager.createCache("temp_cache", mutableConfiguration);
cacheManager.createCache("eternal_cache", mutableConfiguration); cacheManager.createCache("eternal_cache", mutableConfiguration);
@ -42,7 +87,9 @@ public class Ehcache3Config {
cacheManager.createCache("rate_limit", mutableConfiguration); cacheManager.createCache("rate_limit", mutableConfiguration);
cacheManager.createCache("pwd_err_cnt", mutableConfiguration); cacheManager.createCache("pwd_err_cnt", mutableConfiguration);
return cacheManager; JCacheCacheManager jCacheCacheManager = new JCacheCacheManager(cacheManager);
return jCacheCacheManager;
} }
} }

View File

@ -13,6 +13,7 @@
<properties> <properties>
<ruoyi.version>3.8.7.3.2</ruoyi.version> <ruoyi.version>3.8.7.3.2</ruoyi.version>
<minio.version>8.2.1</minio.version> <minio.version>8.2.1</minio.version>
<spring-boot.version>3.2.5</spring-boot.version>
</properties> </properties>
<description> <description>
@ -20,13 +21,6 @@
</description> </description>
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<!-- 通用工具-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>${ruoyi.version}</version>
</dependency>
<!-- Minio 文件存储 --> <!-- Minio 文件存储 -->
<dependency> <dependency>
<groupId>io.minio</groupId> <groupId>io.minio</groupId>
@ -40,6 +34,12 @@
<version>${ruoyi.version}</version> <version>${ruoyi.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-middleware-redis</artifactId>
<version>${ruoyi.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-middleware-starter</artifactId> <artifactId>ruoyi-middleware-starter</artifactId>
@ -51,6 +51,7 @@
<modules> <modules>
<module>ruoyi-middleware-minio</module> <module>ruoyi-middleware-minio</module>
<module>ruoyi-middleware-redis</module>
<module>ruoyi-middleware-starter</module> <module>ruoyi-middleware-starter</module>
</modules> </modules>
<packaging>pom</packaging> <packaging>pom</packaging>

View File

@ -10,7 +10,6 @@ import com.ruoyi.common.exception.file.InvalidExtensionException;
import com.ruoyi.common.utils.file.FileUploadUtils; import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.utils.file.MimeTypeUtils; import com.ruoyi.common.utils.file.MimeTypeUtils;
import com.ruoyi.middleware.minio.config.MinioConfig; import com.ruoyi.middleware.minio.config.MinioConfig;
import com.ruoyi.middleware.minio.utils.MinioUtil;
public class FileUploadMinioUtils extends FileUploadUtils { public class FileUploadMinioUtils extends FileUploadUtils {
/** /**

View File

@ -0,0 +1,33 @@
<?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>ruoyi-middleware</artifactId>
<groupId>com.ruoyi</groupId>
<version>3.8.7.3.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-middleware-redis</artifactId>
<description>
中间件
</description>
<dependencies>
<!-- 通用工具-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
</dependency>
<!-- redis 缓存操作 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,4 +1,4 @@
package com.ruoyi.framework.aspectj; package com.ruoyi.middleware.redis.aspectj;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Collections; import java.util.Collections;

View File

@ -1,4 +1,4 @@
package com.ruoyi.framework.config; package com.ruoyi.middleware.redis.config;
import java.nio.charset.Charset; import java.nio.charset.Charset;

View File

@ -1,8 +1,12 @@
package com.ruoyi.framework.config; package com.ruoyi.middleware.redis.config;
import java.time.Duration; import java.time.Duration;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager; import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurer; import org.springframework.cache.annotation.CachingConfigurer;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@ -16,6 +20,9 @@ import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer;
import com.ruoyi.common.core.cache.CacheSpecialUtils;
import com.ruoyi.common.utils.StringUtils;
/** /**
* redis配置 * redis配置
* *
@ -23,37 +30,58 @@ import org.springframework.data.redis.serializer.StringRedisSerializer;
*/ */
@Configuration @Configuration
@ConditionalOnProperty(prefix = "spring.cache", name = { "type" }, havingValue = "redis", matchIfMissing = false) @ConditionalOnProperty(prefix = "spring.cache", name = { "type" }, havingValue = "redis", matchIfMissing = false)
public class RedisConfig implements CachingConfigurer public class RedisConfig implements CachingConfigurer {
{
@Bean @Bean
@Primary @Primary
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
{
RedisCacheConfiguration config = instanceConfig(3600 * 24 * 15L); RedisCacheConfiguration config = instanceConfig(3600 * 24 * 15L);
return RedisCacheManager.builder(connectionFactory).cacheDefaults(config).transactionAware().build(); return RedisCacheManager.builder(connectionFactory).cacheDefaults(config).transactionAware().build();
} }
@Bean @Bean
public CacheManager cacheManager30m(RedisConnectionFactory connectionFactory) public CacheManager cacheManager30m(RedisConnectionFactory connectionFactory) {
{
RedisCacheConfiguration config = instanceConfig(1800L); RedisCacheConfiguration config = instanceConfig(1800L);
return RedisCacheManager.builder(connectionFactory).cacheDefaults(config).transactionAware().build(); return RedisCacheManager.builder(connectionFactory).cacheDefaults(config).transactionAware().build();
} }
@Bean
public CacheSpecialUtils cacheGetKets(RedisTemplate<Object, Object> redisTemplate) {
return new CacheSpecialUtils() {
@Override
public Set<String> getKeys(Cache cache) {
Set<String> keyset = new HashSet<>();
Set<Object> keysets = redisTemplate.keys(cache.getName() + "*");
for (Object s : keysets) {
keyset.add(StringUtils.replace(s.toString(), cache.getName() + ":", ""));
}
return keyset;
}
@Override
public <T> void set(String cacheName, T value, long timeout, TimeUnit unit){
redisTemplate.opsForValue().set(cacheName, value, timeout, unit);
}
public <T> void set(String cacheName, T value){
redisTemplate.opsForValue().set(cacheName, value);
};
};
}
@SuppressWarnings(value = { "unchecked", "rawtypes" }) @SuppressWarnings(value = { "unchecked", "rawtypes" })
private RedisCacheConfiguration instanceConfig(Long ttl) private RedisCacheConfiguration instanceConfig(Long ttl) {
{
FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class); FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);
return RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(ttl)).disableCachingNullValues() return RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(ttl)).disableCachingNullValues()
.computePrefixWith(name -> name + ":") .computePrefixWith(name -> name + ":")
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) .serializeKeysWith(
RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer)); .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer));
} }
@Bean @Bean
@SuppressWarnings(value = { "unchecked", "rawtypes" }) @SuppressWarnings(value = { "unchecked", "rawtypes" })
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
{
RedisTemplate<Object, Object> template = new RedisTemplate<>(); RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory); template.setConnectionFactory(connectionFactory);
@ -72,8 +100,7 @@ public class RedisConfig implements CachingConfigurer
} }
@Bean @Bean
public DefaultRedisScript<Long> limitScript() public DefaultRedisScript<Long> limitScript() {
{
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(); DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
redisScript.setScriptText(limitScriptText()); redisScript.setScriptText(limitScriptText());
redisScript.setResultType(Long.class); redisScript.setResultType(Long.class);
@ -83,8 +110,7 @@ public class RedisConfig implements CachingConfigurer
/** /**
* 限流脚本 * 限流脚本
*/ */
private String limitScriptText() private String limitScriptText() {
{
return "local key = KEYS[1]\n" + return "local key = KEYS[1]\n" +
"local count = tonumber(ARGV[1])\n" + "local count = tonumber(ARGV[1])\n" +
"local time = tonumber(ARGV[2])\n" + "local time = tonumber(ARGV[2])\n" +

View File

@ -0,0 +1,64 @@
package com.ruoyi.middleware.redis.controller;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.StringUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
/**
* 缓存监控
*
* @author ruoyi
*/
@Tag(name = "缓存监控")
@RestController
@SuppressWarnings(value = { "unchecked", "rawtypes" })
@ConditionalOnProperty(prefix = "spring.cache", name = { "type" }, havingValue = "redis", matchIfMissing = false)
@RequestMapping("/monitor/cache")
public class RedisCacheController {
@Autowired
private RedisTemplate redisTemplate;
@Operation(summary = "获取缓存信息")
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@GetMapping()
public AjaxResult getInfo() throws Exception {
Map<String, Object> result = new HashMap<>(3);
Properties info = (Properties) redisTemplate
.execute((RedisCallback<Object>) connection -> connection.commands().info());
Properties commandStats = (Properties) redisTemplate
.execute((RedisCallback<Object>) connection -> connection.commands().info("commandstats"));
Object dbSize = redisTemplate.execute((RedisCallback<Object>) connection -> connection.commands().dbSize());
result.put("info", info);
result.put("dbSize", dbSize);
List<Map<String, String>> pieList = new ArrayList<>();
commandStats.stringPropertyNames().forEach(key -> {
Map<String, String> data = new HashMap<>(2);
String property = commandStats.getProperty(key);
data.put("name", StringUtils.removeStart(key, "cmdstat_"));
data.put("value", StringUtils.substringBetween(property, "calls=", ",usec"));
pieList.add(data);
});
result.put("commandStats", pieList);
return AjaxResult.success(result);
}
}

View File

@ -1,4 +1,4 @@
package com.ruoyi.common.core.redis; package com.ruoyi.middleware.redis.utils;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
@ -6,7 +6,9 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.redis.core.BoundSetOperations; import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
@ -20,6 +22,7 @@ import org.springframework.stereotype.Component;
**/ **/
@SuppressWarnings(value = { "unchecked", "rawtypes" }) @SuppressWarnings(value = { "unchecked", "rawtypes" })
@Component @Component
@ConditionalOnProperty(prefix = "spring.cache", name = { "type" }, havingValue = "redis", matchIfMissing = false)
public class RedisCache public class RedisCache
{ {
@Autowired @Autowired

View File

@ -27,6 +27,11 @@
<artifactId>ruoyi-middleware-minio</artifactId> <artifactId>ruoyi-middleware-minio</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-middleware-redis</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -20,14 +20,6 @@
</description> </description>
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<!-- 核心模块-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-framework</artifactId>
<version>${ruoyi.version}</version>
</dependency>
<!-- 第三方认证通用工具--> <!-- 第三方认证通用工具-->
<dependency> <dependency>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>

View File

@ -11,8 +11,8 @@ import org.springframework.stereotype.Service;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.CacheUtils;
import com.ruoyi.framework.web.service.TokenService; import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.framework.web.service.UserDetailsServiceImpl; import com.ruoyi.framework.web.service.UserDetailsServiceImpl;
import com.ruoyi.oauth.common.enums.OauthVerificationUse; import com.ruoyi.oauth.common.enums.OauthVerificationUse;
@ -34,32 +34,32 @@ public class DySmsServiceImpl implements DySmsService, OauthVerificationCodeServ
@Autowired @Autowired
private DySmsUtil dySmsUtil; private DySmsUtil dySmsUtil;
@Autowired @Autowired
private RedisCache redisCache;
@Autowired
private ISysUserService userService; private ISysUserService userService;
@Autowired @Autowired
private UserDetailsServiceImpl userDetailsServiceImpl; private UserDetailsServiceImpl userDetailsServiceImpl;
@Autowired @Autowired
private TokenService tokenService; private TokenService tokenService;
private static final String CACHE_NAME = "phone_codes";
private static final Logger log = LoggerFactory.getLogger(DySmsServiceImpl.class); private static final Logger log = LoggerFactory.getLogger(DySmsServiceImpl.class);
public boolean beforeSendCode(String phone, OauthVerificationUse use) throws Exception {// 1.查验手机号是否存在分辨登录和删除用户以及注册用户
public boolean beforeSendCode(String phone, OauthVerificationUse use) throws Exception {//1.查验手机号是否存在分辨登录和删除用户以及注册用户 boolean havePhoneFlag = userService.selectUserByPhone(phone) != null;
boolean havePhoneFlag= userService.selectUserByPhone(phone) != null; if ((use.equals(OauthVerificationUse.LOGIN) || use.equals(OauthVerificationUse.DISABLE)
if((use.equals(OauthVerificationUse.LOGIN ) || use.equals(OauthVerificationUse.DISABLE )||use.equals(OauthVerificationUse.RESET_PASSWORD) )&& !havePhoneFlag){ || use.equals(OauthVerificationUse.RESET_PASSWORD)) && !havePhoneFlag) {
throw new ServiceException("该手机号未绑定用户"); throw new ServiceException("该手机号未绑定用户");
}else if((use.equals(OauthVerificationUse.REGISTER ) ||use.equals(OauthVerificationUse.RESET_PHONE))&& havePhoneFlag){ } else if ((use.equals(OauthVerificationUse.REGISTER) || use.equals(OauthVerificationUse.RESET_PHONE))
&& havePhoneFlag) {
throw new ServiceException("该手机号已绑定用户"); throw new ServiceException("该手机号已绑定用户");
} }
return true; return true;
} }
@Override @Override
public boolean sendCode(String phone, String code, OauthVerificationUse use) throws Exception {//1.查验手机号是否存在分辨登录和删除用户以及注册用户 public boolean sendCode(String phone, String code, OauthVerificationUse use) throws Exception {// 1.查验手机号是否存在分辨登录和删除用户以及注册用户
//限制短信一分钟只能发送一次短信 // 限制短信一分钟只能发送一次短信
String cacheKey = "phone_codes_" + use.getValue() + "_" + phone; if (CacheUtils.hasKey(CACHE_NAME, phone + use.getValue())) {
if(redisCache.hasKey(cacheKey)){
throw new ServiceException("请在1分钟后再发送短信"); throw new ServiceException("请在1分钟后再发送短信");
} }
@ -67,7 +67,7 @@ public class DySmsServiceImpl implements DySmsService, OauthVerificationCodeServ
JSONObject templateParams = new JSONObject(); JSONObject templateParams = new JSONObject();
templateParams.put("code", code); templateParams.put("code", code);
dySmsUtil.sendSms(DySmsTemplate.Test_TEMPLATE_CODE, templateParams, phone); dySmsUtil.sendSms(DySmsTemplate.Test_TEMPLATE_CODE, templateParams, phone);
redisCache.setCacheObject("phone_codes_" + use.getValue() + "_" + phone, code, 1, TimeUnit.MINUTES); CacheUtils.put(CACHE_NAME, phone + use.getValue(), code, 1, TimeUnit.MINUTES);
log.info("发送手机验证码成功:{ phone: " + phone + " code:" + code + "}"); log.info("发送手机验证码成功:{ phone: " + phone + " code:" + code + "}");
return true; return true;
} catch (Exception e) { } catch (Exception e) {
@ -76,40 +76,38 @@ public class DySmsServiceImpl implements DySmsService, OauthVerificationCodeServ
} }
} }
@Override @Override
public String checkCode(String phone, String code, OauthVerificationUse use) throws Exception{ public String checkCode(String phone, String code, OauthVerificationUse use) throws Exception {
String cacheKey = "phone_codes_" + use.getValue() + "_" + phone; String cachedCode = CacheUtils.get(use.getValue(), use.getValue() + phone, String.class); // 从缓存中获取验证码
String cachedCode = redisCache.getCacheObject(cacheKey); // 从缓存中获取验证码 boolean havePhoneFlag = userService.selectUserByPhone(phone) != null;
boolean havePhoneFlag= userService.selectUserByPhone(phone) != null; if (use.equals(OauthVerificationUse.LOGIN) && havePhoneFlag) {// 登录校验
if(use.equals(OauthVerificationUse.LOGIN ) && havePhoneFlag){//登录校验
if (code.equals(cachedCode)) { if (code.equals(cachedCode)) {
SysUser sysUser = userService.selectUserByPhone(phone); SysUser sysUser = userService.selectUserByPhone(phone);
LoginUser loginUser = (LoginUser) userDetailsServiceImpl.createLoginUser(sysUser); LoginUser loginUser = (LoginUser) userDetailsServiceImpl.createLoginUser(sysUser);
return tokenService.createToken(loginUser); return tokenService.createToken(loginUser);
// return true; // return true;
} else { } else {
throw new ServiceException("验证码错误"); throw new ServiceException("验证码错误");
} }
}else if(use.equals(OauthVerificationUse.REGISTER )&& !havePhoneFlag){//注册校验 } else if (use.equals(OauthVerificationUse.REGISTER) && !havePhoneFlag) {// 注册校验
if (code.equals(cachedCode)) { if (code.equals(cachedCode)) {
return Boolean.toString(true); return Boolean.toString(true);
} else { } else {
throw new ServiceException("验证码错误"); throw new ServiceException("验证码错误");
} }
}else if(use.equals(OauthVerificationUse.DISABLE )&& havePhoneFlag){//注销校验 } else if (use.equals(OauthVerificationUse.DISABLE) && havePhoneFlag) {// 注销校验
if (code.equals(cachedCode)) { if (code.equals(cachedCode)) {
return Boolean.toString(true); return Boolean.toString(true);
} else { } else {
throw new ServiceException("验证码错误"); throw new ServiceException("验证码错误");
} }
}else if(use.equals(OauthVerificationUse.RESET_PASSWORD )&& havePhoneFlag){//重置密码校验 } else if (use.equals(OauthVerificationUse.RESET_PASSWORD) && havePhoneFlag) {// 重置密码校验
if (code.equals(cachedCode)) { if (code.equals(cachedCode)) {
return Boolean.toString(true); return Boolean.toString(true);
} else { } else {
throw new ServiceException("验证码错误"); throw new ServiceException("验证码错误");
} }
}else if(use.equals(OauthVerificationUse.RESET_PHONE )&& !havePhoneFlag){//重置账号校验 } else if (use.equals(OauthVerificationUse.RESET_PHONE) && !havePhoneFlag) {// 重置账号校验
if (code.equals(cachedCode)) { if (code.equals(cachedCode)) {
return Boolean.toString(true); return Boolean.toString(true);
} else { } else {
@ -134,7 +132,7 @@ public class DySmsServiceImpl implements DySmsService, OauthVerificationCodeServ
@Override @Override
public String doLogin(String phone) { public String doLogin(String phone) {
String verify = redisCache.getCacheObject("phone_codes_login" + phone); String verify = CacheUtils.get(CACHE_NAME, phone + OauthVerificationUse.LOGIN, String.class);
if (verify != null) { if (verify != null) {
throw new ServiceException("该手机号验证码未过期"); throw new ServiceException("该手机号验证码未过期");
} }
@ -147,7 +145,8 @@ public class DySmsServiceImpl implements DySmsService, OauthVerificationCodeServ
JSONObject templateParams = new JSONObject(); JSONObject templateParams = new JSONObject();
templateParams.put("code", code); templateParams.put("code", code);
dySmsUtil.sendSms(DySmsTemplate.Test_TEMPLATE_CODE, templateParams, phone); dySmsUtil.sendSms(DySmsTemplate.Test_TEMPLATE_CODE, templateParams, phone);
redisCache.setCacheObject("phone_codes_login" + phone, code, 1, TimeUnit.MINUTES); CacheUtils.put(CACHE_NAME, phone + OauthVerificationUse.LOGIN, code, 1,
TimeUnit.MINUTES);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -155,7 +154,7 @@ public class DySmsServiceImpl implements DySmsService, OauthVerificationCodeServ
} }
public String doLoginVerify(String phone, String code) { public String doLoginVerify(String phone, String code) {
String verify = redisCache.getCacheObject("phone_codes_login" + phone); String verify = CacheUtils.get(CACHE_NAME, phone + OauthVerificationUse.LOGIN, String.class);
if (code.equals(verify)) { if (code.equals(verify)) {
SysUser sysUser = userService.selectUserByPhone(phone); SysUser sysUser = userService.selectUserByPhone(phone);
LoginUser loginUser = (LoginUser) userDetailsServiceImpl.createLoginUser(sysUser); LoginUser loginUser = (LoginUser) userDetailsServiceImpl.createLoginUser(sysUser);
@ -167,14 +166,14 @@ public class DySmsServiceImpl implements DySmsService, OauthVerificationCodeServ
public String doRegister(String phone) { public String doRegister(String phone) {
String code = generateRandomString(6); String code = generateRandomString(6);
redisCache.setCacheObject("phone_codes_register" + phone, code, 1, TimeUnit.MINUTES); CacheUtils.put(CACHE_NAME, phone + OauthVerificationUse.REGISTER, code, 1, TimeUnit.MINUTES);
String verify = redisCache.getCacheObject("phone_codes_register" + phone); String verify = CacheUtils.get("phone_codes_register", phone, String.class);
if (verify != null) { if (verify != null) {
throw new ServiceException("该手机号验证码未过期"); throw new ServiceException("该手机号验证码未过期");
} else { } else {
try { try {
dySmsUtil.sendSms(null, null, phone); dySmsUtil.sendSms(null, null, phone);
redisCache.setCacheObject("phone_codes_register" + phone, code, 1, TimeUnit.MINUTES); CacheUtils.put(CACHE_NAME, phone + OauthVerificationUse.REGISTER, code, 1, TimeUnit.MINUTES);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }

View File

@ -20,13 +20,6 @@
</description> </description>
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<!-- 通用工具-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>${ruoyi.version}</version>
</dependency>
<!-- 支付基础模块 --> <!-- 支付基础模块 -->
<dependency> <dependency>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>