SpringBoot實現微信支付接口調用及回調函數(商戶參數獲取)
一、具體業(yè)務流程
1. 用戶下單
- 前端操作:
- 用戶在應用中選擇商品、填寫訂單信息(如地址、聯(lián)系方式等),并點擊“下單”按鈕。
- 前端將訂單信息(商品ID、數量、價格等)發(fā)送到后端。
- 后端處理:
- 接收到訂單請求后,生成唯一的訂單號(`out_trade_no`)。
- 將訂單信息存儲到數據庫中,設置訂單狀態(tài)為“待支付”。
2. 后端創(chuàng)建訂單
- 構建請求參數:
- 使用商戶號、應用ID、隨機字符串、訂單描述、商戶訂單號、金額(單位:分)、IP 地址等構建 XML 格式的請求數據。
- 發(fā)送請求:
- 使用 HTTP POST 方法將請求數據發(fā)送到微信的統(tǒng)一下單 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 數據。
- 驗證簽名:
- 提取回調數據中的簽名字段,使用相同的參數生成新的簽名,與返回的簽名進行比較,確保數據的完整性和有效性。
- 更新訂單狀態(tài):
- 根據回調數據中的 `result_code` 更新數據庫中的訂單狀態(tài)。如果支付成功,修改訂單狀態(tài)為“已支付”,并進行相應的業(yè)務處理(如發(fā)貨)。
- 返回處理結果:
- 向微信返回處理結果,通常是 `<xml><return_code>SUCCESS</return_code></xml>`。
6. 返回處理結果
- 響應微信:
- 確保響應格式正確,避免微信因無法解析而重發(fā)通知。
7. 訂單狀態(tài)查詢(可選)
- 查詢訂單狀態(tài):
- 在用戶支付后的一段時間內,可以調用微信的訂單查詢 API(`https://api.mch.weixin.qq.com/pay/orderquery`)來確認訂單的狀態(tài)。
- 處理結果:
- 根據查詢結果更新本地訂單狀態(tài),確保數據一致性。
8. 訂單完成
- 后續(xù)處理:
- 一旦訂單支付成功并發(fā)貨,可以根據業(yè)務需求進行后續(xù)操作,例如發(fā)送確認郵件、更新庫存等。
二、代碼具體實現
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. 創(chuàng)建 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. 創(chuàng)建微信支付服務類
創(chuàng)建一個服務類 WeChatPayService
,用于處理訂單的創(chuàng)建和簽名等操作。
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. 創(chuàng)建微信支付控制器
創(chuàng)建一個控制器 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)) { // 處理業(yè)務邏輯,例如更新訂單狀態(tài) String resultCode = data.get("result_code"); if ("SUCCESS".equals(resultCode)) { String orderNo = data.get("out_trade_no"); // 更新訂單狀態(tài)為已支付 // updateOrderStatus(orderNo, "PAID"); } return "<xml><return_code>SUCCESS</return_code></xml>"; } else { return "<xml><return_code>FAIL</return_code></xml>"; } } }
5. 簽名和 XML 處理工具類
創(chuàng)建一個工具類 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微信支付接口調用內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
java中gradle項目報錯org.gradle?.api.plugins.MavenPlugin解決辦法
在使用Gradle時開發(fā)者可能會遇到org.gradle?.api.plugins.MavenPlugin報錯提醒,這篇文章主要給大家介紹了關于java中gradle項目報錯org.gradle?.api.plugins.MavenPlugin的解決辦法,需要的朋友可以參考下2023-12-12springboot?vue測試列表遞歸查詢子節(jié)點下的接口功能實現
這篇文章主要為大家介紹了springboot?vue測試列表遞歸查詢子節(jié)點下的接口功能實現,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-05-05MyBatis_Generator插件的安裝以及簡單使用方法(圖解)
下面小編就為大家?guī)硪黄狹yBatis_Generator插件的安裝以及簡單使用方法(圖解)。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-05-05