发起微信支付

流程总结

  1. 用户点击按钮:用户点击“立即购买”按钮,触发initiatePayment函数。
  2. 获取OpenID:从页面获取OpenID,如果为空,则提示错误。
  3. 发送创建订单请求:将OpenID发送到后端,创建微信支付订单。
  4. 处理响应:根据后端返回的数据配置微信JS-SDK。
  5. 调用微信支付接口:调用wx.chooseWXPay接口,发起微信支付。
  6. 支付结果处理:根据支付结果显示成功或失败的提示。

第一步:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Callback</title>
    <script src="https://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
    <script>
        function initiatePayment() {
            const openid = document.getElementById('openid').textContent;

            if (!openid) {
                alert('OpenID 不能为空');
                return;
            }

            fetch('/createOrder', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ openid: openid })
            }).then(response => response.json())
                .then(data => {
                    if (data.success) {
                        wx.config({
                            debug: false, // 开启调试模式
                            appId: data.appId, // 必填,公众号的唯一标识
                            timestamp: data.timeStamp, // 必填,生成签名的时间戳
                            nonceStr: data.nonceStr, // 必填,生成签名的随机串
                            signature: data.paySign, // 必填,签名
                            jsApiList: ['chooseWXPay'] // 必填,需要使用的JS接口列表
                        });

                        wx.ready(function() {
                            wx.chooseWXPay({
                                timestamp: data.timeStamp, // 支付签名时间戳
                                nonceStr: data.nonceStr, // 支付签名随机串
                                package: data.package, // 统一下单接口返回的prepay_id参数值
                                signType: 'MD5', // 签名方式
                                paySign: data.paySign, // 支付签名
                                success: function (res) {
                                    alert('支付成功');
                                },
                                fail: function (res) {
                                    alert('支付失败');
                                }
                            });
                        });
                    } else {
                        alert('创建订单失败');
                    }
                }).catch(error => {
                console.error('Error:', error);
            });
        }
    </script>
</head>
<body>
<h1 th:text="${message}">Callback</h1>
<p>Authorization Code: <span id="code" th:text="${code}">No Code</span></p>
<p>Your OpenID is: <span id="openid" th:text="${openid}">OpenID</span></p>
<p>Your Nickname is: <span id="nickname" th:text="${nickname}">Nickname</span></p>
<p>Your Profile Picture: <img th:src="${headimgurl}" alt="Profile Picture"></p>
<button onclick="initiatePayment()">立即购买</button>
</body>
</html>

第二步:

package com.example.demo.controller;

import org.jdom2.JDOMException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import com.example.demo.util.PayUtil;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.logging.Logger;

@RestController
public class WeChatPayController {

    private static final Logger logger = Logger.getLogger(WeChatPayController.class.getName());

    @Value("${wechat.appId}")
    private String appId;

    @Value("${wechat.mchId}")
    private String mchId;

    @Value("${wechat.apiKey}")
    private String apiKey;

    @Value("${wechat.notifyUrl}")
    private String notifyUrl;

    @PostMapping("/createOrder")
    public Map<String, Object> createOrder(@RequestBody Map<String, String> requestBody, HttpServletRequest request) throws JDOMException, IOException {
        String openid = requestBody.get("openid");

        SortedMap<String, String> params = new TreeMap<>();
        params.put("appid", appId);
        params.put("mch_id", mchId);
        params.put("nonce_str", PayUtil.generateNonceStr());
        params.put("body", "Test Product");
        params.put("out_trade_no", PayUtil.generateOutTradeNo());
        params.put("total_fee", "1"); // 单位为分
        params.put("spbill_create_ip", request.getRemoteAddr());
        params.put("notify_url", notifyUrl);
        params.put("trade_type", "JSAPI");
        params.put("openid", openid);

        // 打印所有参数
        for (Map.Entry<String, String> entry : params.entrySet()) {
            logger.info(entry.getKey() + ": " + entry.getValue());
        }

        String sign = PayUtil.createSign(params, apiKey);
        logger.info("Generated Sign: " + sign);
        params.put("sign", sign);

        String requestXML = PayUtil.mapToXml(params);

        logger.info("Request XML: " + requestXML);

        RestTemplate restTemplate = new RestTemplate();
        String responseXML = restTemplate.postForObject("https://api.mch.weixin.qq.com/pay/unifiedorder", requestXML, String.class);

        logger.info("Response XML: " + responseXML);

        Map<String, String> resultMap = PayUtil.xmlToMap(responseXML);
        if ("SUCCESS".equals(resultMap.get("return_code")) && "SUCCESS".equals(resultMap.get("result_code"))) {
            SortedMap<String, String> payMap = new TreeMap<>();
            payMap.put("appId", appId);
            payMap.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
            payMap.put("nonceStr", PayUtil.generateNonceStr());
            payMap.put("package", "prepay_id=" + resultMap.get("prepay_id"));
            payMap.put("signType", "MD5");
            payMap.put("paySign", PayUtil.createSign(payMap, apiKey));

            Map<String, Object> data = new HashMap<>();
            data.put("success", true);
            data.putAll(payMap);
            return data;
        } else {
            logger.severe("Error creating order: " + resultMap.get("return_msg"));
            Map<String, Object> data = new HashMap<>();
            data.put("success", false);
            data.put("message", resultMap.get("return_msg"));
            return data;
        }
    }
}

第三步:

这段代码是一个用于处理微信支付结果通知的控制器,定义在 WeChatNotifyController 中。微信支付成功后,微信服务器会通过POST请求将支付结果发送到商户服务器。商户服务器需要实现一个接口来接收和处理这个通知。以下是详细解释:

功能概述

WeChatNotifyController 负责接收和处理微信支付的结果通知。具体步骤如下:

  1. 接收通知数据:从 HttpServletRequest 中读取微信服务器发送的XML格式通知数据。
  2. 解析通知数据:将XML格式的通知数据解析为一个 Map
  3. 验证签名:使用通知数据中的签名信息和商户的API密钥进行签名验证,确保通知数据的真实性和完整性。
  4. 处理业务逻辑:如果签名验证成功且支付结果为成功,执行相应的业务逻辑(如更新订单状态、发送通知等)。
  5. 返回响应:根据处理结果返回XML格式的响应数据,告知微信服务器通知是否成功处理。
package com.example.demo.controller;

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.SortedMap;

import com.example.demo.util.PayUtil;

@RestController
public class WeChatNotifyController {

    @PostMapping("/notify")
    public String weChatPayNotify(HttpServletRequest request) {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
            String line;
            StringBuilder sb = new StringBuilder();
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            String notifyData = sb.toString();

            Map<String, String> resultMap = PayUtil.xmlToMap(notifyData);
            // 验证签名
            if (PayUtil.createSign((SortedMap<String, String>) resultMap, "your_api_key").equals(resultMap.get("sign"))) {
                // 签名验证成功,处理业务逻辑
                // 比如更新订单状态、发送通知等
                if ("SUCCESS".equals(resultMap.get("result_code"))) {
                    // 支付成功
                    return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[FAIL]]></return_msg></xml>";
    }
}

第四步:工具类

package com.example.demo.util;

import java.security.MessageDigest;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;
import org.jdom2.JDOMException;
import org.xml.sax.InputSource;
import java.io.StringReader;
import java.io.IOException;
import java.util.List;

public class PayUtil {

    public static String generateNonceStr() {
        return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
    }

    public static String generateOutTradeNo() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    public static String createSign(SortedMap<String, String> params, String apiKey) {
        StringBuilder sb = new StringBuilder();
        Set<Map.Entry<String, String>> es = params.entrySet();
        for (Map.Entry<String, String> entry : es) {
            String k = entry.getKey();
            String v = entry.getValue();
            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k).append("=").append(v).append("&");
            }
        }
        sb.append("key=").append(apiKey);
        return MD5(sb.toString()).toUpperCase();
    }

    public static String MD5(String str) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(str.getBytes("UTF-8"));
            byte[] md5Bytes = md.digest();
            StringBuilder hexValue = new StringBuilder();
            for (byte md5Byte : md5Bytes) {
                int val = ((int) md5Byte) & 0xff;
                if (val < 16) hexValue.append("0");
                hexValue.append(Integer.toHexString(val));
            }
            return hexValue.toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static String mapToXml(SortedMap<String, String> map) {
        StringBuilder xml = new StringBuilder("<xml>");
        for (Map.Entry<String, String> entry : map.entrySet()) {
            xml.append("<").append(entry.getKey()).append(">");
            xml.append(entry.getValue());
            xml.append("</").append(entry.getKey()).append(">");
        }
        xml.append("</xml>");
        return xml.toString();
    }

    public static Map<String, String> xmlToMap(String xmlStr) throws JDOMException, IOException {
        SAXBuilder builder = new SAXBuilder();
        InputSource source = new InputSource(new StringReader(xmlStr));
        org.jdom2.Document doc = builder.build(source);
        Element root = doc.getRootElement();
        List<Element> list = root.getChildren();
        Map<String, String> map = new TreeMap<>();
        for (Element e : list) {
            map.put(e.getName(), e.getText());
        }
        return map;
    }
    public static String createJsSdkSign(SortedMap<String, String> params) {
        StringBuilder sb = new StringBuilder();
        Set<Map.Entry<String, String>> es = params.entrySet();
        for (Map.Entry<String, String> entry : es) {
            String k = entry.getKey();
            String v = entry.getValue();
            sb.append(k).append("=").append(v).append("&");
        }
        sb.deleteCharAt(sb.length() - 1);
        return SHA1(sb.toString());
    }

    public static String SHA1(String str) {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-1");
            digest.update(str.getBytes("UTF-8"));
            byte[] messageDigest = digest.digest();
            StringBuilder hexStr = new StringBuilder();
            for (byte b : messageDigest) {
                String shaHex = Integer.toHexString(b & 0xff);
                if (shaHex.length() < 2) {
                    hexStr.append(0);
                }
                hexStr.append(shaHex);
            }
            return hexStr.toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
uniapp点击支付发起微信支付的过程如下: 首先,确保在微信开放平台注册并申请了账号,并在应用详情中开通了微信支付功能。同时,你需要获取到AppID和商户号作为配置参数。 然后,在uniCloud中找到云函数uni-config-center,进入config.json文件,将其中的wxConfigApp字段修改为你自己的AppID、商户号和秘钥。 接下来,在uniapp的代码中,通过调用相关API来发起支付。具体的代码实现可以参考uni-app官方文档,其中包括了通过uni.request方法调用云函数uni-pay的接口来发起支付请求。 最后,支付成功后,微信会通过回调通知你的服务器接口,你可以在服务器端进行相应的处理。 请注意,如果你使用的是iOS平台,还需要配置Universal Link以确保支付完成后能回到APP。在微信开放平台的应用详情中,将Universal Links配置与你的应用中的配置一致。 希望以上信息对你有帮助。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [uniapp支付之APP微信支付unicloud版(附源码)](https://blog.csdn.net/qq_32340877/article/details/125461425)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值