mirror of
https://github.com/blossom-editor/blossom
synced 2024-11-17 14:39:21 +08:00
Merge 68a7858a60
into b2d5342189
This commit is contained in:
commit
0d1a5f9929
@ -88,6 +88,10 @@
|
||||
<artifactId>lucene-highlighter</artifactId>
|
||||
<version>${lucene.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@ -164,4 +168,4 @@
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.blossom.backend;
|
||||
|
||||
import com.blossom.backend.config.ContextInitializer;
|
||||
import com.blossom.backend.config.PropertiesCheckListener;
|
||||
import com.blossom.common.base.BaseConstants;
|
||||
import com.blossom.expand.tracker.core.Tracker;
|
||||
@ -23,6 +24,7 @@ public class APP {
|
||||
Tracker.start("APPLICATION_START", TrackerConstants.SPAN_TYPE_APPLICATION_RUN);
|
||||
SpringApplication app = new SpringApplication(APP.class);
|
||||
app.addListeners(new PropertiesCheckListener());
|
||||
app.addInitializers(new ContextInitializer());
|
||||
app.run(args);
|
||||
BaseConstants.desc();
|
||||
Tracker.end();
|
||||
|
@ -1,111 +1,111 @@
|
||||
//package com.blossom.backend.base.auth.redis;
|
||||
//
|
||||
//import com.blossom.backend.base.auth.AuthConstant;
|
||||
//import com.blossom.backend.base.auth.AuthProperties;
|
||||
//import com.blossom.backend.base.auth.repo.TokenRepository;
|
||||
//import com.blossom.backend.base.auth.filters.AuthFilterProxy;
|
||||
//import com.blossom.backend.base.auth.filters.HttpFirewall;
|
||||
//import com.blossom.backend.base.auth.filters.RequestLogFilter;
|
||||
//import com.blossom.backend.base.auth.filters.WhiteListFilter;
|
||||
//import lombok.extern.slf4j.Slf4j;
|
||||
//import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
//import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
//import org.springframework.core.annotation.Order;
|
||||
//import org.springframework.data.redis.core.RedisTemplate;
|
||||
//import org.springframework.stereotype.Component;
|
||||
//
|
||||
//import javax.servlet.FilterChain;
|
||||
//import javax.servlet.ServletException;
|
||||
//import javax.servlet.ServletRequest;
|
||||
//import javax.servlet.ServletResponse;
|
||||
//import java.io.IOException;
|
||||
//
|
||||
///**
|
||||
// * redis token 拦截器实现
|
||||
// *
|
||||
// * @author xzzz
|
||||
// */
|
||||
//@Slf4j
|
||||
//@Component
|
||||
//@Order(AuthConstant.AUTH_FILTER_PROXY)
|
||||
//@ConditionalOnClass(RedisTemplate.class)
|
||||
//@ConditionalOnProperty(value = "project.auth.type", havingValue = "redis")
|
||||
//public class RedisTokenAuthFilterProxy extends AuthFilterProxy {
|
||||
// /**
|
||||
// * 防火墙对象
|
||||
// */
|
||||
// protected final HttpFirewall httpFirewall = new HttpFirewall();
|
||||
// /**
|
||||
// * 日期过滤器
|
||||
// */
|
||||
// protected final RequestLogFilter logFilter;
|
||||
// /**
|
||||
// * 白名单过滤器
|
||||
// */
|
||||
// protected final WhiteListFilter whiteListFilter;
|
||||
// /**
|
||||
// * 授权检查过滤器
|
||||
// */
|
||||
// private final RedisTokenValidateFilter redisTokenValidateFilter;
|
||||
// /**
|
||||
// * 唯一授权检查过滤器
|
||||
// */
|
||||
// private final RedisTokenUniqueFilter redisTokenUniqueFilter;
|
||||
// /**
|
||||
// * 授权重置过滤器
|
||||
// */
|
||||
// private final RedisTokenExpireResetFilter redisTokenExpireResetFilter;
|
||||
//
|
||||
// public RedisTokenAuthFilterProxy(AuthProperties properties, TokenRepository tokenRepository) {
|
||||
// super(properties);
|
||||
// this.logFilter = new RequestLogFilter(properties);
|
||||
// this.whiteListFilter = new WhiteListFilter(properties);
|
||||
// this.redisTokenValidateFilter = new RedisTokenValidateFilter(tokenRepository);
|
||||
// this.redisTokenUniqueFilter = new RedisTokenUniqueFilter(tokenRepository);
|
||||
// this.redisTokenExpireResetFilter = new RedisTokenExpireResetFilter(tokenRepository);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * <p>1. 防火墙校验
|
||||
// * <p>2. 授权校验
|
||||
// * <ol>
|
||||
// * <li>日志</li>
|
||||
// * <li>白名单</li>
|
||||
// * <li>授权校验</li>
|
||||
// * <li>授权续期</li>
|
||||
// * </ol>
|
||||
// *
|
||||
// * @param request request
|
||||
// * @param response response
|
||||
// * @param chain chain
|
||||
// */
|
||||
// @Override
|
||||
// protected void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
// /*
|
||||
// 1. 执行防火墙
|
||||
// */
|
||||
// httpFirewall.wall(request);
|
||||
//
|
||||
// /*
|
||||
// 2. 授权校验
|
||||
// */
|
||||
// // 2.1 日志
|
||||
// logFilter.doFilter(request, response);
|
||||
// // 2.2 白名单
|
||||
// whiteListFilter.doFilter(request, response);
|
||||
// // 2.3 token 校验
|
||||
// redisTokenValidateFilter.doFilter(request, response);
|
||||
// // 2.4 token 唯一校验
|
||||
// redisTokenUniqueFilter.doFilter(request, response);
|
||||
// // 2.5 过期时间刷新
|
||||
// redisTokenExpireResetFilter.doFilter(request, response);
|
||||
//
|
||||
// /*
|
||||
// 虚拟过滤器链执行完毕后交由原生过滤器继续执行
|
||||
// */
|
||||
// chain.doFilter(request, response);
|
||||
//
|
||||
// log.debug("[AUTHORIZ] **Proxy** >> 原生过滤器: request 请求结束");
|
||||
// }
|
||||
//
|
||||
//}
|
||||
package com.blossom.backend.base.auth.redis;
|
||||
|
||||
import com.blossom.backend.base.auth.AuthConstant;
|
||||
import com.blossom.backend.base.auth.AuthProperties;
|
||||
import com.blossom.backend.base.auth.filters.AuthFilterProxy;
|
||||
import com.blossom.backend.base.auth.filters.HttpFirewall;
|
||||
import com.blossom.backend.base.auth.filters.RequestLogFilter;
|
||||
import com.blossom.backend.base.auth.filters.WhiteListFilter;
|
||||
import com.blossom.backend.base.auth.repo.TokenRepository;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* redis token 拦截器实现
|
||||
*
|
||||
* @author xzzz
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@Order(AuthConstant.AUTH_FILTER_PROXY)
|
||||
@ConditionalOnClass(RedisTemplate.class)
|
||||
@ConditionalOnProperty(value = "project.auth.type", havingValue = "redis")
|
||||
public class RedisTokenAuthFilterProxy extends AuthFilterProxy {
|
||||
/**
|
||||
* 防火墙对象
|
||||
*/
|
||||
protected final HttpFirewall httpFirewall = new HttpFirewall();
|
||||
/**
|
||||
* 日期过滤器
|
||||
*/
|
||||
protected final RequestLogFilter logFilter;
|
||||
/**
|
||||
* 白名单过滤器
|
||||
*/
|
||||
protected final WhiteListFilter whiteListFilter;
|
||||
/**
|
||||
* 授权检查过滤器
|
||||
*/
|
||||
private final RedisTokenValidateFilter redisTokenValidateFilter;
|
||||
/**
|
||||
* 唯一授权检查过滤器
|
||||
*/
|
||||
private final RedisTokenUniqueFilter redisTokenUniqueFilter;
|
||||
/**
|
||||
* 授权重置过滤器
|
||||
*/
|
||||
private final RedisTokenExpireResetFilter redisTokenExpireResetFilter;
|
||||
|
||||
public RedisTokenAuthFilterProxy(AuthProperties properties, TokenRepository tokenRepository) {
|
||||
super(properties);
|
||||
this.logFilter = new RequestLogFilter(properties);
|
||||
this.whiteListFilter = new WhiteListFilter(properties);
|
||||
this.redisTokenValidateFilter = new RedisTokenValidateFilter(tokenRepository);
|
||||
this.redisTokenUniqueFilter = new RedisTokenUniqueFilter(tokenRepository);
|
||||
this.redisTokenExpireResetFilter = new RedisTokenExpireResetFilter(tokenRepository);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>1. 防火墙校验
|
||||
* <p>2. 授权校验
|
||||
* <ol>
|
||||
* <li>日志</li>
|
||||
* <li>白名单</li>
|
||||
* <li>授权校验</li>
|
||||
* <li>授权续期</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param request request
|
||||
* @param response response
|
||||
* @param chain chain
|
||||
*/
|
||||
@Override
|
||||
protected void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
/*
|
||||
1. 执行防火墙
|
||||
*/
|
||||
httpFirewall.wall(request);
|
||||
|
||||
/*
|
||||
2. 授权校验
|
||||
*/
|
||||
// 2.1 日志
|
||||
logFilter.doFilter(request, response);
|
||||
// 2.2 白名单
|
||||
whiteListFilter.doFilter(request, response);
|
||||
// 2.3 token 校验
|
||||
redisTokenValidateFilter.doFilter(request, response);
|
||||
// 2.4 token 唯一校验
|
||||
redisTokenUniqueFilter.doFilter(request, response);
|
||||
// 2.5 过期时间刷新
|
||||
redisTokenExpireResetFilter.doFilter(request, response);
|
||||
|
||||
/*
|
||||
虚拟过滤器链执行完毕后交由原生过滤器继续执行
|
||||
*/
|
||||
chain.doFilter(request, response);
|
||||
|
||||
log.debug("[AUTHORIZ] **Proxy** >> 原生过滤器: request 请求结束");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,31 +1,31 @@
|
||||
//package com.blossom.backend.base.auth.redis;
|
||||
//
|
||||
//import cn.hutool.core.lang.UUID;
|
||||
//import com.blossom.backend.base.auth.pojo.AccessToken;
|
||||
//import com.blossom.backend.base.auth.token.TokenEncoder;
|
||||
//import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
//import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
//import org.springframework.data.redis.core.RedisTemplate;
|
||||
//import org.springframework.stereotype.Component;
|
||||
//
|
||||
///**
|
||||
// * token 编解码器, 简单生成一个 UUID token, 与 token 信息无加解密, 编解码关系
|
||||
// *
|
||||
// * @author xzzz
|
||||
// */
|
||||
//@Component
|
||||
//@ConditionalOnClass(RedisTemplate.class)
|
||||
//@ConditionalOnProperty(value = "project.auth.type", havingValue = "redis")
|
||||
//public class RedisTokenEncoder implements TokenEncoder {
|
||||
//
|
||||
// /**
|
||||
// * 生成一个 uuid 作为 token
|
||||
// *
|
||||
// * @param accessToken token
|
||||
// * @return uuid
|
||||
// */
|
||||
// @Override
|
||||
// public String encode(AccessToken accessToken) {
|
||||
// return UUID.randomUUID().toString(true);
|
||||
// }
|
||||
//}
|
||||
package com.blossom.backend.base.auth.redis;
|
||||
|
||||
import cn.hutool.core.lang.UUID;
|
||||
import com.blossom.backend.base.auth.pojo.AccessToken;
|
||||
import com.blossom.backend.base.auth.token.TokenEncoder;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* token 编解码器, 简单生成一个 UUID token, 与 token 信息无加解密, 编解码关系
|
||||
*
|
||||
* @author xzzz
|
||||
*/
|
||||
@Component
|
||||
@ConditionalOnClass(RedisTemplate.class)
|
||||
@ConditionalOnProperty(value = "project.auth.type", havingValue = "redis")
|
||||
public class RedisTokenEncoder implements TokenEncoder {
|
||||
|
||||
/**
|
||||
* 生成一个 uuid 作为 token
|
||||
*
|
||||
* @param accessToken token
|
||||
* @return uuid
|
||||
*/
|
||||
@Override
|
||||
public String encode(AccessToken accessToken) {
|
||||
return UUID.randomUUID().toString(true);
|
||||
}
|
||||
}
|
||||
|
@ -1,85 +1,96 @@
|
||||
//package com.blossom.backend.base.auth.redis;
|
||||
//
|
||||
//import cn.hutool.core.util.StrUtil;
|
||||
//import com.blossom.backend.base.auth.TokenUtil;
|
||||
//import com.blossom.backend.base.auth.pojo.AccessToken;
|
||||
//import com.blossom.backend.base.auth.repo.TokenRepository;
|
||||
//import com.blossom.common.base.exception.XzException500;
|
||||
//import com.blossom.common.base.util.json.JsonUtil;
|
||||
//import lombok.extern.slf4j.Slf4j;
|
||||
//import org.springframework.beans.factory.annotation.Autowired;
|
||||
//import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
//import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
//import org.springframework.data.redis.core.RedisTemplate;
|
||||
//import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
//import org.springframework.scheduling.annotation.Async;
|
||||
//import org.springframework.stereotype.Component;
|
||||
//
|
||||
//import java.util.concurrent.TimeUnit;
|
||||
//
|
||||
///**
|
||||
// * redis token 存储
|
||||
// *
|
||||
// * @author xzzz
|
||||
// */
|
||||
//@Slf4j
|
||||
//@Component
|
||||
//@ConditionalOnClass(RedisTemplate.class)
|
||||
//@ConditionalOnProperty(value = "project.auth.type", havingValue = "redis")
|
||||
//public class RedisTokenRepository implements TokenRepository {
|
||||
//
|
||||
// @Autowired
|
||||
// private StringRedisTemplate redisTemplate;
|
||||
//
|
||||
// @Override
|
||||
// public void saveToken(AccessToken accessToken) {
|
||||
// if (accessToken == null || StrUtil.isBlank(accessToken.getToken())) {
|
||||
// throw new XzException500("无法保存空的AccessToken");
|
||||
// }
|
||||
// redisTemplate.opsForValue().set(
|
||||
// TokenUtil.buildTokenKey(accessToken.getToken()),
|
||||
// JsonUtil.toJson(accessToken),
|
||||
// accessToken.getDuration(),
|
||||
// TimeUnit.SECONDS);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public AccessToken getToken(String token) {
|
||||
// if (StrUtil.isBlank(token)) {
|
||||
// return null;
|
||||
// }
|
||||
// return JsonUtil.toObj(redisTemplate.opsForValue().get(TokenUtil.buildTokenKey(token)), AccessToken.class);
|
||||
// }
|
||||
//
|
||||
// @Async
|
||||
// @Override
|
||||
// public void remove(String token) {
|
||||
// log.info("异步删除 token");
|
||||
// redisTemplate.delete(TokenUtil.buildTokenKey(token));
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void saveUniqueToken(AccessToken accessToken) {
|
||||
// if (accessToken == null || StrUtil.isBlank(accessToken.getToken())) {
|
||||
// throw new XzException500("无法保存空的AccessToken");
|
||||
// }
|
||||
//
|
||||
// if (accessToken.getMultiPlaceLogin()) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// redisTemplate.opsForValue().set(
|
||||
// TokenUtil.buildUniqueTokenKey(String.valueOf(accessToken.getUserId())),
|
||||
// accessToken.getToken(),
|
||||
// accessToken.getDuration(),
|
||||
// TimeUnit.SECONDS);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String getUniqueToken(String userId) {
|
||||
// if (StrUtil.isBlank(userId)) {
|
||||
// return null;
|
||||
// }
|
||||
// return redisTemplate.opsForValue().get(TokenUtil.buildUniqueTokenKey(userId));
|
||||
// }
|
||||
//}
|
||||
package com.blossom.backend.base.auth.redis;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.blossom.backend.base.auth.TokenUtil;
|
||||
import com.blossom.backend.base.auth.pojo.AccessToken;
|
||||
import com.blossom.backend.base.auth.repo.TokenRepository;
|
||||
import com.blossom.common.base.exception.XzException500;
|
||||
import com.blossom.common.base.util.json.JsonUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* redis token 存储
|
||||
*
|
||||
* @author xzzz
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@ConditionalOnClass(RedisTemplate.class)
|
||||
@ConditionalOnProperty(value = "project.auth.type", havingValue = "redis")
|
||||
public class RedisTokenRepository implements TokenRepository {
|
||||
|
||||
@Autowired
|
||||
private StringRedisTemplate redisTemplate;
|
||||
|
||||
@Override
|
||||
public void saveToken(AccessToken accessToken) {
|
||||
if (accessToken == null || StrUtil.isBlank(accessToken.getToken())) {
|
||||
throw new XzException500("无法保存空的AccessToken");
|
||||
}
|
||||
redisTemplate.opsForValue().set(
|
||||
TokenUtil.buildTokenKey(accessToken.getToken()),
|
||||
JsonUtil.toJson(accessToken),
|
||||
accessToken.getDuration(),
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessToken getToken(String token) {
|
||||
if (StrUtil.isBlank(token)) {
|
||||
return null;
|
||||
}
|
||||
return JsonUtil.toObj(redisTemplate.opsForValue().get(TokenUtil.buildTokenKey(token)), AccessToken.class);
|
||||
}
|
||||
|
||||
@Async
|
||||
@Override
|
||||
public void remove(String token) {
|
||||
log.info("异步删除 token");
|
||||
redisTemplate.delete(TokenUtil.buildTokenKey(token));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAll(Long userId) {
|
||||
// redisTemplate.delete(userId);
|
||||
// Map<String, AccessToken> maps = tokenCache.asMap();
|
||||
// maps.forEach((k, t) -> {
|
||||
// if (t.getUserId().equals(userId)) {
|
||||
// tokenCache.invalidate(k);
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveUniqueToken(AccessToken accessToken) {
|
||||
if (accessToken == null || StrUtil.isBlank(accessToken.getToken())) {
|
||||
throw new XzException500("无法保存空的AccessToken");
|
||||
}
|
||||
|
||||
if (accessToken.getMultiPlaceLogin()) {
|
||||
return;
|
||||
}
|
||||
|
||||
redisTemplate.opsForValue().set(
|
||||
TokenUtil.buildUniqueTokenKey(String.valueOf(accessToken.getUserId())),
|
||||
accessToken.getToken(),
|
||||
accessToken.getDuration(),
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueToken(String userId) {
|
||||
if (StrUtil.isBlank(userId)) {
|
||||
return null;
|
||||
}
|
||||
return redisTemplate.opsForValue().get(TokenUtil.buildUniqueTokenKey(userId));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,21 @@
|
||||
package com.blossom.backend.config;
|
||||
|
||||
import com.blossom.common.base.exception.XzExceptionSys;
|
||||
import com.blossom.common.cache.CacheTypeEnum;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
|
||||
/**
|
||||
* 系统参数初始化
|
||||
*/
|
||||
public class ContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
|
||||
|
||||
@Override
|
||||
public void initialize(ConfigurableApplicationContext applicationContext) {
|
||||
ConfigurableEnvironment environment = applicationContext.getEnvironment();
|
||||
boolean enabled = Boolean.parseBoolean(environment.getProperty("project.base.enabled.redis"));
|
||||
boolean status = CacheTypeEnum.redis.name().equals(environment.getProperty("project.cache.type")) && !enabled;
|
||||
XzExceptionSys.throwBy(status, "请在配置文件中开启 redis 【project.base.enabled.redis】");
|
||||
}
|
||||
}
|
@ -3,17 +3,15 @@ package com.blossom.backend.server.article.draft;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import com.blossom.common.base.exception.XzException400;
|
||||
import com.blossom.common.base.util.security.SHA256Util;
|
||||
import com.blossom.common.cache.caffeine.DynamicExpiry;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.RemovalCause;
|
||||
import com.blossom.common.cache.CacheService;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Objects;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 文章临时访问
|
||||
@ -24,18 +22,9 @@ import java.util.concurrent.TimeUnit;
|
||||
@Service
|
||||
public class ArticleTempVisitService {
|
||||
|
||||
/**
|
||||
* 存放文章ID的缓存
|
||||
*
|
||||
* @since 1.13.0 支持动态过期时间
|
||||
*/
|
||||
private final Cache<String, TempVisit> tempVisitCache = Caffeine.newBuilder()
|
||||
.expireAfter(new DynamicExpiry())
|
||||
.initialCapacity(500)
|
||||
.removalListener((String key, TempVisit value, RemovalCause cause) ->
|
||||
log.info("remove temp visit articleId [" + Objects.requireNonNull(value).getArticleId() + "]")
|
||||
)
|
||||
.build();
|
||||
@Lazy
|
||||
@Resource
|
||||
private CacheService<String, TempVisit> cacheService;
|
||||
|
||||
/**
|
||||
* 生成一个缓存 key, key 并非文章的摘要码,
|
||||
@ -48,9 +37,8 @@ public class ArticleTempVisitService {
|
||||
public String create(Long articleId, Long userId, Long duration) {
|
||||
XzException400.throwBy(ObjUtil.isNull(articleId), "文章ID为必填项");
|
||||
String key = SHA256Util.encode(UUID.randomUUID().toString());
|
||||
tempVisitCache.policy().expireVariably().ifPresent(e -> {
|
||||
e.put(key, new TempVisit(articleId, userId), duration, TimeUnit.MINUTES);
|
||||
});
|
||||
TempVisit value = new TempVisit(articleId, userId);
|
||||
cacheService.put(key, value, duration * 60);
|
||||
return key;
|
||||
}
|
||||
|
||||
@ -62,13 +50,14 @@ public class ArticleTempVisitService {
|
||||
* @return 文章ID, 文章ID不存在时返回 null
|
||||
*/
|
||||
public TempVisit get(String key) {
|
||||
return tempVisitCache.getIfPresent(key);
|
||||
return cacheService.get(key,TempVisit.class).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 临时访问对象
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public static class TempVisit {
|
||||
/**
|
||||
* 文章ID
|
||||
|
@ -3,45 +3,38 @@ package com.blossom.backend.server.article.draft;
|
||||
import com.blossom.backend.server.doc.DocService;
|
||||
import com.blossom.backend.server.folder.FolderTypeEnum;
|
||||
import com.blossom.common.base.exception.XzException500;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.RemovalCause;
|
||||
import lombok.AllArgsConstructor;
|
||||
import com.blossom.common.cache.CacheService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
public class ImportManager {
|
||||
|
||||
private final DocService docService;
|
||||
@Autowired
|
||||
private DocService docService;
|
||||
|
||||
private final ReentrantLock LOCK = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* 批量导入时的批次缓存, 一个批次的导入只会从数据库获取一次排序, 后续排序从缓存中递增
|
||||
*/
|
||||
private final Cache<String, AtomicInteger> batchCache = Caffeine.newBuilder()
|
||||
.initialCapacity(50)
|
||||
.expireAfterWrite(120, TimeUnit.MINUTES)
|
||||
.removalListener((String location, AtomicInteger i, RemovalCause cause) ->
|
||||
log.info("batch import [" + location + "] has been deleted")
|
||||
)
|
||||
.build();
|
||||
@Resource
|
||||
private CacheService<String, AtomicInteger> cacheService;
|
||||
|
||||
/**
|
||||
* 并发导入时的排序获取
|
||||
*/
|
||||
public Integer getSort(String batchId, Long pid, Long userId) {
|
||||
AtomicInteger sort = batchCache.getIfPresent(batchId);
|
||||
AtomicInteger sort = cacheService.get(batchId, AtomicInteger.class).orElse(null);
|
||||
if (null == sort) {
|
||||
try {
|
||||
LOCK.tryLock(1000, TimeUnit.MILLISECONDS);
|
||||
sort = batchCache.getIfPresent(batchId);
|
||||
sort = cacheService.get(batchId, AtomicInteger.class).orElse(null);
|
||||
if (null == sort) {
|
||||
sort = initBatchCount(batchId, pid, userId);
|
||||
}
|
||||
@ -58,7 +51,7 @@ public class ImportManager {
|
||||
private AtomicInteger initBatchCount(String batchId, Long pid, Long userId) {
|
||||
System.out.println("初始化导入排序");
|
||||
AtomicInteger i = new AtomicInteger(docService.selectMaxSortByPid(pid, userId, FolderTypeEnum.ARTICLE) + 1);
|
||||
batchCache.put(batchId, i);
|
||||
cacheService.put(batchId, i, 120 * 60L);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
@ -9,19 +9,19 @@ import com.blossom.backend.thirdparty.hefeng.pojo.*;
|
||||
import com.blossom.common.base.exception.XzException400;
|
||||
import com.blossom.common.base.util.json.JsonUtil;
|
||||
import com.blossom.common.base.util.okhttp.HttpUtil;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.RemovalCause;
|
||||
import com.blossom.common.cache.CacheService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 天气查询
|
||||
@ -42,16 +42,9 @@ public class WeatherManager {
|
||||
private static final String URL_HOURLY = "https://devapi.heweather.net/v7/weather/24h";
|
||||
private static final String SUCCESS = "200";
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private final Cache<String, WeatherRes> weatherCache = Caffeine.newBuilder()
|
||||
.initialCapacity(50)
|
||||
.expireAfterWrite(45, TimeUnit.MINUTES)
|
||||
.removalListener((String location, WeatherRes weather, RemovalCause cause) ->
|
||||
log.info("Weather cache [" + location + "] has been deleted")
|
||||
)
|
||||
.build();
|
||||
@Lazy
|
||||
@Resource
|
||||
private CacheService<String, WeatherRes> cacheService;
|
||||
|
||||
@Autowired
|
||||
private ParamService paramService;
|
||||
@ -59,12 +52,8 @@ public class WeatherManager {
|
||||
/**
|
||||
* 查询天气信息
|
||||
*/
|
||||
@Cacheable(cacheNames = "weather:location", key = "#location")
|
||||
public WeatherRes findWeatherAll(String location) {
|
||||
WeatherRes cache = weatherCache.getIfPresent(location);
|
||||
if (cache != null) {
|
||||
log.debug("[BLOSSOM] get weather from cache: {}", location);
|
||||
return cache;
|
||||
}
|
||||
log.info("[BLOSSOM] refresh weather: {}", location);
|
||||
Map<String, String> maps = initParam(location);
|
||||
if (maps == null) {
|
||||
@ -143,7 +132,6 @@ public class WeatherManager {
|
||||
} else {
|
||||
log.error("获取小时预报失败, resp: {}", cityStr);
|
||||
}
|
||||
weatherCache.put(location, weather);
|
||||
return weather;
|
||||
}
|
||||
|
||||
@ -151,7 +139,7 @@ public class WeatherManager {
|
||||
* 清除缓存
|
||||
*/
|
||||
public void clear(String location) {
|
||||
weatherCache.invalidate(location);
|
||||
cacheService.remove(location);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -6,6 +6,12 @@ spring:
|
||||
password: jasmine888
|
||||
hikari:
|
||||
max-lifetime: 120000
|
||||
redis:
|
||||
database: 0
|
||||
host: 127.0.0.1
|
||||
password:
|
||||
port: 6379
|
||||
timeout: 3000 # 连接超时时间 单位 ms(毫秒)
|
||||
|
||||
logging:
|
||||
level:
|
||||
@ -29,6 +35,8 @@ logging:
|
||||
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ project ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
project:
|
||||
base:
|
||||
enabled:
|
||||
redis: false #是否需要使用 redis
|
||||
time-zone: GMT+8
|
||||
version: @project.version@
|
||||
ex:
|
||||
@ -64,6 +72,8 @@ project:
|
||||
- /assets/**
|
||||
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ Cache/Redis ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
cache: # 缓存
|
||||
#项目的缓存方式 redis/caffeine
|
||||
type: caffeine
|
||||
names-config: # 缓存键超时时间配置
|
||||
- name: test_cache1
|
||||
seconds: 10
|
||||
@ -86,4 +96,4 @@ project:
|
||||
# 请以 /pic 结尾, 如果你在 nginx 中配置有代理, 注意别忘了添加你的代理路径
|
||||
domain: "http://www.google.com/"
|
||||
# 请以 / 开头, / 结尾, 简短的路径在文章中有更好的显示效果, 过长一定程度会使文章内容混乱
|
||||
default-path: "/home/bl/img/"
|
||||
default-path: "/home/bl/img/"
|
||||
|
@ -6,6 +6,12 @@ spring:
|
||||
password: jasmine888
|
||||
hikari:
|
||||
max-lifetime: 120000
|
||||
redis:
|
||||
database: 1
|
||||
host: 127.0.0.1
|
||||
password:
|
||||
port: 6379
|
||||
timeout: 3000 # 连接超时时间 单位 ms(毫秒)
|
||||
|
||||
logging:
|
||||
level:
|
||||
@ -20,6 +26,8 @@ logging:
|
||||
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ project ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
project:
|
||||
base:
|
||||
enabled:
|
||||
redis: false #是否需要使用 redis
|
||||
time-zone: GMT+8
|
||||
version: @project.version@
|
||||
ex:
|
||||
@ -30,9 +38,9 @@ project:
|
||||
# 动态日志级别配置
|
||||
log:
|
||||
duration: 600000 # 动态日志级别 6 分钟后失效
|
||||
restore-duration: 30000 # 30 秒判断一次是否失效
|
||||
restore-duration: 5000 # 30 秒判断一次是否失效
|
||||
db:
|
||||
slow-interval: 200 # 慢SQL
|
||||
slow-interval: 500 # 慢SQL
|
||||
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ Auth ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
auth: # 授权
|
||||
enabled: true # 开启授权
|
||||
@ -56,6 +64,8 @@ project:
|
||||
- /assets/**
|
||||
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ Cache/Redis ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
cache: # 缓存
|
||||
#项目的缓存方式 redis/caffeine
|
||||
type: caffeine
|
||||
names-config: # 缓存键超时时间配置
|
||||
- name: test_cache1
|
||||
seconds: 10
|
||||
@ -79,4 +89,4 @@ project:
|
||||
# 注意:在下方示例中, /bl 即为 nginx 反向代理路径, 如果你的访问路径中不包含反向代理或路径不同, 请酌情删除或修改
|
||||
domain: "http://www.google.com/"
|
||||
# 请以 / 开头, / 结尾, 简短的路径在文章中有更好的显示效果, 过长一定程度会使文章内容混乱
|
||||
default-path: "/home/bl/img/"
|
||||
default-path: "/home/bl/img/"
|
||||
|
@ -9,6 +9,12 @@ spring:
|
||||
password: jasmine888
|
||||
hikari:
|
||||
max-lifetime: 120000
|
||||
redis:
|
||||
database: 0
|
||||
host: 127.0.0.1
|
||||
password:
|
||||
port: 6379
|
||||
timeout: 3000 # 连接超时时间 单位 ms(毫秒)
|
||||
|
||||
logging:
|
||||
level:
|
||||
@ -23,6 +29,8 @@ logging:
|
||||
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ project ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
project:
|
||||
base:
|
||||
enabled:
|
||||
redis: false #是否需要使用 redis
|
||||
time-zone: GMT+8
|
||||
version: @project.version@
|
||||
ex:
|
||||
@ -58,6 +66,8 @@ project:
|
||||
- /assets/**
|
||||
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ Cache/Redis ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
cache: # 缓存
|
||||
#项目的缓存方式 redis/caffeine
|
||||
type: caffeine
|
||||
names-config: # 缓存键超时时间配置
|
||||
- name: test_cache1
|
||||
seconds: 10
|
||||
@ -81,4 +91,4 @@ project:
|
||||
# 注意:在下方示例中, /bl 即为 nginx 反向代理路径, 如果你的访问路径中不包含反向代理或路径不同, 请酌情删除或修改
|
||||
domain: "https://www.wangyunf.com/blall/pic/"
|
||||
# 请以 / 开头, / 结尾, 简短的路径在文章中有更好的显示效果, 过长一定程度会使文章内容混乱
|
||||
default-path: "/home/blall/img/"
|
||||
default-path: "/home/blall/img/"
|
||||
|
@ -27,6 +27,11 @@ public class BaseProperties {
|
||||
*/
|
||||
private String version = "xyz";
|
||||
|
||||
/**
|
||||
* 中间件启用配置
|
||||
*/
|
||||
private Enabled enabled = new Enabled();
|
||||
|
||||
/**
|
||||
* 异常处理信息配置
|
||||
*/
|
||||
@ -37,6 +42,16 @@ public class BaseProperties {
|
||||
*/
|
||||
private Log log = new Log();
|
||||
|
||||
@Data
|
||||
public static class Enabled {
|
||||
|
||||
/**
|
||||
* 是否开启 Redis
|
||||
*/
|
||||
private Boolean redis = false;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Ex {
|
||||
/**
|
||||
|
@ -0,0 +1,27 @@
|
||||
package com.blossom.common.base.exception;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.blossom.common.base.pojo.RCode;
|
||||
|
||||
/**
|
||||
* @author xzzz
|
||||
*/
|
||||
public class XzExceptionSys extends XzAbstractException {
|
||||
|
||||
public XzExceptionSys(String message) {
|
||||
super(RCode.SYSTEM_INITIATE_ERROR.getCode(), message);
|
||||
}
|
||||
|
||||
public XzExceptionSys(String message, String... args) {
|
||||
super(RCode.SYSTEM_INITIATE_ERROR.getCode(), String.format(message, args));
|
||||
}
|
||||
|
||||
public static void throwBy(boolean expression, String msg) {
|
||||
if (expression) {
|
||||
if (StrUtil.isBlank(msg)) {
|
||||
msg = RCode.SYSTEM_INITIATE_ERROR.getMsg();
|
||||
}
|
||||
throw new XzExceptionSys(msg);
|
||||
}
|
||||
}
|
||||
}
|
@ -35,6 +35,9 @@ public enum RCode implements IRCode {
|
||||
|
||||
/* ──────────────────────────────────────────── 503 ────────────────────────────────────────*/
|
||||
SERVER_UNAVAILABLE ("50300", "服务器暂时无法处理请求, 请稍后再试"),
|
||||
|
||||
/* ──────────────────────────────────────────── 900 ────────────────────────────────────────*/
|
||||
SYSTEM_INITIATE_ERROR("90001", "系统启动失败"),
|
||||
;
|
||||
|
||||
@Getter
|
||||
|
@ -5,7 +5,6 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.blossom.common.base.config.WebMvcConfig,\
|
||||
com.blossom.common.base.exception.ExceptionAdviceByGlobal,\
|
||||
com.blossom.common.base.exception.ExceptionAdviceByXz,\
|
||||
com.blossom.common.base.util.spring.SpringUtil,\
|
||||
com.blossom.common.base.log.DynamicLogRepositoryCaffeine
|
||||
com.blossom.common.base.util.spring.SpringUtil
|
||||
|
||||
|
||||
|
24
blossom-backend/common/common-cache/src/main/java/com/blossom/common/cache/CacheService.java
vendored
Normal file
24
blossom-backend/common/common-cache/src/main/java/com/blossom/common/cache/CacheService.java
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
package com.blossom.common.cache;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 抽象缓存接口
|
||||
*
|
||||
* @param <K> 缓存Key
|
||||
* @param <V> 缓存值
|
||||
*/
|
||||
public interface CacheService<K, V> {
|
||||
void put(K key, V value);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param key
|
||||
* @param value
|
||||
* @param expirationInSeconds 过期时间(秒)
|
||||
*/
|
||||
void put(K key, V value, Long expirationInSeconds);
|
||||
Optional<V> get(K key, Class<V> valueType);
|
||||
void remove(K key);
|
||||
void removeAll();
|
||||
}
|
12
blossom-backend/common/common-cache/src/main/java/com/blossom/common/cache/CacheTypeEnum.java
vendored
Normal file
12
blossom-backend/common/common-cache/src/main/java/com/blossom/common/cache/CacheTypeEnum.java
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
package com.blossom.common.cache;
|
||||
|
||||
/**
|
||||
* 缓存类型
|
||||
*
|
||||
*/
|
||||
public enum CacheTypeEnum {
|
||||
redis,
|
||||
|
||||
caffeine,
|
||||
|
||||
}
|
@ -17,6 +17,11 @@ import java.util.List;
|
||||
@ConfigurationProperties(prefix = "project.cache")
|
||||
public class CommonCacheProperties {
|
||||
|
||||
/**
|
||||
* 缓存类型 redis/caffeine
|
||||
*/
|
||||
private CacheTypeEnum type = CacheTypeEnum.caffeine;
|
||||
|
||||
/**
|
||||
* 缓存的 key 配置
|
||||
*/
|
||||
|
@ -5,7 +5,7 @@ import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.RemovalCause;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.cache.caffeine.CaffeineCacheManager;
|
||||
@ -20,7 +20,7 @@ import java.util.concurrent.TimeUnit;
|
||||
*/
|
||||
@Slf4j
|
||||
@EnableCaching
|
||||
@ConditionalOnMissingClass("org.springframework.data.redis.core.RedisTemplate")
|
||||
@ConditionalOnProperty(value = "project.cache.type", havingValue = "caffeine")
|
||||
public class CaffeineCacheConfig {
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,57 @@
|
||||
package com.blossom.common.cache.caffeine;
|
||||
|
||||
import com.blossom.common.cache.CacheService;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Caffeine 缓存操作
|
||||
* @param <K>
|
||||
* @param <V>
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
@ConditionalOnProperty(value = "project.cache.type", havingValue = "caffeine")
|
||||
public class CaffeineCacheService<K, V> implements CacheService<K, V> {
|
||||
private final Cache<K, V> cache;
|
||||
|
||||
@Autowired
|
||||
public CaffeineCacheService() {
|
||||
log.info("[ CACHE] 业务缓存使用 : Caffeine");
|
||||
cache = Caffeine.newBuilder().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, V value) {
|
||||
cache.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, V value, Long expirationInSeconds) {
|
||||
cache.policy().expireVariably().ifPresent(e -> e.put(key, value, expirationInSeconds, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<V> get(K key, Class<V> valueType) {
|
||||
return Optional.ofNullable(cache.getIfPresent(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(K key) {
|
||||
cache.invalidate(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAll() {
|
||||
cache.invalidateAll();
|
||||
}
|
||||
}
|
@ -1,11 +1,13 @@
|
||||
package com.blossom.common.base.log;
|
||||
package com.blossom.common.cache.caffeine;
|
||||
|
||||
import com.blossom.common.base.BaseProperties;
|
||||
import com.blossom.common.base.log.DynamicLogRepository;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.RemovalCause;
|
||||
import com.blossom.common.base.BaseProperties;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.logging.LogLevel;
|
||||
import org.springframework.boot.logging.LoggingSystem;
|
||||
import org.springframework.stereotype.Component;
|
||||
@ -21,7 +23,7 @@ import java.util.concurrent.TimeUnit;
|
||||
*/
|
||||
@Slf4j
|
||||
@Component("dynamicLogRepositoryCaffeine")
|
||||
@ConditionalOnMissingClass("org.springframework.data.redis.core.RedisTemplate")
|
||||
@ConditionalOnProperty(value = "project.cache.type", havingValue = "caffeine")
|
||||
public class DynamicLogRepositoryCaffeine implements DynamicLogRepository {
|
||||
|
||||
private final LoggingSystem loggingSystem;
|
||||
@ -29,7 +31,7 @@ public class DynamicLogRepositoryCaffeine implements DynamicLogRepository {
|
||||
private final ScheduledExecutorService clearUpScheduled = Executors.newScheduledThreadPool(1);
|
||||
|
||||
public DynamicLogRepositoryCaffeine(LoggingSystem loggingSystem, BaseProperties properties) {
|
||||
log.debug("[ BASE] 日志级别存储 : Caffeine, 配置持续时长[{}ms], 刷新间隔[{}ms]",
|
||||
log.info("[ BASE] 日志级别存储 : Caffeine, 配置持续时长[{}ms], 刷新间隔[{}ms]",
|
||||
properties.getLog().getDuration(), properties.getLog().getRestoreDuration());
|
||||
cache = Caffeine.newBuilder()
|
||||
.initialCapacity(100)
|
@ -7,12 +7,12 @@ import com.blossom.common.base.util.json.JsonUtil;
|
||||
import com.blossom.common.base.util.spring.SpringUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.logging.LogLevel;
|
||||
import org.springframework.boot.logging.LoggingSystem;
|
||||
import org.springframework.data.redis.connection.Message;
|
||||
import org.springframework.data.redis.connection.MessageListener;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.data.redis.listener.ChannelTopic;
|
||||
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||
@ -32,7 +32,7 @@ import java.util.concurrent.TimeUnit;
|
||||
*/
|
||||
@Slf4j
|
||||
@Component("DynamicLogRepositoryRedis")
|
||||
@ConditionalOnClass(RedisTemplate.class)
|
||||
@ConditionalOnProperty(value = "project.cache.type", havingValue = "redis")
|
||||
public class DynamicLogRepositoryRedis implements DynamicLogRepository {
|
||||
|
||||
private final StringRedisTemplate redisTemplate;
|
||||
|
@ -3,14 +3,14 @@ package com.blossom.common.cache.redis;
|
||||
import com.blossom.common.base.util.json.JsonUtil;
|
||||
import com.blossom.common.cache.CommonCacheProperties;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
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.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.RedisSerializationContext;
|
||||
|
||||
@ -26,7 +26,7 @@ import java.util.Map;
|
||||
*/
|
||||
@Slf4j
|
||||
@EnableCaching
|
||||
@ConditionalOnClass(RedisTemplate.class)
|
||||
@ConditionalOnProperty(value = "project.cache.type", havingValue = "redis")
|
||||
public class RedisCacheConfig {
|
||||
|
||||
private static final Integer DEFAULT_TIME_OUT = 60 * 60 * 4;
|
||||
|
@ -0,0 +1,67 @@
|
||||
package com.blossom.common.cache.redis;
|
||||
|
||||
import com.blossom.common.base.util.json.JsonUtil;
|
||||
import com.blossom.common.cache.CacheService;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.type.TypeFactory;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.data.redis.core.RedisCallback;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Redis 缓存操作
|
||||
* @param <K>
|
||||
* @param <V>
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
@ConditionalOnProperty(value = "project.cache.type", havingValue = "redis")
|
||||
public class RedisCacheService<K, V> implements CacheService<K, V> {
|
||||
public RedisCacheService() {
|
||||
log.info("[ CACHE] 业务缓存使用 : Redis");
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate<K, String> redisTemplate;
|
||||
|
||||
@Override
|
||||
public void put(K key, V value) {
|
||||
redisTemplate.opsForValue().set(key, JsonUtil.toJson(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, V value, Long expirationInSeconds) {
|
||||
redisTemplate.opsForValue().set(key, JsonUtil.toJson(value));
|
||||
redisTemplate.expire(key, expirationInSeconds, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<V> get(K key, Class<V> valueType) {
|
||||
return Optional.ofNullable(JsonUtil.toObj(redisTemplate.opsForValue().get(key), valueType));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void remove(K key) {
|
||||
redisTemplate.delete(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAll() {
|
||||
redisTemplate.execute((RedisCallback<Object>) connection -> {
|
||||
connection.flushDb();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.blossom.common.cache.redis;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@ -10,6 +11,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
*/
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "project.redis")
|
||||
@ConditionalOnProperty(value = "project.base.enabled.redis", havingValue = "true")
|
||||
public class RedisProperties {
|
||||
|
||||
}
|
||||
|
@ -1,8 +1,11 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.blossom.common.cache.CommonCacheProperties,\
|
||||
com.blossom.common.cache.caffeine.CaffeineCacheConfig,\
|
||||
com.blossom.common.cache.caffeine.CaffeineCacheService,\
|
||||
com.blossom.common.cache.redis.RedisProperties,\
|
||||
com.blossom.common.cache.redis.RedisCacheConfig,\
|
||||
com.blossom.common.cache.redis.RedisCacheService,\
|
||||
com.blossom.common.cache.redis.RedisConfiguration,\
|
||||
com.blossom.common.cache.redis.DynamicLogRepositoryRedis
|
||||
com.blossom.common.cache.redis.DynamicLogRepositoryRedis,\
|
||||
com.blossom.common.cache.caffeine.DynamicLogRepositoryCaffeine
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user