mirror of
https://github.com/abcv7/sfbx-cloud.git
synced 2026-08-16 19:49:49 +00:00
first commit
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
<?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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>sfbx-framework</artifactId>
|
||||
<groupId>com.itheima.sfbx</groupId>
|
||||
<version>2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<!--基础模块-redis支持-->
|
||||
<artifactId>framework-redis</artifactId>
|
||||
<name>framework-redis</name>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.itheima.sfbx</groupId>
|
||||
<artifactId>framework-commons</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-cache</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.itheima.sfbx.framework.redis.config;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.redisson.Redisson;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.redisson.codec.JsonJacksonCodec;
|
||||
import org.redisson.config.Config;
|
||||
import org.redisson.config.SingleServerConfig;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
@ConditionalOnClass(RedissonClient.class)
|
||||
public class CustomRedissonConfig {
|
||||
private final RedisProperties redisProperties;
|
||||
@Bean(
|
||||
destroyMethod = "shutdown"
|
||||
)
|
||||
@Primary
|
||||
public RedissonClient redisson() {
|
||||
Config config = new Config();
|
||||
String prefix = "redis://";
|
||||
((SingleServerConfig)config.useSingleServer()
|
||||
.setAddress(prefix + this.redisProperties.getHost() + ":" + this.redisProperties.getPort()))
|
||||
.setDatabase(this.redisProperties.getDatabase())
|
||||
.setPassword(this.redisProperties.getPassword());
|
||||
config.setCodec(JsonJacksonCodec.INSTANCE);
|
||||
return Redisson.create(config);
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package com.itheima.sfbx.framework.redis.config;
|
||||
|
||||
import com.itheima.sfbx.framework.redis.properties.DataSecurityCacheProperties;
|
||||
import com.itheima.sfbx.framework.redis.resolver.CustomRedisCacheManager;
|
||||
import com.itheima.sfbx.framework.redis.properties.TenantCacheProperties;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.cache.CacheKeyPrefix;
|
||||
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.RedisSerializationContext;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
@EnableConfigurationProperties({TenantCacheProperties.class,DataSecurityCacheProperties.class})
|
||||
public class RedisCacheConfig {
|
||||
|
||||
@Autowired
|
||||
TenantCacheProperties tenantCacheProperties;
|
||||
|
||||
@Autowired
|
||||
DataSecurityCacheProperties dataSecurityCacheProperties;
|
||||
|
||||
/**
|
||||
* 修改spring-cache默认前缀为:
|
||||
*/
|
||||
@Bean
|
||||
public CacheKeyPrefix cacheKeyPrefix() {
|
||||
return cacheName -> cacheName + ":";
|
||||
}
|
||||
|
||||
/**
|
||||
* 申明缓存管理器,会创建一个切面(aspect)并触发Spring缓存注解的切点(pointcut)
|
||||
* 根据类或者方法所使用的注解以及缓存的状态,这个切面会从缓存中获取数据,
|
||||
* 将数据添加到缓存之中或者从缓存中移除某个值
|
||||
*/
|
||||
@Bean
|
||||
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
|
||||
//对key的序列化操作:String
|
||||
RedisSerializer<String> keySerializer = new StringRedisSerializer();
|
||||
//对value的序列化操作:json
|
||||
GenericJackson2JsonRedisSerializer valuesSerializer = new GenericJackson2JsonRedisSerializer();
|
||||
//配置config,指定超时时间记得key val 序列化处理
|
||||
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
|
||||
.computePrefixWith(cacheKeyPrefix())
|
||||
//指定全局默认超时时间【600S】
|
||||
.entryTtl(Duration.ofSeconds(1))
|
||||
//配置key的序列化方式
|
||||
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer))
|
||||
//配置value的序列化方式
|
||||
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valuesSerializer));
|
||||
//关闭空值的存储
|
||||
//.disableCachingNullValues();
|
||||
//使用CustomRedisCacheManager进行初始化
|
||||
return new CustomRedisCacheManager(redisConnectionFactory, config, tenantCacheProperties,dataSecurityCacheProperties);
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.itheima.sfbx.framework.redis.properties;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @ClassName TenantProperties.java
|
||||
* @Description spring-cache多租户属性
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@ConfigurationProperties(prefix = "spring.cache")
|
||||
public class DataSecurityCacheProperties {
|
||||
|
||||
//需要忽略的数据权限的表
|
||||
public List<String> ignoreDataSecurityTables;
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.itheima.sfbx.framework.redis.properties;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.ConstructorBinding;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @ClassName TenantProperties.java
|
||||
* @Description spring-cache多租户属性
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@ConfigurationProperties(prefix = "spring.cache")
|
||||
public class TenantCacheProperties {
|
||||
|
||||
//需要忽略的企业ID的表
|
||||
public List<String> ignoreCompanyTables;
|
||||
|
||||
//默认企业编号Id
|
||||
public String defaultCompanyNo;
|
||||
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package com.itheima.sfbx.framework.redis.resolver;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.redis.cache.RedisCache;
|
||||
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||||
import org.springframework.data.redis.cache.RedisCacheWriter;
|
||||
|
||||
/**
|
||||
* @ClassName CustomRedisCache.java
|
||||
* @Description redis缓存自定义处理
|
||||
*/
|
||||
public class CustomRedisCache extends RedisCache {
|
||||
private final String name;
|
||||
private final RedisCacheWriter cacheWriter;
|
||||
private final ConversionService conversionService;
|
||||
|
||||
protected CustomRedisCache(String name, RedisCacheWriter cacheWriter, RedisCacheConfiguration cacheConfig) {
|
||||
super(name, cacheWriter, cacheConfig);
|
||||
this.name = name;
|
||||
this.cacheWriter = cacheWriter;
|
||||
this.conversionService = cacheConfig.getConversionService();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @Title: evict
|
||||
* @Description: 重写删除的方法
|
||||
* @param @param key
|
||||
* @throws
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public void evict(Object key) {
|
||||
|
||||
if (key instanceof String) {
|
||||
String keyString = key.toString();
|
||||
// 后缀删除
|
||||
if (keyString.endsWith("*")) {
|
||||
evictLikeSuffix(keyString);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 删除指定的key
|
||||
super.evict(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 后缀匹配匹配
|
||||
*
|
||||
* @param key
|
||||
*/
|
||||
private void evictLikeSuffix(String key) {
|
||||
byte[] pattern = this.conversionService.convert(this.createCacheKey(key), byte[].class);
|
||||
this.cacheWriter.clean(this.name, pattern);
|
||||
}
|
||||
}
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
package com.itheima.sfbx.framework.redis.resolver;
|
||||
|
||||
import com.itheima.sfbx.framework.commons.dto.security.DataSecurityVO;
|
||||
import com.itheima.sfbx.framework.commons.utils.EmptyUtil;
|
||||
import com.itheima.sfbx.framework.commons.utils.SubjectContent;
|
||||
import com.itheima.sfbx.framework.redis.properties.DataSecurityCacheProperties;
|
||||
import com.itheima.sfbx.framework.redis.properties.TenantCacheProperties;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.data.redis.cache.RedisCache;
|
||||
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||||
import org.springframework.data.redis.cache.RedisCacheManager;
|
||||
import org.springframework.data.redis.cache.RedisCacheWriter;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @ClassName CustomCacheManager.java
|
||||
* @Description 自定义缓存管理者
|
||||
*/
|
||||
public class CustomRedisCacheManager extends RedisCacheManager {
|
||||
|
||||
private final RedisCacheWriter cacheWriter;
|
||||
private final RedisCacheConfiguration defaultCacheConfig;
|
||||
private TenantCacheProperties tenantCacheProperties;
|
||||
private DataSecurityCacheProperties dataSecurityCacheProperties;
|
||||
|
||||
public CustomRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
|
||||
super(cacheWriter, defaultCacheConfiguration);
|
||||
this.cacheWriter = cacheWriter;
|
||||
this.defaultCacheConfig = defaultCacheConfiguration;
|
||||
}
|
||||
|
||||
public CustomRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration, String... initialCacheNames) {
|
||||
super(cacheWriter, defaultCacheConfiguration, initialCacheNames);
|
||||
this.cacheWriter = cacheWriter;
|
||||
this.defaultCacheConfig = defaultCacheConfiguration;
|
||||
}
|
||||
|
||||
public CustomRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration, boolean allowInFlightCacheCreation, String... initialCacheNames) {
|
||||
super(cacheWriter, defaultCacheConfiguration, allowInFlightCacheCreation, initialCacheNames);
|
||||
this.cacheWriter = cacheWriter;
|
||||
this.defaultCacheConfig = defaultCacheConfiguration;
|
||||
}
|
||||
|
||||
public CustomRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration, Map<String, RedisCacheConfiguration> initialCacheConfigurations) {
|
||||
super(cacheWriter, defaultCacheConfiguration, initialCacheConfigurations);
|
||||
this.cacheWriter = cacheWriter;
|
||||
this.defaultCacheConfig = defaultCacheConfiguration;
|
||||
}
|
||||
|
||||
public CustomRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration, Map<String, RedisCacheConfiguration> initialCacheConfigurations, boolean allowInFlightCacheCreation) {
|
||||
super(cacheWriter, defaultCacheConfiguration, initialCacheConfigurations, allowInFlightCacheCreation);
|
||||
this.cacheWriter = cacheWriter;
|
||||
this.defaultCacheConfig = defaultCacheConfiguration;
|
||||
}
|
||||
|
||||
public CustomRedisCacheManager(RedisConnectionFactory redisConnectionFactory, RedisCacheConfiguration cacheConfiguration, TenantCacheProperties tenantCacheProperties, DataSecurityCacheProperties dataSecurityCacheProperties) {
|
||||
this(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory),cacheConfiguration);
|
||||
this.tenantCacheProperties =tenantCacheProperties;
|
||||
this.dataSecurityCacheProperties=dataSecurityCacheProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* 覆盖父类创建RedisCache,采用自定义的RedisCacheResolver
|
||||
* @Title: createRedisCache
|
||||
* @Description: TODO
|
||||
* @param @param name
|
||||
* @param @param cacheConfig
|
||||
* @param @return
|
||||
* @throws
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
protected RedisCache createRedisCache(String name, @Nullable RedisCacheConfiguration cacheConfig) {
|
||||
//自定义缓存时间例如
|
||||
//@Cacheable(value = DataDictCacheConstant.PARENT_KEY+"=-1",key = "#parentKey")
|
||||
String[] split = name.split("&");
|
||||
if (split.length==1){
|
||||
name=split[0];
|
||||
}else if (split.length==2){
|
||||
name=split[0];
|
||||
long ttl = Long.valueOf(split[1].replaceAll("ttl=",""));
|
||||
cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(ttl));
|
||||
}else {
|
||||
throw new RuntimeException("自定义缓存失效时间异常");
|
||||
}
|
||||
return new CustomRedisCache(name, cacheWriter, cacheConfig != null ? cacheConfig : defaultCacheConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从上下文中获取租户ID,重写key值添加多租户模式
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Cache getCache(String name) {
|
||||
//多租户及数据权限缓存key处理
|
||||
String companyNo = SubjectContent.getCompanyNo();
|
||||
String dataSecurity = null;
|
||||
DataSecurityVO dataSecurityVO = SubjectContent.getDataSecurityVO();
|
||||
//查看个人数据
|
||||
if (!EmptyUtil.isNullOrEmpty(dataSecurityVO)&&dataSecurityVO.getYouselfData()){
|
||||
dataSecurity = String.valueOf(SubjectContent.getUserVO().getId().hashCode());
|
||||
}
|
||||
//查看授权数据
|
||||
if (!EmptyUtil.isNullOrEmpty(dataSecurityVO)&&!dataSecurityVO.getYouselfData()){
|
||||
dataSecurity = dataSecurity+":"+SubjectContent.getUserVO().getDataSecurityVO().hashCode();
|
||||
}
|
||||
String[] nameTime = name.split("&");
|
||||
String targetTab = "tab_"+name.split(":")[0].replace("-","_");
|
||||
if (!EmptyUtil.isNullOrEmpty(companyNo)&&
|
||||
!tenantCacheProperties.getDefaultCompanyNo().equals(companyNo)){
|
||||
boolean isIgnoreCompanyNo = false;
|
||||
if (!EmptyUtil.isNullOrEmpty(tenantCacheProperties.getIgnoreCompanyTables())){
|
||||
isIgnoreCompanyNo = !tenantCacheProperties.getIgnoreCompanyTables().contains(targetTab);
|
||||
}
|
||||
if (isIgnoreCompanyNo){
|
||||
nameTime[0] = nameTime[0]+":"+companyNo;
|
||||
}
|
||||
}
|
||||
boolean isIgnoreDataSecurity = false;
|
||||
if (!EmptyUtil.isNullOrEmpty(dataSecurityCacheProperties.getIgnoreDataSecurityTables())){
|
||||
isIgnoreDataSecurity = !dataSecurityCacheProperties.getIgnoreDataSecurityTables().contains(targetTab);
|
||||
}
|
||||
if (isIgnoreDataSecurity){
|
||||
nameTime[0] = nameTime[0]+":"+dataSecurity;
|
||||
}
|
||||
if (nameTime.length==2){
|
||||
name = nameTime[0]+"&"+nameTime[1];
|
||||
}else{
|
||||
name = nameTime[0];
|
||||
}
|
||||
//默认企业则不做缓存租户处理
|
||||
return super.getCache(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, RedisCacheConfiguration> getCacheConfigurations() {
|
||||
Map<String, RedisCacheConfiguration> configurationMap = new HashMap<>(getCacheNames().size());
|
||||
getCacheNames().forEach(it -> {
|
||||
RedisCache cache = CustomRedisCache.class.cast(lookupCache(it));
|
||||
configurationMap.put(it, cache != null ? cache.getCacheConfiguration() : null);
|
||||
});
|
||||
return Collections.unmodifiableMap(configurationMap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.itheima.sfbx.framework.redis.config.CustomRedissonConfig
|
||||
Reference in New Issue
Block a user