SpringBoot实现微信支付接口调用及回调函数(商户参数获取)

news2024/10/23 13:18:30

#1024程序员节 | 征文 #

 一、具体业务流程

1. 用户下单

- 前端操作:
  - 用户在应用中选择商品、填写订单信息(如地址、联系方式等),并点击“下单”按钮。
  - 前端将订单信息(商品ID、数量、价格等)发送到后端。

- 后端处理:
  - 接收到订单请求后,生成唯一的订单号(`out_trade_no`)。
  - 将订单信息存储到数据库中,设置订单状态为“待支付”。

 2. 后端创建订单

- 构建请求参数:
  - 使用商户号、应用ID、随机字符串、订单描述、商户订单号、金额(单位:分)、IP 地址等构建 XML 格式的请求数据。

- 发送请求:
  - 使用 HTTP POST 方法将请求数据发送到微信的统一下单 API(`https://api.mch.weixin.qq.com/pay/unifiedorder`)。
- 处理响应:
  - 接收微信返回的响应数据(XML 格式),解析响应内容。
  - 检查返回的 `return_code` 和 `result_code`,确保请求成功。
  - 获取 `prepay_id`,并根据它生成支付签名等信息。

 3. 返回支付信息

- 返回给前端:
  - 将 `prepay_id` 和其他必要参数(如时间戳、随机字符串、签名等)封装成 JSON 响应返回给前端。
- 前端支付:
  - 前端使用微信支付 SDK,调用支付接口启动支付流程。
  - 用户确认支付后,微信客户端处理支付。

 4. 用户确认支付

- 用户行为:
  - 用户在微信中查看支付信息,确认后进行支付。

- 支付结果:
  - 微信处理支付请求,完成后将结果异步通知你的服务器。

 5. 微信支付回调

- 回调 URL 配置:
  - 在微信商户平台配置你的回调 URL(如 `https://yourdomain.com/wechat/notify`)。

- 处理回调请求:
  - 接收到来自微信的 POST 请求,读取请求体中的 XML 数据。

- 验证签名:
  - 提取回调数据中的签名字段,使用相同的参数生成新的签名,与返回的签名进行比较,确保数据的完整性和有效性。

- 更新订单状态:
  - 根据回调数据中的 `result_code` 更新数据库中的订单状态。如果支付成功,修改订单状态为“已支付”,并进行相应的业务处理(如发货)。
- 返回处理结果:
  - 向微信返回处理结果,通常是 `<xml><return_code>SUCCESS</return_code></xml>`。

 6. 返回处理结果

- 响应微信:
  - 确保响应格式正确,避免微信因无法解析而重发通知。

7. 订单状态查询(可选)

- 查询订单状态:
  - 在用户支付后的一段时间内,可以调用微信的订单查询 API(`https://api.mch.weixin.qq.com/pay/orderquery`)来确认订单的状态。
  
- 处理结果:
  - 根据查询结果更新本地订单状态,确保数据一致性。

 8. 订单完成

- 后续处理:
  - 一旦订单支付成功并发货,可以根据业务需求进行后续操作,例如发送确认邮件、更新库存等。

二、代码具体实现

1. 商户参数配置

application.properties 中配置微信支付的相关参数:

# 微信支付配置
wechat.pay.appId=your_app_id
wechat.pay.mchId=your_mch_id
wechat.pay.apiKey=your_api_key
wechat.pay.notifyUrl=https://yourdomain.com/wechat/notify

2. 创建 Spring Boot 项目

确保你的项目引入了必要的依赖。在 pom.xml 中添加以下内容:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
</dependency>
<dependency>
    <groupId>com.thoughtworks.xstream</groupId>
    <artifactId>xstream</artifactId>
    <version>1.4.18</version>
</dependency>

3. 创建微信支付服务类

创建一个服务类 WeChatPayService,用于处理订单的创建和签名等操作。

import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;

@Service
public class WeChatPayService {

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

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

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

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

    private static final String UNIFIED_ORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";

    public String createOrder(String orderNo, double amount) throws Exception {
        String nonceStr = String.valueOf(System.currentTimeMillis());
        String xmlData = "<xml>"
                + "<appid>" + appId + "</appid>"
                + "<mch_id>" + mchId + "</mch_id>"
                + "<nonce_str>" + nonceStr + "</nonce_str>"
                + "<body>Product Description</body>"
                + "<out_trade_no>" + orderNo + "</out_trade_no>"
                + "<total_fee>" + (int) (amount * 100) + "</total_fee>"
                + "<spbill_create_ip>127.0.0.1</spbill_create_ip>"
                + "<notify_url>" + notifyUrl + "</notify_url>"
                + "<trade_type>APP</trade_type>"
                + "</xml>";

        // 生成签名并添加到请求数据
        String sign = WeChatPayUtil.generateSign(xmlData, apiKey);
        xmlData = xmlData.replace("</xml>", "<sign>" + sign + "</sign></xml>");

        try (CloseableHttpClient client = HttpClients.createDefault()) {
            HttpPost post = new HttpPost(UNIFIED_ORDER_URL);
            post.setEntity(new StringEntity(xmlData, "UTF-8"));
            post.setHeader("Content-Type", "text/xml");

            String response = EntityUtils.toString(client.execute(post).getEntity(), "UTF-8");
            return response; // 解析并返回需要的信息
        }
    }
}

4. 创建微信支付控制器

创建一个控制器 WeChatPayController,处理用户的下单请求(@PostMapping("/createOrder"))和回调@PostMapping("/notify")。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;

@RestController
@RequestMapping("/wechat")
public class WeChatPayController {

    @Autowired
    private WeChatPayService weChatPayService;

    @PostMapping("/createOrder")
    public String createOrder(@RequestParam String orderNo, @RequestParam double amount) {
        try {
            return weChatPayService.createOrder(orderNo, amount);
        } catch (Exception e) {
            e.printStackTrace();
            return "Error creating order";
        }
    }

    @PostMapping("/notify")
    public String handleCallback(HttpServletRequest request) {
        StringBuilder sb = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        String xmlData = sb.toString();
        Map<String, String> data = WeChatPayUtil.parseXml(xmlData); // 解析 XML 数据

        // 验证签名
        String sign = data.get("sign");
        if (WeChatPayUtil.generateSign(xmlData, apiKey).equals(sign)) {
            // 处理业务逻辑,例如更新订单状态
            String resultCode = data.get("result_code");
            if ("SUCCESS".equals(resultCode)) {
                String orderNo = data.get("out_trade_no");
                // 更新订单状态为已支付
                // updateOrderStatus(orderNo, "PAID");
            }
            return "<xml><return_code>SUCCESS</return_code></xml>";
        } else {
            return "<xml><return_code>FAIL</return_code></xml>";
        }
    }
}

5. 签名和 XML 处理工具类

创建一个工具类 WeChatPayUtil,负责签名和 XML 解析。

import com.thoughtworks.xstream.XStream;

import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

public class WeChatPayUtil {

    public static String generateSign(String xmlData, String apiKey) {
        // 将 XML 转换为 Map
        Map<String, String> data = parseXml(xmlData);
        TreeMap<String, String> sortedMap = new TreeMap<>(data);
        StringBuilder stringBuilder = new StringBuilder();
        for (Map.Entry<String, String> entry : sortedMap.entrySet()) {
            if (!entry.getKey().equals("sign") && entry.getValue() != null) {
                stringBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
            }
        }
        stringBuilder.append("key=").append(apiKey);
        return md5(stringBuilder.toString()).toUpperCase();
    }

    public static String md5(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] digest = md.digest(input.getBytes());
            StringBuilder hexString = new StringBuilder();
            for (byte b : digest) {
                String hex = Integer.toHexString(0xFF & b);
                if (hex.length() == 1) hexString.append('0');
                hexString.append(hex);
            }
            return hexString.toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static Map<String, String> parseXml(String xml) {
        // 使用 XStream 解析 XML
        XStream xStream = new XStream();
        xStream.alias("xml", HashMap.class);
        return (Map<String, String>) xStream.fromXML(xml);
    }
}

三、参数配置及获取

一、回调函数的配置步骤
  1. 在微信商户平台配置回调地址

    • 登录微信商户平台。
    • 找到“账户设置”或“API安全”选项。
    • 在“支付结果通知 URL”中填写你的回调地址(如 https://yourdomain.com/wechat/notify)。

二、商户参数获取

商户参数主要包括微信支付的相关信息,这些信息可以在微信商户平台上获取。

商户参数
  • appId: 公众账号ID,由微信开放平台或微信支付商户平台提供。
  • mchId: 商户号,由微信支付商户平台提供。
  • apiKey: API 密钥,在微信支付商户平台设置,用于签名请求。
  • notifyUrl: 支付结果通知地址,即微信支付成功后,微信服务器将异步通知该地址。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2221605.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习的一些数学基础

数学基础 万丈高楼平地起 怎么说呢&#xff0c;学的数二对于这些东西还是太陌生了&#xff0c;而且当时学的只会做题&#xff0c;不知道怎么使用/(ㄒoㄒ)/~~ 所以记下来一些不太清楚的前置知识点&#xff0c;主要来自《艾伯特深度学习》&#xff0c;书中内容很多&#xff0c…

动手学深度学习9.6. 编码器-解码器架构-笔记练习(PyTorch)

本节课程地址&#xff1a;61 编码器-解码器架构【动手学深度学习v2】_哔哩哔哩_bilibili 本节教材地址&#xff1a;9.6. 编码器-解码器架构 — 动手学深度学习 2.0.0 documentation (d2l.ai) 本节开源代码&#xff1a;...>d2l-zh>pytorch>chapter_multilayer-percep…

cnn_lstm_kan模型创新实现股票预测

获取更多完整项目代码数据集&#xff0c;点此加入免费社区群 &#xff1a; 首页-置顶必看 1. 项目简介 A002-cnn_lstm_kan模型创新实现股票预测项目旨在通过结合卷积神经网络&#xff08;CNN&#xff09;、长短期记忆网络&#xff08;LSTM&#xff09;以及知识注意网络&#…

Java项目实战II基于微信小程序UNIAPP+SSM+MySQL的电子点餐系统(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 在当今快节…

华为配置 之 Console线路配置

目录 简介&#xff1a; 知识点&#xff1a; 配置Console线路密码 1.密码认证模式 2.AAA认证模式 知识点&#xff1a; 总结&#xff1a; 简介&#xff1a; 使用PC模拟器与路由器相连&#xff08;与交换机相连原理一样&#xff09;&#xff0c;在关机状态下&#xff0c;使用…

【CS常见问题】你用的是VS2019,最高支持.NET5.0,但是项目将.NET6.0设为目标无法运行,怎么办?

.NET版本问题 报错示例报错分析最简单的方法步骤 报错示例 严重性 代码 说明 项目 文件 行 禁止显示状态 错误 NETSDK1045 当前 .NET SDK 不支持将 .NET 6.0 设置为目标。请将 .NET 5.0 或更低版本设置为目标&#xff0c;或使用支持 .NET 6.0 的 .NET SDK 版本。 ABFview C:\x…

Request2:Post请求和Json

百度翻译拿到自己想看的数据&#xff0c;下图查看请求到数据的请求 preview提前看下 取出对应的RequestUrl &#xff0c;看出来要使用的话得用post请求 #!/usr/bin/env python # -*- coding:utf-8 -*- import requests import json if __name__ "__main__":#1.指定…

『 Linux 』HTTPS

文章目录 HTTPS协议密钥加密的原因加密方式数据指纹网络通信加密方案及短板CA认证CA证书的细节以及如何保证服务端公钥的安全性和数据完整性 CA认证后对称加密与非对称加密配合使用的安全性中间人的攻击方式 HTTPS协议 HTTPS协议并不是一个独立的协议,其是一种以HTTP协议为基础…

武汉融资融券开户佣金最低是多少?哪家证券交易两融利率最低?

编辑搜图 请点击输入图片描述&#xff08;最多18字&#xff09; 目前两融开户利率是在4%—5%&#xff0c;每个人的融资融券利率都是不一样的。低利率是需要提前联系证券公司的工作人员协助您进行开户&#xff0c;工作人员会根据您的个人需求向与您商谈利率的优惠策略。投资者…

Excel常用操作培训

1 Excel基本操作 1.1 常用快捷键 1.1.1快捷键操作工作簿、工作表 1.1.2快捷键操作 1.1.3单元格操作 1.1.4输入操作 2.1 常见功能描述 2.1.1 窗口功能栏 excel有很多功能可以用&#xff0c;新建文档后&#xff0c;可以最上方&#xff0c;可以看到所有的功能栏目 2.1.2 剪切板…

Unity中使用UnityEvent遇到Bug

UnityEvent绑定过程中&#xff0c;放在Start&#xff08;&#xff09;中绑定会报错&#xff08;通过脚本添加UnityEvent事件脚本&#xff0c;绑定&#xff09; 绑定事件放在OnEnable&#xff08;&#xff09;中不会报错&#xff0c;但是依然不可以立刻添加UnityEvent事件脚本紧…

一些小概念和实战有用的知识

------------------------- IDEA是热保存&#xff0c;能一直crtlz撤销的&#xff0c;除非已经代码入库了&#xff0c;入库也能看到git上该文件历史记录/本地历史记录(看以前自己改了什么) -------------------------- 引用bean时候最好写明一下名字&#xff0c;防止以后有多…

双十一期间有哪些入手不亏的数码好物?这五款优质产品不容错过!

在这个令人期待的双十一购物狂欢节期间&#xff0c;我们总希望能以最实惠的方式&#xff0c;入手那些能够提升生活品质的数码好物。但是还有一些人还在犹豫考虑&#xff0c;不知道入手什么产品比较好&#xff0c;我也是特地挑选了五款实用又富有创意的数码产品&#xff0c;希望…

通过AI检测越权漏洞的指令

通过AI检测越权漏洞的指令 这段指令描述了一个AI的功能和工作流程&#xff0c;主要是用于比较两个HTTP响应数据包&#xff0c;以检测潜在的越权行为。以下是对其内容的详细介绍&#xff1a; 效果 先看一个简单的示例效果&#xff1a; 指令详情 指令详情&#xff1a; {&q…

快速上手C语言【下】(非常详细!!!)

目录 1. 指针 1.1 指针是什么 1.2 指针类型 1.2.1 指针-整数 1.2.2 指针解引用 1.3 const修饰 1.4 字符指针 1.5 指针-指针 1.6 二级指针 2. 数组 2.1 定义和初始化 2.2 下标引用操作符[ ] 2.3 二维数组 2.4 终极测试 3. 函数 3.1 声明和定义 3.2 传值调用…

Java最全面试题->Java基础面试题->JavaEE面试题->Web应用服务器面试题

文章目录 Web应用服务器面试题Tomcat是什么?Tomcat缺省端口是多少&#xff0c;如何修改&#xff1f;Tomcat 有那几种Connector 运行模式&#xff1f;什么是Servlet&#xff1f;Servlet请求过程&#xff1f;Tomcat执行流程&#xff1f;Tomcat部署方式?什么是JBoss ?在JBoss 7…

数据结构与算法:贪心算法与应用场景

目录 11.1 贪心算法的原理 11.2 经典贪心问题 11.3 贪心算法在图中的应用 11.4 贪心算法的优化与扩展 总结 数据结构与算法&#xff1a;贪心算法与应用场景 贪心算法是一种通过选择当前最佳解来构造整体最优解的算法策略。贪心算法在很多实际问题中都取得了良好的效果&am…

双十一母婴必买清单 推荐超实用母婴用品

随着双十一购物狂欢节的临近&#xff0c;无数准父母和年轻家长开始摩拳擦掌&#xff0c;准备为家中的小宝贝抢购一系列高品质、实用的母婴用品。在这个年度最大的电商促销活动中&#xff0c;选择对的产品不仅能够节省开支&#xff0c;更能确保宝宝的健康成长与舒适生活。以下是…

告别微信封号!学会这5招,让你的账号坚不可摧

在这个信息爆炸的时代&#xff0c;无论是工作沟通、社交互动还是获取信息&#xff0c;微信都扮演着极其重要的角色。但是&#xff0c;随着微信平台规则的日益严格&#xff0c;账号被封的风险也随之增加。今天&#xff0c;我们就来聊聊如何有效防止 微信被封&#xff0c;让你的账…

Java基于SSM微信小程序物流仓库管理系统设计与实现(源码+lw+数据库+讲解等)

选题背景 随着社会的发展&#xff0c;社会的方方面面都在利用信息化时代的优势。互联网的优势和普及使得各种系统的开发成为必需。 本文以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#xff0c;它主要是采用java语言技术和mysql数据库来完成对系统的设计。整个…