支持redis单机或集群缓存
This commit is contained in:
parent
cf211fa19c
commit
86dd0b3be6
|
|
@ -23,6 +23,12 @@
|
||||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 支持redis缓存 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- spring-boot-devtools -->
|
<!-- spring-boot-devtools -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -69,6 +69,22 @@ spring:
|
||||||
restart:
|
restart:
|
||||||
# 热部署开关
|
# 热部署开关
|
||||||
enabled: true
|
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
|
||||||
mybatis:
|
mybatis:
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ import java.io.InputStream;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.servlet.Filter;
|
import javax.servlet.Filter;
|
||||||
|
|
||||||
|
import com.ruoyi.framework.shiro.cache.SpringCacheManagerWrapper;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.shiro.cache.ehcache.EhCacheManager;
|
import org.apache.shiro.cache.ehcache.EhCacheManager;
|
||||||
import org.apache.shiro.codec.Base64;
|
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.CookieRememberMeManager;
|
||||||
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
|
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
|
||||||
import org.apache.shiro.web.servlet.SimpleCookie;
|
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.Qualifier;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.cache.CacheManager;
|
||||||
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.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
|
|
@ -93,25 +97,29 @@ public class ShiroConfig
|
||||||
@Value("${shiro.user.unauthorizedUrl}")
|
@Value("${shiro.user.unauthorizedUrl}")
|
||||||
private String unauthorizedUrl;
|
private String unauthorizedUrl;
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private CacheManager cacheManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 缓存管理器 使用Ehcache实现
|
* 缓存管理器 使用Spring CacheManager或Ehcache实现
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public EhCacheManager getEhCacheManager()
|
public org.apache.shiro.cache.CacheManager getEhCacheManager()
|
||||||
{
|
{
|
||||||
|
if(cacheManager != null){
|
||||||
|
return new SpringCacheManagerWrapper(cacheManager);
|
||||||
|
}else {
|
||||||
net.sf.ehcache.CacheManager cacheManager = net.sf.ehcache.CacheManager.getCacheManager("ruoyi");
|
net.sf.ehcache.CacheManager cacheManager = net.sf.ehcache.CacheManager.getCacheManager("ruoyi");
|
||||||
EhCacheManager em = new EhCacheManager();
|
EhCacheManager em = new EhCacheManager();
|
||||||
if (StringUtils.isNull(cacheManager))
|
if (StringUtils.isNull(cacheManager)) {
|
||||||
{
|
|
||||||
em.setCacheManager(new net.sf.ehcache.CacheManager(getCacheManagerConfigFileInputStream()));
|
em.setCacheManager(new net.sf.ehcache.CacheManager(getCacheManagerConfigFileInputStream()));
|
||||||
return em;
|
return em;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
em.setCacheManager(cacheManager);
|
em.setCacheManager(cacheManager);
|
||||||
return em;
|
return em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回配置文件流 避免ehcache配置文件一直被占用,无法完全销毁项目重新部署
|
* 返回配置文件流 避免ehcache配置文件一直被占用,无法完全销毁项目重新部署
|
||||||
|
|
@ -142,7 +150,7 @@ public class ShiroConfig
|
||||||
* 自定义Realm
|
* 自定义Realm
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public UserRealm userRealm(EhCacheManager cacheManager)
|
public UserRealm userRealm(org.apache.shiro.cache.CacheManager cacheManager)
|
||||||
{
|
{
|
||||||
UserRealm userRealm = new UserRealm();
|
UserRealm userRealm = new UserRealm();
|
||||||
userRealm.setCacheManager(cacheManager);
|
userRealm.setCacheManager(cacheManager);
|
||||||
|
|
|
||||||
22
ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/cache/SpringCacheManagerWrapper.java
vendored
Normal file
22
ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/cache/SpringCacheManagerWrapper.java
vendored
Normal file
|
|
@ -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 <K, V> Cache<K, V> getCache(String name) throws CacheException {
|
||||||
|
org.springframework.cache.Cache springCache = cacheManager.getCache(name);
|
||||||
|
return new SpringCacheWrapper(springCache);
|
||||||
|
}
|
||||||
|
}
|
||||||
106
ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/cache/SpringCacheWrapper.java
vendored
Normal file
106
ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/cache/SpringCacheWrapper.java
vendored
Normal file
|
|
@ -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<Object> 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<Object>(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<Object> 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<Object> values = new ArrayList<>(keys.size());
|
||||||
|
for (Object key : keys) {
|
||||||
|
Object value = get(key);
|
||||||
|
values.add(value);
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableCollection(values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -92,6 +92,8 @@ public class OnlineSessionDAO extends EnterpriseCacheSessionDAO
|
||||||
}
|
}
|
||||||
// 更新上次同步数据库时间
|
// 更新上次同步数据库时间
|
||||||
onlineSession.setAttribute(LAST_SYNC_DB_TIMESTAMP, onlineSession.getLastAccessTime());
|
onlineSession.setAttribute(LAST_SYNC_DB_TIMESTAMP, onlineSession.getLastAccessTime());
|
||||||
|
// 保存数据更新到缓存,避免每次都同步到数据库
|
||||||
|
cache(onlineSession, onlineSession.getId());
|
||||||
// 更新完后 重置标识
|
// 更新完后 重置标识
|
||||||
if (onlineSession.isAttributeChanged())
|
if (onlineSession.isAttributeChanged())
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue