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

 更新时间:2024年11月21日 11:39:50   作者:guicai_guojia  
本文详细介绍了使用SpringBoot实现微信支付接口调用及回调函数的步骤,提供了代码实现的具体步骤和工具类的创建,感兴趣的朋友跟随小编一起看看吧

 一、具体业务流程

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);
    }
}

三、参数配置及获取

一、回调函数的配置步骤

  • 在微信商户平台配置回调地址

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

二、商户参数获取

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

商户参数

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

到此这篇关于SpringBoot实现微信支付接口调用及回调函数(商户参数获取)的文章就介绍到这了,更多相关SpringBoot微信支付接口调用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Gradle:修改默认的Build配置文件名方式

    Gradle:修改默认的Build配置文件名方式

    这篇文章主要介绍了Gradle:修改默认的Build配置文件名方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • MyBatis的各种查询功能结果接收类型的选择(推荐)

    MyBatis的各种查询功能结果接收类型的选择(推荐)

    文章介绍了MyBatis中查询结果的不同接收方式,包括单条数据和多条数据的处理方法,以及MyBatis的默认类型别名,感兴趣的朋友跟随小编一起看看吧
    2024-11-11
  • Java线程的生命周期和状态控制_动力节点Java学院整理

    Java线程的生命周期和状态控制_动力节点Java学院整理

    这篇文章主要介绍了Java线程的生命周期和状态控制,需要的朋友可以参考下
    2017-05-05
  • 通过实例解析Java分布式锁三种实现方法

    通过实例解析Java分布式锁三种实现方法

    这篇文章主要介绍了通过实例解析Java分布式锁三种实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-07-07
  • 聊一聊concurrenthashmap的size方法原理

    聊一聊concurrenthashmap的size方法原理

    这篇文章主要介绍了concurrenthashmap的size方法原理,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-02-02
  • Java中RSA加密解密的实现方法分析

    Java中RSA加密解密的实现方法分析

    这篇文章主要介绍了Java中RSA加密解密的实现方法,结合具体实例形式分析了java实现RSA加密解密算法的具体步骤与相关操作技巧,并附带了关于RSA算法密钥长度/密文长度/明文长度的参考说明,需要的朋友可以参考下
    2017-07-07
  • @ConfigurationProperties在IDEA中出现红色波浪线问题解决方法

    @ConfigurationProperties在IDEA中出现红色波浪线问题解决方法

    本文介绍了在Springboot项目中,当@ConfigurationProperties注解出现红色波浪线时的解决方法,文中有详细的解决方案供大家参考,需要的朋友可以参考下
    2024-09-09
  • Spring的Model 和 Map的原理源码解析

    Spring的Model 和 Map的原理源码解析

    这篇文章主要介绍了Spring的Model 和 Map的原理解析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-06-06
  • Dubbo异步调用的实现介绍

    Dubbo异步调用的实现介绍

    dubbo默认使用同步的方式调用。但在有些特殊的场景下,我们可能希望异步调用dubbo接口,从而避免不必要的等待时间,这时候我们就需要用到异步。那么dubbo的异步是如何实现的呢?下面就来看看这个问题
    2022-09-09
  • SpringCloud zookeeper作为注册中心使用介绍

    SpringCloud zookeeper作为注册中心使用介绍

    ZooKeeper由雅虎研究院开发,是Google Chubby的开源实现,后来托管到Apache,于2010年11月正式成为Apache的顶级项目。ZooKeeper是一个经典的分布式数据一致性解决方案,致力于为分布式应用提供一个高性能、高可用,且具有严格顺序访问控制能力的分布式协调服务
    2022-11-11

最新评论