SpringBoot实现微信支付接口调用及回调函数(商户参数获取)
作者:guicai_guojia
一、具体业务流程
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微信支付接口调用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!