feat(mqtt): 关闭MQTT服务并添加微信小程序token服务

- 将application-glt.yml中的mqtt.enabled设置为false
- 重构ShopDealerOrder实体类的导入顺序
- 在ShopDealerOrder中新增isUnfreeze字段表示佣金冻结状态
- 在ShopDealerOrder中新增unfreezeTime字段表示解冻时间
- 新增WxMiniappAccessTokenService接口用于获取微信小程序access_token
- 实现WxMiniappAccessTokenServiceImpl服务支持按租户获取access_token
- 集成Redis缓存机制支持access_token的缓存管理
- 实现微信API调用逻辑支持token获取和异常处理
This commit is contained in:
2026-02-22 18:34:07 +08:00
parent 90965b6d0a
commit b713ba0dcc
4 changed files with 137 additions and 6 deletions

View File

@@ -0,0 +1,18 @@
package com.gxwebsoft.common.system.service;
/**
* 微信小程序 access_token 获取服务(按租户)。
*
* <p>用于调用微信小程序开放接口(例如:上传发货信息)。</p>
*/
public interface WxMiniappAccessTokenService {
/**
* 获取指定租户的小程序 access_token内部带缓存
*
* @param tenantId 租户ID
* @return access_token
*/
String getAccessToken(Integer tenantId);
}

View File

@@ -0,0 +1,108 @@
package com.gxwebsoft.common.system.service.impl;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gxwebsoft.common.core.exception.BusinessException;
import com.gxwebsoft.common.core.utils.RedisUtil;
import com.gxwebsoft.common.system.service.WxMiniappAccessTokenService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
import static com.gxwebsoft.common.core.constants.RedisConstants.ACCESS_TOKEN_KEY;
import static com.gxwebsoft.common.core.constants.RedisConstants.MP_WX_KEY;
/**
* 微信小程序 access_token 获取实现(按租户)。
*
* <p>复用现有缓存结构:
* <ul>
* <li>小程序配置Redis key = {@code mp-weixin:{tenantId}}value 为 JSON包含 appId/appSecret</li>
* <li>access_tokenRedis key = {@code access-token:{tenantId}}value 为微信返回的 JSON 字符串</li>
* </ul>
* </p>
*/
@Slf4j
@Service
public class WxMiniappAccessTokenServiceImpl implements WxMiniappAccessTokenService {
@Resource
private RedisUtil redisUtil;
@Override
public String getAccessToken(Integer tenantId) {
if (tenantId == null) {
throw new BusinessException("tenantId 不能为空");
}
final String tokenCacheKey = ACCESS_TOKEN_KEY + ":" + tenantId;
// 1) 优先从缓存取(兼容 JSON 或纯字符串 token 的历史格式)
String cachedValue = redisUtil.get(tokenCacheKey);
if (StrUtil.isNotBlank(cachedValue)) {
try {
JSONObject cachedJson = JSON.parseObject(cachedValue);
String accessToken = cachedJson.getString("access_token");
if (StrUtil.isNotBlank(accessToken)) {
return accessToken;
}
} catch (Exception ignore) {
// 旧格式:直接存 token
return cachedValue;
}
}
// 2) 缓存没有则从租户配置获取 appId/appSecret
final String wxConfigKey = MP_WX_KEY + tenantId;
final String wxConfigValue = redisUtil.get(wxConfigKey);
if (StrUtil.isBlank(wxConfigValue)) {
throw new BusinessException("未找到微信小程序配置请检查缓存key: " + wxConfigKey);
}
JSONObject wxConfig;
try {
wxConfig = JSON.parseObject(wxConfigValue);
} catch (Exception e) {
throw new BusinessException("微信小程序配置格式错误: " + e.getMessage());
}
final String appId = wxConfig.getString("appId");
final String appSecret = wxConfig.getString("appSecret");
if (StrUtil.isBlank(appId) || StrUtil.isBlank(appSecret)) {
throw new BusinessException("微信小程序配置不完整(appId/appSecret)");
}
// 3) 调用微信接口获取 token
final String apiUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential"
+ "&appid=" + appId + "&secret=" + appSecret;
String result = HttpUtil.get(apiUrl);
JSONObject json = JSON.parseObject(result);
if (json.containsKey("errcode") && json.getIntValue("errcode") != 0) {
Integer errcode = json.getInteger("errcode");
String errmsg = json.getString("errmsg");
throw new BusinessException("获取小程序access_token失败: " + errmsg + " (errcode: " + errcode + ")");
}
String accessToken = json.getString("access_token");
Integer expiresIn = json.getInteger("expires_in");
if (StrUtil.isBlank(accessToken)) {
throw new BusinessException("获取小程序access_token失败: access_token为空");
}
// 4) 缓存微信原始 JSON与现有实现保持一致提前5分钟过期
long ttlSeconds = 7000L;
if (expiresIn != null && expiresIn > 300) {
ttlSeconds = expiresIn - 300L;
}
redisUtil.set(tokenCacheKey, result, ttlSeconds, TimeUnit.SECONDS);
log.info("获取小程序access_token成功 - tenantId={}, ttlSeconds={}", tenantId, ttlSeconds);
return accessToken;
}
}

View File

@@ -1,19 +1,18 @@
package com.gxwebsoft.shop.entity;
import java.math.BigDecimal;
import cn.afterturn.easypoi.excel.annotation.Excel;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import java.time.LocalDateTime;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serializable;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 分销商订单记录表
*
@@ -120,9 +119,15 @@ public class ShopDealerOrder implements Serializable {
@Schema(description = "佣金结算(0未结算 1已结算)")
private Integer isSettled;
@Schema(description = "佣金冻结(1解冻中 0已解冻)")
private Integer isUnfreeze;
@Schema(description = "结算时间")
private LocalDateTime settleTime;
@Schema(description = "解冻时间")
private LocalDateTime unfreezeTime;
@Schema(description = "备注")
private String comments;

View File

@@ -32,7 +32,7 @@ socketio:
# MQTT配置
mqtt:
enabled: true # 启用MQTT服务
enabled: false # 启用MQTT服务
host: tcp://132.232.214.96:1883
username: swdev
password: Sw20250523