From b713ba0dccc67946f17b91e8e44d0429a76fb7f9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com>
Date: Sun, 22 Feb 2026 18:34:07 +0800
Subject: [PATCH] =?UTF-8?q?feat(mqtt):=20=E5=85=B3=E9=97=ADMQTT=E6=9C=8D?=
=?UTF-8?q?=E5=8A=A1=E5=B9=B6=E6=B7=BB=E5=8A=A0=E5=BE=AE=E4=BF=A1=E5=B0=8F?=
=?UTF-8?q?=E7=A8=8B=E5=BA=8Ftoken=E6=9C=8D=E5=8A=A1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 将application-glt.yml中的mqtt.enabled设置为false
- 重构ShopDealerOrder实体类的导入顺序
- 在ShopDealerOrder中新增isUnfreeze字段表示佣金冻结状态
- 在ShopDealerOrder中新增unfreezeTime字段表示解冻时间
- 新增WxMiniappAccessTokenService接口用于获取微信小程序access_token
- 实现WxMiniappAccessTokenServiceImpl服务支持按租户获取access_token
- 集成Redis缓存机制支持access_token的缓存管理
- 实现微信API调用逻辑支持token获取和异常处理
---
.../service/WxMiniappAccessTokenService.java | 18 +++
.../impl/WxMiniappAccessTokenServiceImpl.java | 108 ++++++++++++++++++
.../shop/entity/ShopDealerOrder.java | 15 ++-
src/main/resources/application-glt.yml | 2 +-
4 files changed, 137 insertions(+), 6 deletions(-)
create mode 100644 src/main/java/com/gxwebsoft/common/system/service/WxMiniappAccessTokenService.java
create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/WxMiniappAccessTokenServiceImpl.java
diff --git a/src/main/java/com/gxwebsoft/common/system/service/WxMiniappAccessTokenService.java b/src/main/java/com/gxwebsoft/common/system/service/WxMiniappAccessTokenService.java
new file mode 100644
index 0000000..3a3a44b
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/common/system/service/WxMiniappAccessTokenService.java
@@ -0,0 +1,18 @@
+package com.gxwebsoft.common.system.service;
+
+/**
+ * 微信小程序 access_token 获取服务(按租户)。
+ *
+ *
用于调用微信小程序开放接口(例如:上传发货信息)。
+ */
+public interface WxMiniappAccessTokenService {
+
+ /**
+ * 获取指定租户的小程序 access_token(内部带缓存)。
+ *
+ * @param tenantId 租户ID
+ * @return access_token
+ */
+ String getAccessToken(Integer tenantId);
+}
+
diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/WxMiniappAccessTokenServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/WxMiniappAccessTokenServiceImpl.java
new file mode 100644
index 0000000..b6dbe7a
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/common/system/service/impl/WxMiniappAccessTokenServiceImpl.java
@@ -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 获取实现(按租户)。
+ *
+ * 复用现有缓存结构:
+ *
+ * - 小程序配置:Redis key = {@code mp-weixin:{tenantId}},value 为 JSON,包含 appId/appSecret
+ * - access_token:Redis key = {@code access-token:{tenantId}},value 为微信返回的 JSON 字符串
+ *
+ *
+ */
+@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;
+ }
+}
+
diff --git a/src/main/java/com/gxwebsoft/shop/entity/ShopDealerOrder.java b/src/main/java/com/gxwebsoft/shop/entity/ShopDealerOrder.java
index 32be34d..e7a8a77 100644
--- a/src/main/java/com/gxwebsoft/shop/entity/ShopDealerOrder.java
+++ b/src/main/java/com/gxwebsoft/shop/entity/ShopDealerOrder.java
@@ -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;
diff --git a/src/main/resources/application-glt.yml b/src/main/resources/application-glt.yml
index ca0f52c..8e5af90 100644
--- a/src/main/resources/application-glt.yml
+++ b/src/main/resources/application-glt.yml
@@ -32,7 +32,7 @@ socketio:
# MQTT配置
mqtt:
- enabled: true # 启用MQTT服务
+ enabled: false # 启用MQTT服务
host: tcp://132.232.214.96:1883
username: swdev
password: Sw20250523