diff --git a/pom.xml b/pom.xml index 6d52bf68b..6cbda80bb 100644 --- a/pom.xml +++ b/pom.xml @@ -31,6 +31,7 @@ 2.2.6.RELEASE 11.0 2.3.1 + 3.15.2 @@ -180,6 +181,13 @@ ${ruoyi-vue-plus.version} + + + org.redisson + redisson-spring-boot-starter + ${redisson.version} + + diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml index 06456dd8d..71e5b6f4f 100644 --- a/ruoyi-admin/src/main/resources/application-dev.yml +++ b/ruoyi-admin/src/main/resources/application-dev.yml @@ -67,13 +67,38 @@ spring: password: # 连接超时时间 timeout: 10s - lettuce: - pool: - # 连接池中的最小空闲连接 - min-idle: 0 - # 连接池中的最大空闲连接 - max-idle: 8 - # 连接池的最大数据库连接数 - max-active: 8 - # #连接池最大阻塞等待时间(使用负值表示没有限制) - max-wait: -1ms + # 是否开启ssl + ssl: false + +--- # redisson 客户端配置 +redisson: + # 线程池数量 + threads: 16 + # Netty线程池数量 + nettyThreads: 32 + # 传输模式 + transportMode: "NIO" + # 单节点配置 + singleServerConfig: + # 客户端名称 + clientName: ${ruoyi-vue-plus.name} + # 最小空闲连接数 + connectionMinimumIdleSize: 32 + # 连接池大小 + connectionPoolSize: 64 + # 连接空闲超时,单位:毫秒 + idleConnectionTimeout: 10000 + # 命令等待超时,单位:毫秒 + timeout: 3000 + # 如果尝试在此限制之内发送成功,则开始启用 timeout 计时。 + retryAttempts: 3 + # 命令重试发送时间间隔,单位:毫秒 + retryInterval: 1500 + # 发布和订阅连接的最小空闲连接数 + subscriptionConnectionMinimumIdleSize: 1 + # 发布和订阅连接池大小 + subscriptionConnectionPoolSize: 50 + # 单个连接最大订阅数量 + subscriptionsPerConnection: 5 + # DNS监测时间间隔,单位:毫秒 + dnsMonitoringInterval: 5000 diff --git a/ruoyi-admin/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml index fbd01b336..eba8a8981 100644 --- a/ruoyi-admin/src/main/resources/application-prod.yml +++ b/ruoyi-admin/src/main/resources/application-prod.yml @@ -67,13 +67,38 @@ spring: password: # 连接超时时间 timeout: 10s - lettuce: - pool: - # 连接池中的最小空闲连接 - min-idle: 0 - # 连接池中的最大空闲连接 - max-idle: 8 - # 连接池的最大数据库连接数 - max-active: 8 - # #连接池最大阻塞等待时间(使用负值表示没有限制) - max-wait: -1ms \ No newline at end of file + # 是否开启ssl + ssl: false + +--- # redisson 客户端配置 +redisson: + # 线程池数量 + threads: 16 + # Netty线程池数量 + nettyThreads: 32 + # 传输模式 + transportMode: "NIO" + # 单节点配置 + singleServerConfig: + # 客户端名称 + clientName: ${ruoyi-vue-plus.name} + # 最小空闲连接数 + connectionMinimumIdleSize: 32 + # 连接池大小 + connectionPoolSize: 64 + # 连接空闲超时,单位:毫秒 + idleConnectionTimeout: 10000 + # 命令等待超时,单位:毫秒 + timeout: 3000 + # 如果尝试在此限制之内发送成功,则开始启用 timeout 计时。 + retryAttempts: 3 + # 命令重试发送时间间隔,单位:毫秒 + retryInterval: 1500 + # 发布和订阅连接的最小空闲连接数 + subscriptionConnectionMinimumIdleSize: 1 + # 发布和订阅连接池大小 + subscriptionConnectionPoolSize: 50 + # 单个连接最大订阅数量 + subscriptionsPerConnection: 5 + # DNS监测时间间隔,单位:毫秒 + dnsMonitoringInterval: 5000 diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index 5f1404e1f..2c75fcd1b 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -151,6 +151,12 @@ spring-boot-configuration-processor + + + org.redisson + redisson-spring-boot-starter + + diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java index 22a610db0..6c4c2393e 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java @@ -1,234 +1,219 @@ package com.ruoyi.common.core.redis; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; +import com.google.common.collect.Lists; +import org.redisson.api.*; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.BoundSetOperations; -import org.springframework.data.redis.core.HashOperations; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Component; +import java.util.*; +import java.util.concurrent.TimeUnit; + /** * spring redis 工具类 * - * @author ruoyi + * @author shenxinquan **/ -@SuppressWarnings(value = { "unchecked", "rawtypes" }) +@SuppressWarnings(value = {"unchecked", "rawtypes"}) @Component -public class RedisCache -{ - @Autowired - public RedisTemplate redisTemplate; +public class RedisCache { - /** - * 缓存基本的对象,Integer、String、实体类等 - * - * @param key 缓存的键值 - * @param value 缓存的值 - */ - public void setCacheObject(final String key, final T value) - { - redisTemplate.opsForValue().set(key, value); - } + @Autowired + private RedissonClient redissonClient; - /** - * 缓存基本的对象,Integer、String、实体类等 - * - * @param key 缓存的键值 - * @param value 缓存的值 - * @param timeout 时间 - * @param timeUnit 时间颗粒度 - */ - public void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) - { - redisTemplate.opsForValue().set(key, value, timeout, timeUnit); - } + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + */ + public void setCacheObject(final String key, final T value) { + redissonClient.getBucket(key).set(value); + } - /** - * 设置有效时间 - * - * @param key Redis键 - * @param timeout 超时时间 - * @return true=设置成功;false=设置失败 - */ - public boolean expire(final String key, final long timeout) - { - return expire(key, timeout, TimeUnit.SECONDS); - } + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + * @param timeout 时间 + * @param timeUnit 时间颗粒度 + */ + public void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) { + RBucket result = redissonClient.getBucket(key); + result.set(value); + result.expire(timeout, timeUnit); + } - /** - * 设置有效时间 - * - * @param key Redis键 - * @param timeout 超时时间 - * @param unit 时间单位 - * @return true=设置成功;false=设置失败 - */ - public boolean expire(final String key, final long timeout, final TimeUnit unit) - { - return redisTemplate.expire(key, timeout, unit); - } + /** + * 设置有效时间 + * + * @param key Redis键 + * @param timeout 超时时间 + * @return true=设置成功;false=设置失败 + */ + public boolean expire(final String key, final long timeout) { + return expire(key, timeout, TimeUnit.SECONDS); + } - /** - * 获得缓存的基本对象。 - * - * @param key 缓存键值 - * @return 缓存键值对应的数据 - */ - public T getCacheObject(final String key) - { - ValueOperations operation = redisTemplate.opsForValue(); - return operation.get(key); - } + /** + * 设置有效时间 + * + * @param key Redis键 + * @param timeout 超时时间 + * @param unit 时间单位 + * @return true=设置成功;false=设置失败 + */ + public boolean expire(final String key, final long timeout, final TimeUnit unit) { + RBucket rBucket = redissonClient.getBucket(key); + return rBucket.expire(timeout, unit); + } - /** - * 删除单个对象 - * - * @param key - */ - public boolean deleteObject(final String key) - { - return redisTemplate.delete(key); - } + /** + * 获得缓存的基本对象。 + * + * @param key 缓存键值 + * @return 缓存键值对应的数据 + */ + public T getCacheObject(final String key) { + RBucket rBucket = redissonClient.getBucket(key); + return rBucket.get(); + } - /** - * 删除集合对象 - * - * @param collection 多个对象 - * @return - */ - public long deleteObject(final Collection collection) - { - return redisTemplate.delete(collection); - } + /** + * 删除单个对象 + * + * @param key + */ + public boolean deleteObject(final String key) { + return redissonClient.getBucket(key).delete(); + } - /** - * 缓存List数据 - * - * @param key 缓存的键值 - * @param dataList 待缓存的List数据 - * @return 缓存的对象 - */ - public long setCacheList(final String key, final List dataList) - { - Long count = redisTemplate.opsForList().rightPushAll(key, dataList); - return count == null ? 0 : count; - } + /* */ - /** - * 获得缓存的list对象 - * - * @param key 缓存的键值 - * @return 缓存键值对应的数据 - */ - public List getCacheList(final String key) - { - return redisTemplate.opsForList().range(key, 0, -1); - } + /** + * 删除集合对象 + * + * @param collection 多个对象 + * @return + */ + public long deleteObject(final Collection collection) { + return redissonClient.getKeys().delete(Arrays.toString(collection.toArray())); + } - /** - * 缓存Set - * - * @param key 缓存键值 - * @param dataSet 缓存的数据 - * @return 缓存数据的对象 - */ - public BoundSetOperations setCacheSet(final String key, final Set dataSet) - { - BoundSetOperations setOperation = redisTemplate.boundSetOps(key); - Iterator it = dataSet.iterator(); - while (it.hasNext()) - { - setOperation.add(it.next()); - } - return setOperation; - } + /** + * 缓存List数据 + * + * @param key 缓存的键值 + * @param dataList 待缓存的List数据 + * @return 缓存的对象 + */ + public boolean setCacheList(final String key, final List dataList) { + RList rList = redissonClient.getList(key); + return rList.addAll(dataList); + } - /** - * 获得缓存的set - * - * @param key - * @return - */ - public Set getCacheSet(final String key) - { - return redisTemplate.opsForSet().members(key); - } + /** + * 获得缓存的list对象 + * + * @param key 缓存的键值 + * @return 缓存键值对应的数据 + */ + public List getCacheList(final String key) { + RList rList = redissonClient.getList(key); + return rList.readAll(); + } - /** - * 缓存Map - * - * @param key - * @param dataMap - */ - public void setCacheMap(final String key, final Map dataMap) - { - if (dataMap != null) { - redisTemplate.opsForHash().putAll(key, dataMap); - } - } + /** + * 缓存Set + * + * @param key 缓存键值 + * @param dataSet 缓存的数据 + * @return 缓存数据的对象 + */ + public boolean setCacheSet(final String key, final Set dataSet) { + RSet rSet = redissonClient.getSet(key); + return rSet.addAll(dataSet); + } - /** - * 获得缓存的Map - * - * @param key - * @return - */ - public Map getCacheMap(final String key) - { - return redisTemplate.opsForHash().entries(key); - } + /** + * 获得缓存的set + * + * @param key + * @return + */ + public Set getCacheSet(final String key) { + RSet rSet = redissonClient.getSet(key); + return rSet.readAll(); + } - /** - * 往Hash中存入数据 - * - * @param key Redis键 - * @param hKey Hash键 - * @param value 值 - */ - public void setCacheMapValue(final String key, final String hKey, final T value) - { - redisTemplate.opsForHash().put(key, hKey, value); - } + /** + * 缓存Map + * + * @param key + * @param dataMap + */ + public void setCacheMap(final String key, final Map dataMap) { + if (dataMap != null) { + RMap rMap = redissonClient.getMap(key); + rMap.putAll(dataMap); + } + } - /** - * 获取Hash中的数据 - * - * @param key Redis键 - * @param hKey Hash键 - * @return Hash中的对象 - */ - public T getCacheMapValue(final String key, final String hKey) - { - HashOperations opsForHash = redisTemplate.opsForHash(); - return opsForHash.get(key, hKey); - } + /** + * 获得缓存的Map + * + * @param key + * @return + */ + public Map getCacheMap(final String key) { + RMap rMap = redissonClient.getMap(key); + return rMap.getAll(rMap.keySet()); + } - /** - * 获取多个Hash中的数据 - * - * @param key Redis键 - * @param hKeys Hash键集合 - * @return Hash对象集合 - */ - public List getMultiCacheMapValue(final String key, final Collection hKeys) - { - return redisTemplate.opsForHash().multiGet(key, hKeys); - } + /** + * 往Hash中存入数据 + * + * @param key Redis键 + * @param hKey Hash键 + * @param value 值 + */ + public void setCacheMapValue(final String key, final String hKey, final T value) { + RMap rMap = redissonClient.getMap(key); + rMap.put(hKey, value); + } - /** - * 获得缓存的基本对象列表 - * - * @param pattern 字符串前缀 - * @return 对象列表 - */ - public Collection keys(final String pattern) - { - return redisTemplate.keys(pattern); - } + /** + * 获取Hash中的数据 + * + * @param key Redis键 + * @param hKey Hash键 + * @return Hash中的对象 + */ + public T getCacheMapValue(final String key, final String hKey) { + RMap rMap = redissonClient.getMap(key); + return rMap.get(hKey); + } + + /** + * 获取多个Hash中的数据 + * + * @param key Redis键 + * @param hKeys Hash键集合 + * @return Hash对象集合 + */ + public List getMultiCacheMapValue(final String key, final Collection hKeys) { + RListMultimap rListMultimap = redissonClient.getListMultimap(key); + return rListMultimap.getAll(hKeys); + } + + /** + * 获得缓存的基本对象列表 + * + * @param pattern 字符串前缀 + * @return 对象列表 + */ + public Collection keys(final String pattern) { + Iterable iterable = redissonClient.getKeys().getKeysByPattern(pattern); + return Lists.newArrayList(iterable); + } } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java index af471f49b..b86872985 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java @@ -1,42 +1,69 @@ package com.ruoyi.framework.config; -import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer; +import com.ruoyi.framework.config.properties.RedissonProperties; +import org.redisson.Redisson; +import org.redisson.api.RedissonClient; +import org.redisson.codec.JsonJacksonCodec; +import org.redisson.config.Config; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.serializer.StringRedisSerializer; + +import java.io.IOException; /** * redis配置 * - * @author ruoyi + * @author Lion Li */ @Configuration @EnableCaching -public class RedisConfig extends CachingConfigurerSupport -{ - @Bean - @SuppressWarnings(value = { "unchecked", "rawtypes" }) - public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) - { - RedisTemplate template = new RedisTemplate<>(); - template.setConnectionFactory(connectionFactory); +public class RedisConfig extends CachingConfigurerSupport { - GenericFastJsonRedisSerializer serializer = new GenericFastJsonRedisSerializer(); - StringRedisSerializer keySerializer = new StringRedisSerializer(); + private static final String REDIS_PROTOCOL_PREFIX = "redis://"; + private static final String REDISS_PROTOCOL_PREFIX = "rediss://"; - // 使用StringRedisSerializer来序列化和反序列化redis的key值 - template.setKeySerializer(keySerializer); - template.setValueSerializer(serializer); + @Autowired + private RedisProperties redisProperties; - // Hash的key也采用StringRedisSerializer的序列化方式 - template.setHashKeySerializer(keySerializer); - template.setHashValueSerializer(serializer); + @Autowired + private RedissonProperties redissonProperties; - template.afterPropertiesSet(); - return template; - } + @Bean(destroyMethod = "shutdown") + @ConditionalOnMissingBean(RedissonClient.class) + public RedissonClient redisson() throws IOException { + String prefix = REDIS_PROTOCOL_PREFIX; + if (redisProperties.isSsl()) { + prefix = REDISS_PROTOCOL_PREFIX; + } + Config config = new Config(); + config.setThreads(redissonProperties.getThreads()) + .setNettyThreads(redissonProperties.getNettyThreads()) + .setCodec(JsonJacksonCodec.INSTANCE) + .setTransportMode(redissonProperties.getTransportMode()); + + RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig(); + // 使用单机模式 + config.useSingleServer() + .setAddress(prefix + redisProperties.getHost() + ":" + redisProperties.getPort()) + .setConnectTimeout(((Long) redisProperties.getTimeout().toMillis()).intValue()) + .setDatabase(redisProperties.getDatabase()) + .setPassword(redisProperties.getPassword()) + .setTimeout(singleServerConfig.getTimeout()) + .setRetryAttempts(singleServerConfig.getRetryAttempts()) + .setRetryInterval(singleServerConfig.getRetryInterval()) + .setSubscriptionsPerConnection(singleServerConfig.getSubscriptionsPerConnection()) + .setClientName(singleServerConfig.getClientName()) + .setIdleConnectionTimeout(singleServerConfig.getIdleConnectionTimeout()) + .setSubscriptionConnectionMinimumIdleSize(singleServerConfig.getSubscriptionConnectionMinimumIdleSize()) + .setSubscriptionConnectionPoolSize(singleServerConfig.getSubscriptionConnectionPoolSize()) + .setConnectionMinimumIdleSize(singleServerConfig.getConnectionMinimumIdleSize()) + .setConnectionPoolSize(singleServerConfig.getConnectionPoolSize()) + .setDnsMonitoringInterval(singleServerConfig.getDnsMonitoringInterval()); + return Redisson.create(config); + } } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/RedissonProperties.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/RedissonProperties.java new file mode 100644 index 000000000..99db89eff --- /dev/null +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/RedissonProperties.java @@ -0,0 +1,101 @@ +package com.ruoyi.framework.config.properties; + +import lombok.Data; +import lombok.NoArgsConstructor; +import org.redisson.client.codec.Codec; +import org.redisson.config.TransportMode; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * Redisson 配置属性 + * + * @author Lion Li + */ +@Data +@Component +@ConfigurationProperties(prefix = "redisson") +public class RedissonProperties { + + /** + * 线程池数量,默认值 = 当前处理核数量 * 2 + */ + private int threads; + + /** + * Netty线程池数量,默认值 = 当前处理核数量 * 2 + */ + private int nettyThreads; + + /** + * 传输模式 + */ + private TransportMode transportMode; + + /** + * 单机服务配置 + */ + private SingleServerConfig singleServerConfig; + + @Data + @NoArgsConstructor + public static class SingleServerConfig { + + /** + * 客户端名称 + */ + private String clientName; + + /** + * 最小空闲连接数 + */ + private int connectionMinimumIdleSize; + + /** + * 连接池大小 + */ + private int connectionPoolSize; + + /** + * 连接空闲超时,单位:毫秒 + */ + private int idleConnectionTimeout; + + /** + * 命令等待超时,单位:毫秒 + */ + private int timeout; + + /** + * 如果尝试在此限制之内发送成功,则开始启用 timeout 计时。 + */ + private int retryAttempts; + + /** + * 命令重试发送时间间隔,单位:毫秒 + */ + private int retryInterval; + + /** + * 发布和订阅连接的最小空闲连接数 + */ + private int subscriptionConnectionMinimumIdleSize; + + /** + * 发布和订阅连接池大小 + */ + private int subscriptionConnectionPoolSize; + + /** + * 单个连接最大订阅数量 + */ + private int subscriptionsPerConnection; + + /** + * DNS监测时间间隔,单位:毫秒 + */ + private int dnsMonitoringInterval; + + } + +}