wlzboy
4 天以前 cfe0b79fbea0fb1d7a5a796e71ada7d3b7812046
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package com.ruoyi.system.service.impl;
 
import com.ruoyi.common.config.WechatConfig;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.WechatUtils;
import com.ruoyi.system.domain.SysConfig;
import com.ruoyi.system.mapper.SysConfigMapper;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.IWechatAccessTokenService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
/**
 * 微信AccessToken服务实现
 * 提供应用级AccessToken的统一管理,使用sys_config表缓存
 * 
 * @author ruoyi
 * @date 2025-12-04
 */
@Service
public class WechatAccessTokenServiceImpl implements IWechatAccessTokenService {
    
    private static final Logger log = LoggerFactory.getLogger(WechatAccessTokenServiceImpl.class);
    
    @Autowired
    private WechatConfig wechatConfig;
    
    @Autowired
    private ISysConfigService configService;
    
    @Autowired
    private SysConfigMapper configMapper;
    
    /**
     * 获取应用级微信AccessToken(带缓存)
     * 优先从sys_config读取并判断有效期;过期则重新获取并写回sys_config
     */
    @Override
    public String getAppAccessToken() {
        try {
            String appId = wechatConfig.getAppId();
            String tokenKey = "weixin.access_token." + appId;
            String expireKey = "weixin.access_token_expires." + appId;
            
            String cachedToken = configService.selectConfigByKey(tokenKey);
            String cachedExpireStr = configService.selectConfigByKey(expireKey);
            long now = System.currentTimeMillis();
            long expireTs = 0L;
            if (StringUtils.isNotEmpty(cachedExpireStr)) {
                try {
                    expireTs = Long.parseLong(cachedExpireStr);
                } catch (NumberFormatException e) {
                    expireTs = 0L;
                }
            }
            
            // 缓存有效且未过期(预留60秒安全边界)
            if (StringUtils.isNotEmpty(cachedToken) && expireTs > now + 60000L) {
                log.debug("使用缓存的AccessToken,剩余有效期:{}秒", (expireTs - now) / 1000);
                return cachedToken;
            }
            
            // 重新获取,并写入sys_config
            log.info("AccessToken已过期或不存在,重新获取");
            return refreshAppAccessToken();
        } catch (Exception e) {
            log.error("获取应用级微信AccessToken失败", e);
            return null;
        }
    }
    
    /**
     * 强制刷新AccessToken
     * 忽略缓存,直接从微信获取新Token并更新缓存
     */
    @Override
    public String refreshAppAccessToken() {
        try {
            String appId = wechatConfig.getAppId();
            String appSecret = wechatConfig.getAppSecret();
            String tokenKey = "weixin.access_token." + appId;
            String expireKey = "weixin.access_token_expires." + appId;
            
            String newToken = WechatUtils.getAccessToken(appId, appSecret);
            if (StringUtils.isEmpty(newToken)) {
                log.error("从微信获取AccessToken失败");
                return null;
            }
            
            long now = System.currentTimeMillis();
            long newExpireTs = now + 7200L * 1000L; // 7200秒
            
            upsertConfig(tokenKey, newToken);
            upsertConfig(expireKey, String.valueOf(newExpireTs));
            
            log.info("AccessToken刷新成功,有效期:7200秒");
            return newToken;
        } catch (Exception e) {
            log.error("刷新应用级微信AccessToken失败", e);
            return null;
        }
    }
    
    /**
     * 根据configKey写入或更新sys_config
     */
    private void upsertConfig(String key, String value) {
        SysConfig exist = configMapper.checkConfigKeyUnique(key);
        if (exist != null && exist.getConfigId() != null) {
            exist.setConfigValue(value);
            configMapper.updateConfig(exist);
        } else {
            SysConfig cfg = new SysConfig();
            cfg.setConfigKey(key);
            cfg.setConfigName(key);
            cfg.setConfigValue(value);
            cfg.setConfigType("Y"); // 内置参数
            configMapper.insertConfig(cfg);
        }
    }
}