0


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

#1024程序员节 | 征文 #

一、具体业务流程

1. 用户下单

  • 前端操作:

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

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

2. 后端创建订单

  • 构建请求参数:

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

    • 使用 HTTP POST 方法将请求数据发送到微信的统一下单 API(https://api.mch.weixin.qq.com/pay/unifiedorder)。
  • 处理响应:

    • 接收微信返回的响应数据(XML 格式),解析响应内容。
    • 检查返回的 return_coderesult_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. 商户参数配置

  1. application.properties

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

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

2. 创建 Spring Boot 项目

确保你的项目引入了必要的依赖。在

  1. pom.xml

中添加以下内容:

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-web</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.apache.httpcomponents</groupId>
  7. <artifactId>httpclient</artifactId>
  8. </dependency>
  9. <dependency>
  10. <groupId>com.thoughtworks.xstream</groupId>
  11. <artifactId>xstream</artifactId>
  12. <version>1.4.18</version>
  13. </dependency>

3. 创建微信支付服务类

创建一个服务类

  1. WeChatPayService

,用于处理订单的创建和签名等操作。

  1. import org.apache.http.client.methods.HttpPost;
  2. import org.apache.http.entity.StringEntity;
  3. import org.apache.http.impl.client.CloseableHttpClient;
  4. import org.apache.http.impl.client.HttpClients;
  5. import org.apache.http.util.EntityUtils;
  6. import org.springframework.beans.factory.annotation.Value;
  7. import org.springframework.stereotype.Service;
  8. import java.util.HashMap;
  9. import java.util.Map;
  10. @Service
  11. public class WeChatPayService {
  12. @Value("${wechat.pay.appId}")
  13. private String appId;
  14. @Value("${wechat.pay.mchId}")
  15. private String mchId;
  16. @Value("${wechat.pay.apiKey}")
  17. private String apiKey;
  18. @Value("${wechat.pay.notifyUrl}")
  19. private String notifyUrl;
  20. private static final String UNIFIED_ORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
  21. public String createOrder(String orderNo, double amount) throws Exception {
  22. String nonceStr = String.valueOf(System.currentTimeMillis());
  23. String xmlData = "<xml>"
  24. + "<appid>" + appId + "</appid>"
  25. + "<mch_id>" + mchId + "</mch_id>"
  26. + "<nonce_str>" + nonceStr + "</nonce_str>"
  27. + "<body>Product Description</body>"
  28. + "<out_trade_no>" + orderNo + "</out_trade_no>"
  29. + "<total_fee>" + (int) (amount * 100) + "</total_fee>"
  30. + "<spbill_create_ip>127.0.0.1</spbill_create_ip>"
  31. + "<notify_url>" + notifyUrl + "</notify_url>"
  32. + "<trade_type>APP</trade_type>"
  33. + "</xml>";
  34. // 生成签名并添加到请求数据
  35. String sign = WeChatPayUtil.generateSign(xmlData, apiKey);
  36. xmlData = xmlData.replace("</xml>", "<sign>" + sign + "</sign></xml>");
  37. try (CloseableHttpClient client = HttpClients.createDefault()) {
  38. HttpPost post = new HttpPost(UNIFIED_ORDER_URL);
  39. post.setEntity(new StringEntity(xmlData, "UTF-8"));
  40. post.setHeader("Content-Type", "text/xml");
  41. String response = EntityUtils.toString(client.execute(post).getEntity(), "UTF-8");
  42. return response; // 解析并返回需要的信息
  43. }
  44. }
  45. }

4. 创建微信支付控制器

创建一个控制器

  1. WeChatPayController

,处理用户的下单请求(@PostMapping("/createOrder"))和回调@PostMapping("/notify")。

  1. import org.springframework.beans.factory.annotation.Autowired;
  2. import org.springframework.web.bind.annotation.*;
  3. import javax.servlet.http.HttpServletRequest;
  4. @RestController
  5. @RequestMapping("/wechat")
  6. public class WeChatPayController {
  7. @Autowired
  8. private WeChatPayService weChatPayService;
  9. @PostMapping("/createOrder")
  10. public String createOrder(@RequestParam String orderNo, @RequestParam double amount) {
  11. try {
  12. return weChatPayService.createOrder(orderNo, amount);
  13. } catch (Exception e) {
  14. e.printStackTrace();
  15. return "Error creating order";
  16. }
  17. }
  18. @PostMapping("/notify")
  19. public String handleCallback(HttpServletRequest request) {
  20. StringBuilder sb = new StringBuilder();
  21. try (BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()))) {
  22. String line;
  23. while ((line = reader.readLine()) != null) {
  24. sb.append(line);
  25. }
  26. } catch (IOException e) {
  27. e.printStackTrace();
  28. }
  29. String xmlData = sb.toString();
  30. Map<String, String> data = WeChatPayUtil.parseXml(xmlData); // 解析 XML 数据
  31. // 验证签名
  32. String sign = data.get("sign");
  33. if (WeChatPayUtil.generateSign(xmlData, apiKey).equals(sign)) {
  34. // 处理业务逻辑,例如更新订单状态
  35. String resultCode = data.get("result_code");
  36. if ("SUCCESS".equals(resultCode)) {
  37. String orderNo = data.get("out_trade_no");
  38. // 更新订单状态为已支付
  39. // updateOrderStatus(orderNo, "PAID");
  40. }
  41. return "<xml><return_code>SUCCESS</return_code></xml>";
  42. } else {
  43. return "<xml><return_code>FAIL</return_code></xml>";
  44. }
  45. }
  46. }

5. 签名和 XML 处理工具类

创建一个工具类

  1. WeChatPayUtil

,负责签名和 XML 解析。

  1. import com.thoughtworks.xstream.XStream;
  2. import java.security.MessageDigest;
  3. import java.util.HashMap;
  4. import java.util.Map;
  5. import java.util.TreeMap;
  6. public class WeChatPayUtil {
  7. public static String generateSign(String xmlData, String apiKey) {
  8. // 将 XML 转换为 Map
  9. Map<String, String> data = parseXml(xmlData);
  10. TreeMap<String, String> sortedMap = new TreeMap<>(data);
  11. StringBuilder stringBuilder = new StringBuilder();
  12. for (Map.Entry<String, String> entry : sortedMap.entrySet()) {
  13. if (!entry.getKey().equals("sign") && entry.getValue() != null) {
  14. stringBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
  15. }
  16. }
  17. stringBuilder.append("key=").append(apiKey);
  18. return md5(stringBuilder.toString()).toUpperCase();
  19. }
  20. public static String md5(String input) {
  21. try {
  22. MessageDigest md = MessageDigest.getInstance("MD5");
  23. byte[] digest = md.digest(input.getBytes());
  24. StringBuilder hexString = new StringBuilder();
  25. for (byte b : digest) {
  26. String hex = Integer.toHexString(0xFF & b);
  27. if (hex.length() == 1) hexString.append('0');
  28. hexString.append(hex);
  29. }
  30. return hexString.toString();
  31. } catch (Exception e) {
  32. throw new RuntimeException(e);
  33. }
  34. }
  35. public static Map<String, String> parseXml(String xml) {
  36. // 使用 XStream 解析 XML
  37. XStream xStream = new XStream();
  38. xStream.alias("xml", HashMap.class);
  39. return (Map<String, String>) xStream.fromXML(xml);
  40. }
  41. }

三、参数配置及获取

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

二、商户参数获取

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

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

本文转载自: https://blog.csdn.net/m0_66572126/article/details/143175353
版权归原作者 guicai_guojia 所有, 如有侵权,请联系我们删除。

“SpringBoot实现微信支付接口调用及回调函数(商户参数获取)”的评论:

还没有评论