From 25df88d0ab9d7444ed1d162b9efa1259ac2f6f66 Mon Sep 17 00:00:00 2001
From: longz <longzhaoz@qq.com>
Date: 星期一, 27 四月 2026 10:13:53 +0800
Subject: [PATCH] 小程序对接finish

---
 backend/src/main/java/com/sinata/appointment/integration/WechatMiniGateway.java |   62 +++++++++++++++++++++++++++++++
 1 files changed, 62 insertions(+), 0 deletions(-)

diff --git a/backend/src/main/java/com/sinata/appointment/integration/WechatMiniGateway.java b/backend/src/main/java/com/sinata/appointment/integration/WechatMiniGateway.java
index 0c31b96..6d8faf5 100644
--- a/backend/src/main/java/com/sinata/appointment/integration/WechatMiniGateway.java
+++ b/backend/src/main/java/com/sinata/appointment/integration/WechatMiniGateway.java
@@ -5,6 +5,7 @@
 import com.sinata.appointment.config.WechatMiniAppProperties;
 import com.sinata.appointment.constants.BizErrorCode;
 import com.sinata.appointment.exception.BizException;
+import java.util.Map;
 import java.util.concurrent.locks.ReentrantLock;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Qualifier;
@@ -30,6 +31,8 @@
             "https://api.weixin.qq.com/cgi-bin/token";
     private static final String GET_USER_PHONE =
             "https://api.weixin.qq.com/wxa/business/getuserphonenumber";
+    private static final String SEND_SUBSCRIBE_MESSAGE =
+            "https://api.weixin.qq.com/cgi-bin/message/subscribe/send";
 
     private final WechatMiniAppProperties props;
     private final RestTemplate restTemplate;
@@ -138,6 +141,65 @@
         }
     }
 
+    public void sendSubscribeMessage(
+            String openId,
+            String templateId,
+            String page,
+            Map<String, String> templateData) {
+        if (openId == null || openId.isBlank()) {
+            throw new BizException(BizErrorCode.MINI_WX_API_ERROR, "openId 不能为空");
+        }
+        if (templateId == null || templateId.isBlank()) {
+            throw new BizException(BizErrorCode.MINI_WX_API_ERROR, "templateId 不能为空");
+        }
+        if (templateData == null || templateData.isEmpty()) {
+            throw new BizException(BizErrorCode.MINI_WX_API_ERROR, "订阅消息参数不能为空");
+        }
+        if (props.useStub()) {
+            log.info(
+                    "Wechat mini stub: subscribe message openId={} templateId={} page={} data={}",
+                    openId,
+                    templateId,
+                    page,
+                    templateData);
+            return;
+        }
+        String token = getAccessToken();
+        String url =
+                UriComponentsBuilder.fromHttpUrl(SEND_SUBSCRIBE_MESSAGE)
+                        .queryParam("access_token", token)
+                        .build()
+                        .toUriString();
+        try {
+            var root = objectMapper.createObjectNode();
+            root.put("touser", openId);
+            root.put("template_id", templateId);
+            if (page != null && !page.isBlank()) {
+                root.put("page", page);
+            }
+            var dataNode = root.putObject("data");
+            templateData.forEach(
+                    (key, value) -> dataNode.putObject(key).put("value", value == null ? "" : value));
+            HttpHeaders headers = new HttpHeaders();
+            headers.setContentType(MediaType.APPLICATION_JSON);
+            String body =
+                    restTemplate.postForObject(
+                            url, new HttpEntity<>(root.toString(), headers), String.class);
+            JsonNode response = objectMapper.readTree(body);
+            int err = response.path("errcode").asInt(-1);
+            if (err != 0) {
+                String msg = response.path("errmsg").asText("wx error");
+                log.warn("sendSubscribeMessage errcode={} msg={}", err, msg);
+                throw new BizException(BizErrorCode.MINI_WX_API_ERROR, "发送订阅消息失败: " + msg);
+            }
+        } catch (BizException e) {
+            throw e;
+        } catch (Exception e) {
+            log.error("sendSubscribeMessage http error", e);
+            throw new BizException(BizErrorCode.MINI_WX_API_ERROR, "微信订阅消息接口异常");
+        }
+    }
+
     private String getAccessToken() {
         tokenLock.lock();
         try {

--
Gitblit v1.7.1