From 86dd0b3be6c6f786de95f77eb521db96aa45afad Mon Sep 17 00:00:00 2001 From: xlongwei Date: Fri, 27 Sep 2019 03:28:35 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81redis=E5=8D=95=E6=9C=BA?= =?UTF-8?q?=E6=88=96=E9=9B=86=E7=BE=A4=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-admin/pom.xml | 6 + .../ruoyi/web/core/config/CacheConfig.java | 68 +++++++++++ .../src/main/resources/application.yml | 16 +++ .../ruoyi/framework/config/ShiroConfig.java | 36 +++--- .../cache/SpringCacheManagerWrapper.java | 22 ++++ .../shiro/cache/SpringCacheWrapper.java | 106 ++++++++++++++++++ .../shiro/session/OnlineSessionDAO.java | 2 + 7 files changed, 242 insertions(+), 14 deletions(-) create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/core/config/CacheConfig.java create mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/cache/SpringCacheManagerWrapper.java create mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/cache/SpringCacheWrapper.java diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml index 87311e4f8..9d3ca7b04 100644 --- a/ruoyi-admin/pom.xml +++ b/ruoyi-admin/pom.xml @@ -23,6 +23,12 @@ spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-data-redis + + org.springframework.boot diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/CacheConfig.java b/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/CacheConfig.java new file mode 100644 index 000000000..ed59d8afe --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/CacheConfig.java @@ -0,0 +1,68 @@ +package com.ruoyi.web.core.config; + +import com.alibaba.fastjson.JSON; +import com.google.common.collect.Maps; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cache.ehcache.EhCacheCacheManager; +import org.springframework.cache.ehcache.EhCacheManagerFactoryBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ClassPathResource; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.connection.RedisConnectionFactory; + +import java.time.Duration; +import java.util.Map; + +@EnableCaching +@Configuration +public class CacheConfig { + @Autowired(required = false) + RedisConnectionFactory redisConnectionFactory; + //默认超时设置1小时 + @Value("${spring.redis.defaultExpiration:3600}") + Duration defaultExpiration; + //自定义部分缓存的超时 + @Value("${spring.redis.expires}") + String expires = "{}"; + + @Bean + public CacheManager cacheManager() { + if (redisConnectionFactory != null) { + try { + //配置有redis standalone或cluster,并且能正常连接时才启用redis缓存 + redisConnectionFactory.getConnection().ping(); + System.err.println("using redis cache manager"); + RedisCacheManager redisCacheManager = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults + (RedisCacheConfiguration.defaultCacheConfig().entryTtl(defaultExpiration)) + .withInitialCacheConfigurations(Maps.transformValues(JSON.parseObject(expires, Map.class), d -> + RedisCacheConfiguration + .defaultCacheConfig().entryTtl(Duration.ofSeconds(Long.valueOf(d.toString()))))) + .transactionAware().build(); + return redisCacheManager; + } catch (Exception e) { + System.err.println("fail to connect to redis"); + } + } + EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean(); + ehCacheManagerFactoryBean.setConfigLocation(new ClassPathResource("classpath:ehcache/ehcache-shiro.xml")); + ehCacheManagerFactoryBean.setShared(true); + return new EhCacheCacheManager(ehCacheManagerFactoryBean.getObject()) { + @Override + protected Cache getMissingCache(String name) { + Cache cache = super.getMissingCache(name); + if (cache == null) { + //使用default配置克隆缓存 + getCacheManager().addCacheIfAbsent(name); + cache = super.getCache(name); + } + return cache; + } + }; + } +} diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 92a78b141..b92c1189d 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -69,6 +69,22 @@ spring: restart: # 热部署开关 enabled: true + # redis配置 + redis: + host: localhost + port: 6379 + password: + timeout: 1500ms + # redis连接池配置 + jedis: + pool: + min-idle: 1 + # redis集群配置,逗号分隔多个host:port +# cluster: +# nodes: 127.0.0.1:6381,127.0.0.1:6382 + # 默认缓存超时1小时,启动时可初始化多个缓存并指定超时N秒 + defaultExpiration: 1h + expires: '{ "loginRecordCache": "600" }' # MyBatis mybatis: diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ShiroConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ShiroConfig.java index 721baf37b..d56faeb1e 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ShiroConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ShiroConfig.java @@ -6,6 +6,8 @@ import java.io.InputStream; import java.util.LinkedHashMap; import java.util.Map; import javax.servlet.Filter; + +import com.ruoyi.framework.shiro.cache.SpringCacheManagerWrapper; import org.apache.commons.io.IOUtils; import org.apache.shiro.cache.ehcache.EhCacheManager; import org.apache.shiro.codec.Base64; @@ -17,8 +19,10 @@ import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.CookieRememberMeManager; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.servlet.SimpleCookie; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.CacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.ruoyi.common.utils.StringUtils; @@ -93,23 +97,27 @@ public class ShiroConfig @Value("${shiro.user.unauthorizedUrl}") private String unauthorizedUrl; + @Autowired(required = false) + private CacheManager cacheManager; + /** - * 缓存管理器 使用Ehcache实现 + * 缓存管理器 使用Spring CacheManager或Ehcache实现 */ @Bean - public EhCacheManager getEhCacheManager() + public org.apache.shiro.cache.CacheManager getEhCacheManager() { - net.sf.ehcache.CacheManager cacheManager = net.sf.ehcache.CacheManager.getCacheManager("ruoyi"); - EhCacheManager em = new EhCacheManager(); - if (StringUtils.isNull(cacheManager)) - { - em.setCacheManager(new net.sf.ehcache.CacheManager(getCacheManagerConfigFileInputStream())); - return em; - } - else - { - em.setCacheManager(cacheManager); - return em; + if(cacheManager != null){ + return new SpringCacheManagerWrapper(cacheManager); + }else { + net.sf.ehcache.CacheManager cacheManager = net.sf.ehcache.CacheManager.getCacheManager("ruoyi"); + EhCacheManager em = new EhCacheManager(); + if (StringUtils.isNull(cacheManager)) { + em.setCacheManager(new net.sf.ehcache.CacheManager(getCacheManagerConfigFileInputStream())); + return em; + } else { + em.setCacheManager(cacheManager); + return em; + } } } @@ -142,7 +150,7 @@ public class ShiroConfig * 自定义Realm */ @Bean - public UserRealm userRealm(EhCacheManager cacheManager) + public UserRealm userRealm(org.apache.shiro.cache.CacheManager cacheManager) { UserRealm userRealm = new UserRealm(); userRealm.setCacheManager(cacheManager); diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/cache/SpringCacheManagerWrapper.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/cache/SpringCacheManagerWrapper.java new file mode 100644 index 000000000..02020d192 --- /dev/null +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/cache/SpringCacheManagerWrapper.java @@ -0,0 +1,22 @@ +package com.ruoyi.framework.shiro.cache; + + +import org.apache.shiro.cache.Cache; +import org.apache.shiro.cache.CacheException; +import org.apache.shiro.cache.CacheManager; + +/** 包装Spring CacheManager为Shiro CacheManager */ +public class SpringCacheManagerWrapper implements CacheManager { + + private org.springframework.cache.CacheManager cacheManager; + + public SpringCacheManagerWrapper(org.springframework.cache.CacheManager cacheManager) { + this.cacheManager = cacheManager; + } + + @Override + public Cache getCache(String name) throws CacheException { + org.springframework.cache.Cache springCache = cacheManager.getCache(name); + return new SpringCacheWrapper(springCache); + } +} \ No newline at end of file diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/cache/SpringCacheWrapper.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/cache/SpringCacheWrapper.java new file mode 100644 index 000000000..2c19a3a6b --- /dev/null +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/cache/SpringCacheWrapper.java @@ -0,0 +1,106 @@ +package com.ruoyi.framework.shiro.cache; + +import net.sf.ehcache.Ehcache; +import org.apache.shiro.cache.Cache; +import org.apache.shiro.cache.CacheException; +import org.apache.shiro.util.CollectionUtils; +import org.springframework.cache.support.SimpleValueWrapper; + +import java.util.*; + +/** 包装Spring Cache为Shiro Cache */ +public class SpringCacheWrapper implements Cache { + private org.springframework.cache.Cache springCache; + private boolean isEhcache; + private Set keys; + + SpringCacheWrapper(org.springframework.cache.Cache springCache) { + this.springCache = springCache; + this.isEhcache = springCache.getNativeCache() instanceof Ehcache; + if (!this.isEhcache) { + keys = new HashSet<>(); + } + } + + @Override + public Object get(Object key) throws CacheException { + Object value = springCache.get(isEhcache ? key : key.toString()); + if (value instanceof SimpleValueWrapper) { + return ((SimpleValueWrapper) value).get(); + } + return value; + } + + @Override + public Object put(Object key, Object value) throws CacheException { + springCache.put(isEhcache ? key : key.toString(), value); + if (!isEhcache) { + keys.add(key.toString()); + } + return value; + } + + @Override + public Object remove(Object key) throws CacheException { + springCache.evict(isEhcache ? key : key.toString()); + if (!isEhcache) { + keys.remove(key.toString()); + } + return null; + } + + @Override + public void clear() throws CacheException { + springCache.clear(); + if (!isEhcache) { + keys.clear(); + } + } + + @Override + public int size() { + if (isEhcache) { + Ehcache ehcache = (Ehcache) springCache.getNativeCache(); + return ehcache.getSize(); + } else { + return keys.size(); + } + } + + @Override + public Set keys() { + if (isEhcache) { + Ehcache ehcache = (Ehcache) springCache.getNativeCache(); + return new HashSet(ehcache.getKeys()); + } else { + return keys; + } + } + + @Override + public Collection values() { + if (isEhcache) { + Ehcache ehcache = (Ehcache) springCache.getNativeCache(); + List keys = ehcache.getKeys(); + if (!CollectionUtils.isEmpty(keys)) { + List values = new ArrayList<>(keys.size()); + for (Object key : keys) { + Object value = get(key); + if (value != null) { + values.add(value); + } + } + return Collections.unmodifiableList(values); + } else { + return Collections.emptyList(); + } + } else { + List values = new ArrayList<>(keys.size()); + for (Object key : keys) { + Object value = get(key); + values.add(value); + } + return Collections.unmodifiableCollection(values); + } + } +} \ No newline at end of file diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/session/OnlineSessionDAO.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/session/OnlineSessionDAO.java index 40ff31277..0ae95a87b 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/session/OnlineSessionDAO.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/session/OnlineSessionDAO.java @@ -92,6 +92,8 @@ public class OnlineSessionDAO extends EnterpriseCacheSessionDAO } // 更新上次同步数据库时间 onlineSession.setAttribute(LAST_SYNC_DB_TIMESTAMP, onlineSession.getLastAccessTime()); + // 保存数据更新到缓存,避免每次都同步到数据库 + cache(onlineSession, onlineSession.getId()); // 更新完后 重置标识 if (onlineSession.isAttributeChanged()) {