首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

微信支付 Java 版 JSAPI 支付與模板消息發送完整整合指南

     編輯:Java 相關知識

業務場景

用戶在公眾號 H5 頁面發起支付(JSAPI),下單成功後發送模板消息通知用戶「待付款」,用戶點擊消息跳轉喚起微信支付收銀台。

核心流程時序

  1. 前端傳 orderNo、openId 調用後端 /weiXinSend
  2. 後端調用統一下單獲取 prepay_id
  3. 構造 JSAPI 支付參數(含 paySign)返回前端
  4. 同時組裝模板消息卡片,調用發送模板消息接口
  5. 前端 WeixinJSBridge.invoke('getBrandWCPayRequest', ...) 唤起支付
  6. 支付結果通過異步通知或前端回調更新訂單狀態

關鍵代碼片段

1. 統一下單獲取 prepay_id

public JSONObject unifiedOrder(String nonceStr, String body, String outTradeNo,
                               String totalFee, String timeStart, String timeExpire,
                               String openId) {
    // 構造 XML 請求體(含簽名)
    String xml = ClientCustomSSL.CreateJsApiPackage(nonceStr, body, outTradeNo,
            totalFee, timeStart, timeExpire, openId);

    // 雙向憑證 HTTPS POST
    CloseableHttpClient client = HttpClients.custom()
        .setSSLSocketFactory(buildSSLFactory()) // 加載商戶證書
        .build();
    HttpPost post = new HttpPost("https://api.mch.weixin.qq.com/pay/unifiedorder");
    post.setEntity(new StringEntity(xml, "UTF-8"));

    try (CloseableHttpResponse resp = client.execute(post)) {
        Document doc = new SAXReader().read(resp.getEntity().getContent());
        Element root = doc.getRootElement();
        if ("SUCCESS".equals(root.elementText("result_code"))) {
            JSONObject result = new JSONObject();
            result.put("prepayId", root.elementText("prepay_id"));
            result.put("sign", root.elementText("sign")); // 簽名供前端二次簽名
            return result;
        }
        throw new RuntimeException("下單失敗: " + root.elementText("err_code_des"));
    }
}

2. 發送模板消息

public JSONObject sendTemplateMsg(String openId, String prepayId, OrderInfo order) {
    String url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + getAccessToken();

    JsPay msg = new JsPay();
    msg.setTouser(openId);
    msg.setTemplate_id("MieXd4-4uqRFMdjnvqMjH0egFYpm16r5DPDT6P9gPgg"); // 模板ID
    msg.setUrl("https://your.domain/weixinJsPay/init?packageValue=" + prepayId);
    msg.setTopcolor("#173177");

    List<Map<String, Map<String, String>>> data = new ArrayList<>();
    Map<String, Map<String, String>> item = new HashMap<>();
    item.put("first", kv("尊敬的用戶,您有一筆新訂單", "#173177"));
    item.put("keyword1", kv(order.getOrderNo(), "#173177"));
    item.put("keyword2", kv("生鮮訂單", "#173177"));
    item.put("keyword3", kv(order.getPrice() + "元", "#173177"));
    item.put("keyword4", kv("待付款", "#173177"));
    item.put("remark", kv("點擊付款", "#173177"));
    data.add(item);
    msg.setData(data);

    // 發送 HTTP POST JSON
    return postJson(url, JSONObject.fromObject(msg).toString());
}

private Map<String, String> kv(String value, String color) {
    Map<String, String> m = new HashMap<>();
    m.put("value", value);
    m.put("color", color);
    return m;
}

3. 前端 JSAPI 唤起支付

<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<script>
wx.config({
    appId: '你的AppId',
    timestamp: '{{timestamp}}',
    nonceStr: '{{nonceStr}}',
    signature: '{{signature}}',
    jsApiList: ['chooseWXPay']
});

wx.ready(function() {
    wx.chooseWXPay({
        timestamp: '{{timestamp}}',
        nonceStr: '{{nonceStr}}',
        package: 'prepay_id={{prepayId}}',
        signType: 'MD5',
        paySign: '{{paySign}}',
        success: function(res) {
            alert('支付成功');
            location.href = '/order/success';
        },
        cancel: function() { alert('用戶取消'); },
        fail: function(res) { alert('支付失敗: ' + res.errMsg); }
    });
});
</script>

安全與簽名關鍵點

  • 商戶證書:雙向 HTTPS 必須加載 apiclient_cert.p12,密碼為商戶號。
  • 簽名算法:MD5(舊版)或 HMAC-SHA256(新版 v3),參數按 ASCII 排序拼接 + key=商戶Key。
  • JSAPI 二次簽名:前端喚起支付需對 appId/timeStamp/nonceStr/package/signType 重新簽名,不可直接用下單返回的 sign。
  • 金額單位:統一下單傳 分(整數),前端展示除以 100。

常見坑點避雷

現象原因解決
prepay_id 失效2小時未支付過期下單即支付,或重新下單
支付頁面簽名驗證失敗參數排序/編碼/Key不一致用官方簽名工具類,統一 UTF-8
模板消息不顯示模板ID錯誤/未審核/用戶未關注確認模板狀態、openId有效性
測試環境無法支付未配置授權目錄/測試白名單公眾號後台設置支付授權目錄、綁定測試者

架構建議

  • 將微信支付封裝為獨立 PayService,暴露 unifiedOrder、queryOrder、refund 等接口。
  • 異步通知單獨 Controller,驗證簽名後發送 MQ 異步更新訂單,避免阻塞微信回調線程。
  • 敏感配置(AppId、MchId、Key、證書路徑)放入配置中心,環境隔離。
  • 引入 幂等性:訂單號唯一、通知去重、狀態機流轉防重複扣款。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved