|
|
@@ -13,8 +13,10 @@ import org.springframework.stereotype.Service;
|
|
|
import org.springframework.web.client.RestTemplate;
|
|
|
import org.springframework.util.StreamUtils;
|
|
|
import com.etotem.cfc.service.api.WechatServiceInterface;
|
|
|
+import org.springframework.data.redis.core.RedisTemplate;
|
|
|
|
|
|
import javax.annotation.PostConstruct;
|
|
|
+import javax.annotation.Resource;
|
|
|
import javax.crypto.Cipher;
|
|
|
import javax.crypto.spec.IvParameterSpec;
|
|
|
import javax.crypto.spec.SecretKeySpec;
|
|
|
@@ -32,6 +34,7 @@ import java.util.Base64;
|
|
|
import java.util.HashMap;
|
|
|
import java.util.Map;
|
|
|
import java.util.UUID;
|
|
|
+import java.time.Duration;
|
|
|
|
|
|
@Service
|
|
|
public class WechatService implements WechatServiceInterface {
|
|
|
@@ -81,6 +84,13 @@ public class WechatService implements WechatServiceInterface {
|
|
|
return new RestTemplate(factory);
|
|
|
}
|
|
|
|
|
|
+ @Resource
|
|
|
+ private RedisTemplate<String, Object> redisTemplate;
|
|
|
+
|
|
|
+ /** Redis access_token 缓存 key 与 TTL(秒) */
|
|
|
+ private static final String STABLE_TOKEN_KEY = "wechat:stable_access_token";
|
|
|
+ private static final long STABLE_TOKEN_TTL_SECONDS = 7000;
|
|
|
+
|
|
|
// ===== stable access_token 缓存(独立缓存,用于避免"not latest"冲突)=====
|
|
|
private volatile String cachedStableAccessToken;
|
|
|
private volatile long stableTokenExpireTime;
|
|
|
@@ -268,9 +278,28 @@ public class WechatService implements WechatServiceInterface {
|
|
|
if (cachedStableAccessToken != null && now < stableTokenExpireTime) {
|
|
|
return cachedStableAccessToken;
|
|
|
}
|
|
|
+ // 内存未命中:优先从 Redis 读取(多实例共享同一 token,避免重复请求微信)
|
|
|
+ try {
|
|
|
+ Object cached = redisTemplate.opsForValue().get(STABLE_TOKEN_KEY);
|
|
|
+ if (cached != null) {
|
|
|
+ String token = cached.toString();
|
|
|
+ cachedStableAccessToken = token;
|
|
|
+ stableTokenExpireTime = now + STABLE_TOKEN_TTL_SECONDS * 1000;
|
|
|
+ return token;
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("Redis 读取 access_token 失败,走微信接口: {}", e.getMessage());
|
|
|
+ }
|
|
|
String token = doGetStableAccessToken();
|
|
|
cachedStableAccessToken = token;
|
|
|
- stableTokenExpireTime = now + 7000 * 1000;
|
|
|
+ stableTokenExpireTime = now + STABLE_TOKEN_TTL_SECONDS * 1000;
|
|
|
+ // 回写 Redis 供多实例共享;失败不影响本次请求
|
|
|
+ try {
|
|
|
+ redisTemplate.opsForValue().set(STABLE_TOKEN_KEY, token,
|
|
|
+ Duration.ofSeconds(STABLE_TOKEN_TTL_SECONDS));
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("Redis 写入 access_token 失败(不影响本次请求): {}", e.getMessage());
|
|
|
+ }
|
|
|
return token;
|
|
|
}
|
|
|
}
|
|
|
@@ -284,6 +313,11 @@ public class WechatService implements WechatServiceInterface {
|
|
|
public synchronized void invalidateAccessToken() {
|
|
|
cachedStableAccessToken = null;
|
|
|
stableTokenExpireTime = 0;
|
|
|
+ try {
|
|
|
+ redisTemplate.delete(STABLE_TOKEN_KEY);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("Redis 删除 access_token 失败(忽略): {}", e.getMessage());
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|