package com.ruoyi.system.service.impl;
|
|
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.system.service.IQyWechatAccessTokenService;
|
import com.ruoyi.system.service.ISysConfigService;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
|
/**
|
* 企业微信AccessToken服务实现类
|
*
|
* @author ruoyi
|
* @date 2025-12-11
|
*/
|
@Service
|
public class QyWechatAccessTokenServiceImpl implements IQyWechatAccessTokenService {
|
|
private static final Logger log = LoggerFactory.getLogger(QyWechatAccessTokenServiceImpl.class);
|
|
@Autowired
|
private ISysConfigService configService;
|
|
/**
|
* 企业微信获取access_token的URL
|
*/
|
private static final String GET_ACCESS_TOKEN_URL = "https://qyapi.weixin.qq.com/cgi-bin/gettoken";
|
|
/**
|
* 获取企业微信应用的AccessToken
|
*
|
* @param corpId 企业ID
|
* @param corpSecret 应用密钥
|
* @return AccessToken
|
*/
|
@Override
|
public String getAppAccessToken(String corpId, String corpSecret) {
|
try {
|
// 参数校验
|
if (StringUtils.isEmpty(corpId) || StringUtils.isEmpty(corpSecret)) {
|
log.warn("企业微信配置参数不完整,corpId或corpSecret为空");
|
return null;
|
}
|
|
// 检查服务是否启用
|
if (!isEnabled()) {
|
log.info("企业微信服务已禁用,无法获取AccessToken");
|
return null;
|
}
|
|
// 构建配置键名
|
String tokenKey = "qy_wechat.access_token." + corpId;
|
String expiresKey = "qy_wechat.access_token_expires." + corpId;
|
|
// 从配置中获取Token和过期时间
|
String accessToken = configService.selectConfigByKey(tokenKey);
|
String expiresStr = configService.selectConfigByKey(expiresKey);
|
|
// 检查Token是否存在且未过期
|
if (StringUtils.isNotEmpty(accessToken) && StringUtils.isNotEmpty(expiresStr)) {
|
try {
|
long expiresTime = Long.parseLong(expiresStr);
|
long currentTime = System.currentTimeMillis();
|
|
// 预留60秒安全边界,避免临界点过期
|
if (currentTime < expiresTime - 60000) {
|
log.debug("使用缓存的企业微信AccessToken,剩余有效时间: {}秒",
|
(expiresTime - currentTime) / 1000);
|
return accessToken;
|
} else {
|
log.info("企业微信AccessToken已过期或即将过期,需要刷新");
|
}
|
} catch (NumberFormatException e) {
|
log.warn("解析企业微信AccessToken过期时间失败: {}", expiresStr);
|
}
|
}
|
|
// Token不存在或已过期,刷新Token
|
return refreshAppAccessToken(corpId, corpSecret);
|
} catch (Exception e) {
|
log.error("获取企业微信AccessToken失败", e);
|
return null;
|
}
|
}
|
|
/**
|
* 刷新企业微信应用的AccessToken
|
*
|
* @param corpId 企业ID
|
* @param corpSecret 应用密钥
|
* @return 新的AccessToken
|
*/
|
@Override
|
public String refreshAppAccessToken(String corpId, String corpSecret) {
|
try {
|
log.info("开始刷新企业微信AccessToken");
|
|
// 构建请求URL
|
String url = GET_ACCESS_TOKEN_URL + "?corpid=" + corpId + "&corpsecret=" + corpSecret;
|
|
// 发送HTTP请求获取Token
|
String response = sendHttpGetRequest(url);
|
|
if (StringUtils.isEmpty(response)) {
|
log.error("获取企业微信AccessToken失败,响应为空");
|
return null;
|
}
|
|
// 解析响应
|
QyWechatTokenResponse tokenResponse = parseTokenResponse(response);
|
|
if (tokenResponse == null || StringUtils.isEmpty(tokenResponse.getAccessToken())) {
|
log.error("解析企业微信AccessToken响应失败: {}", response);
|
return null;
|
}
|
|
// 计算过期时间(当前时间 + 有效期 - 60秒安全边界)
|
long expiresTime = System.currentTimeMillis() + (tokenResponse.getExpiresIn() * 1000L) - 60000L;
|
|
// 构建配置键名
|
String tokenKey = "qy_wechat.access_token." + corpId;
|
String expiresKey = "qy_wechat.access_token_expires." + corpId;
|
|
// 保存到系统配置表
|
configService.updateConfigValue(tokenKey, tokenResponse.getAccessToken());
|
configService.updateConfigValue(expiresKey, String.valueOf(expiresTime));
|
|
log.info("企业微信AccessToken刷新成功,有效期: {}秒", tokenResponse.getExpiresIn());
|
return tokenResponse.getAccessToken();
|
} catch (Exception e) {
|
log.error("刷新企业微信AccessToken失败", e);
|
return null;
|
}
|
}
|
|
/**
|
* 检查企业微信服务是否启用
|
*
|
* @return true-启用,false-禁用
|
*/
|
@Override
|
public boolean isEnabled() {
|
try {
|
String enabled = configService.selectConfigByKey("qy_wechat.enable");
|
return !"false".equals(enabled); // 默认启用
|
} catch (Exception e) {
|
log.warn("获取企业微信服务启用状态失败,使用默认值(true)", e);
|
return true;
|
}
|
}
|
|
/**
|
* 发送HTTP GET请求
|
*
|
* @param url 请求URL
|
* @return 响应内容
|
*/
|
private String sendHttpGetRequest(String url) {
|
try {
|
java.net.HttpURLConnection conn = (java.net.HttpURLConnection) new java.net.URL(url).openConnection();
|
conn.setRequestMethod("GET");
|
conn.setConnectTimeout(5000);
|
conn.setReadTimeout(5000);
|
|
int responseCode = conn.getResponseCode();
|
if (responseCode == 200) {
|
java.io.BufferedReader reader = new java.io.BufferedReader(
|
new java.io.InputStreamReader(conn.getInputStream(), "UTF-8"));
|
StringBuilder response = new StringBuilder();
|
String line;
|
while ((line = reader.readLine()) != null) {
|
response.append(line);
|
}
|
reader.close();
|
return response.toString();
|
} else {
|
log.error("HTTP请求失败,响应码: {}", responseCode);
|
return null;
|
}
|
} catch (Exception e) {
|
log.error("发送HTTP请求失败", e);
|
return null;
|
}
|
}
|
|
/**
|
* 解析企业微信Token响应
|
*
|
* @param response 响应JSON
|
* @return Token响应对象
|
*/
|
private QyWechatTokenResponse parseTokenResponse(String response) {
|
try {
|
// 简单JSON解析(实际项目中建议使用Jackson或Gson)
|
// 示例响应: {"errcode":0,"errmsg":"ok","access_token":"xxxxxx","expires_in":7200}
|
|
// 移除花括号
|
String content = response.substring(1, response.length() - 1);
|
|
// 按逗号分割
|
String[] pairs = content.split(",");
|
|
QyWechatTokenResponse tokenResponse = new QyWechatTokenResponse();
|
|
for (String pair : pairs) {
|
String[] keyValue = pair.split(":");
|
if (keyValue.length == 2) {
|
String key = keyValue[0].trim().replaceAll("\"", "");
|
String value = keyValue[1].trim().replaceAll("\"", "");
|
|
switch (key) {
|
case "errcode":
|
tokenResponse.setErrcode(Integer.parseInt(value));
|
break;
|
case "errmsg":
|
tokenResponse.setErrmsg(value);
|
break;
|
case "access_token":
|
tokenResponse.setAccessToken(value);
|
break;
|
case "expires_in":
|
tokenResponse.setExpiresIn(Integer.parseInt(value));
|
break;
|
}
|
}
|
}
|
|
// 检查是否有错误
|
if (tokenResponse.getErrcode() != 0) {
|
log.error("获取企业微信AccessToken失败,错误码: {}, 错误信息: {}",
|
tokenResponse.getErrcode(), tokenResponse.getErrmsg());
|
return null;
|
}
|
|
return tokenResponse;
|
} catch (Exception e) {
|
log.error("解析企业微信Token响应失败: {}", response, e);
|
return null;
|
}
|
}
|
|
/**
|
* 企业微信Token响应内部类
|
*/
|
private static class QyWechatTokenResponse {
|
private int errcode;
|
private String errmsg;
|
private String accessToken;
|
private int expiresIn;
|
|
// Getters and Setters
|
public int getErrcode() {
|
return errcode;
|
}
|
|
public void setErrcode(int errcode) {
|
this.errcode = errcode;
|
}
|
|
public String getErrmsg() {
|
return errmsg;
|
}
|
|
public void setErrmsg(String errmsg) {
|
this.errmsg = errmsg;
|
}
|
|
public String getAccessToken() {
|
return accessToken;
|
}
|
|
public void setAccessToken(String accessToken) {
|
this.accessToken = accessToken;
|
}
|
|
public int getExpiresIn() {
|
return expiresIn;
|
}
|
|
public void setExpiresIn(int expiresIn) {
|
this.expiresIn = expiresIn;
|
}
|
}
|
}
|