# 一、前言 [從零玩轉系列之微信支付實戰PC端支付微信取消介面搭建 | 技術創作特訓營第一期 ](https://cloud.tencent.com/developer/article/2308342) halo各位大佬很久沒更新了最近在搞微信支付,因商戶號審核了我半個月和小程式認證也找了資料並 ...
一、前言
從零玩轉系列之微信支付實戰PC端支付微信取消介面搭建 | 技術創作特訓營第一期
halo各位大佬很久沒更新了最近在搞微信支付,因商戶號審核了我半個月和小程式認證也找了資料並且將商戶號和小程式進行關聯,至此微信支付Native支付完成.此篇文章過長我將分幾個階段的文章發佈(項目源碼都有,小程式和PC端)
在此之前已經更新了微信支付開篇、微信支付安全、微信實戰基礎框架搭建、本次更新為微信支付實戰PC端介面搭建,實戰篇分為幾個章節因為代碼量確實有點多哈.
- 第一章從零玩轉系列之微信支付開篇
- 第二章從零玩轉系列之微信支付安全
- 第三章從零玩轉系列之微信支付實戰基礎框架搭建
- 第四章從零玩轉系列之微信支付實戰PC端支付下單介面搭建
- 第五章從零玩轉系列之微信支付實戰PC端支付微信回調介面搭建
- 第五章從零玩轉系列之微信支付實戰PC端支付微信取消訂單介面搭建
- 第六章從零玩轉系列之微信支付實戰PC端支付微信退款訂單介面搭建
本次項目使用技術棧
後端: SpringBoot3.1.x、Mysql8.0、MybatisPlus
前端: Vue3、Vite、ElementPlus
小程式: Uniapp、Uview
一、取消訂單介面
場景
- 用戶下單完畢後未支付 可進行取消訂單
- 訂單超時支付系統自動取消訂單
修改 WechatNativeController
/**
* 用戶取消訂單
*/
@PostMapping("/cancel/{orderNo}")
public R<String> cancel(@PathVariable String orderNo) {
log.info("取消訂單");
wxPayService.cancelOrder(orderNo);
return R.ok("訂單已取消");
}
修改 wxPayService
/**
* 關閉訂單
*/
@SneakyThrows
public void cancelOrder(String orderNo) {
// ...../
}
邏輯分析
在工作中我們邏輯可能是這樣子的
step 1 查詢該訂單狀態是否需要關閉訂單,如果訂單已經關閉則不需要再次關閉
思考: 我們應該去哪裡查詢訂單的狀態?
假如我們去資料庫查詢記錄的話,如果資料庫因為什麼原因導致狀態可能不對呢?
所以我們直接去微信伺服器查最新的直接更新關閉狀態到資料庫當中
你看微信也要我們這樣子玩那就萬無一失直接乾
================================================================
好既然我們要去調用微信查詢介面我們是不是可以封裝一個通用的 後續肯定有其他地方也會調用查詢支付信息的情況
文檔(商戶): https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_2.shtml
有兩種查詢方式第二種方便就這麼簡單
代碼很好理解傳遞商戶訂單號和直連商戶號mchid
/**
* 抽出公共獲取微信訂單信息
*/
private WeChartOrderInfo selectOrderInfo(String orderNo) throws IOException {
log.info("查詢訂單,直連商戶號:{} , 微信支付訂單號: {}", orderNo, wxPayConfig.getMchId());
String url = wxPayConfig.getDomain().concat(String.format(WxApiType.ORDER_QUERY_BY_NO.getType(), orderNo)).concat("?mchid=").concat(wxPayConfig.getMchId());
HttpGet httpGet = new HttpGet(url);
httpGet.setHeader("Accept", "application/json");
CloseableHttpResponse response = wxPayClient.execute(httpGet);
WeChartOrderInfo weChartOrderInfo = buildBodyParams(response, WeChartOrderInfo.class);
log.info("查詢訂單響應, {}", weChartOrderInfo);
response.close();
return weChartOrderInfo;
}
響應結果
{
"amount": {
"currency": "CNY",
"payer_currency": "CNY",
"payer_total": 1,
"total": 1
},
"appid": "wxdace645e0bc2cXXX",
"attach": "",
"bank_type": "OTHERS",
"mchid": "1900006XXX",
"out_trade_no": "44_2126281063_5504",
"payer": {
"openid": "o4GgauJP_mgWEWictzA15WT15XXX"
},
"promotion_detail": [],
"success_time": "2021-03-22T10:29:05+08:00",
"trade_state": "SUCCESS",
"trade_state_desc": "支付成功",
"trade_type": "JSAPI",
"transaction_id": "4200000891202103228088184743"
}
完善邏輯
/**
* 關閉訂單
*/
@SneakyThrows
public void cancelOrder(String orderNo) {
// step 1 查詢該訂單狀態是否需要關閉訂單
WeChartOrderInfo state = selectOrderInfo(orderNo);
// 判斷如果訂單已經關閉則不需要再次關閉 更新資料庫
if (null == state || state.getTrade_state() == null) {
// 更新本地訂單狀態超時關閉訂單
orderInfoService.lambdaUpdate().eq(OrderInfo::getOrderNo, orderNo).set(OrderInfo::getOrderStatus, OrderStatus.CLOSED.getType()).update();
return;
}
// step 2 還未支付才能取消訂單
if (state.getTrade_state().equals(OrderStatus.NOTPAY.name())) {
// step 2 進行調用微信關閉訂單介面
sendCloseRequest(orderNo);
// step 2 更新商戶端的訂單狀態用戶取消訂單
this.orderInfoService.lambdaUpdate().eq(OrderInfo::getOrderNo, orderNo).set(OrderInfo::getOrderStatus, OrderStatus.CANCEL.getType()).update();
}
}
抽出通用訂單關閉代碼
文檔: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_3.shtml
/**
* 發送關閉訂單請求
*
* @param orderNo 訂單編號
*/
@SneakyThrows
private void sendCloseRequest(String orderNo) {
log.info("關閉訂單, 訂單號:{}", orderNo);
String url = String.format(wxPayConfig.getDomain().concat(WxApiType.CLOSE_ORDER_BY_NO.getType()), orderNo);
HttpPost httpPost = new HttpPost(url);
Map<String, Object> paramsMap = new HashMap<>(1);
paramsMap.put("mchid", wxPayConfig.getMchId());
String jsonParams = JSONUtil.toJsonStr(paramsMap);
log.info("請求參數 ===> {}", jsonParams);
StringEntity entity = new StringEntity(jsonParams, "utf-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
httpPost.setHeader("Accept", "application/json");
try (CloseableHttpResponse response = wxPayClient.execute(httpPost)) {
log.info("關單響應: {}", response.getEntity());
log.info("解析body {}", buildBodyParams(response, Map.class));
}
}
到這裡訂單取消就完畢了
二、查詢訂單介面
根據上面編寫的查詢訂單方法完善一下
修改 WechatNativeController
/**
* 查詢訂單
*/
@PostMapping("/query/{orderNo}")
public R<WeChartOrderInfo> query(@PathVariable String orderNo) {
log.info("查詢訂單");
return R.ok(wxPayService.queryOrder(orderNo));
}
修改 WxPayService
/**
* 查詢訂單信息
*
* @param orderNo 訂單號
* @return 訂單信息
*/
@SneakyThrows
public WeChartOrderInfo queryOrder(String orderNo) {
return this.selectOrderInfo(orderNo);
}
好了查詢介面也寫完了so easy to happy !
我們來測試看看是什麼效果咯~
三、測試
下單
我們還沒編寫到前端來所以還是和之前的文章操作一樣使介面調試工具操作這裡我使用之前推薦的IDEA FastRequest插件如下圖
發送
生成二維碼
複製codeUrl
參數打開草料 https://cli.im/url
不要支付哦我們確保訂單是否成功創建,確保二維碼沒有過期哦
我們也可以先看看訂單啥狀態上面我們不是寫了個查詢訂單詳情的嘛
調用取消訂單介面
複製 orderNo
訂單編號直接發送取消完成
在查詢一下訂單看看狀態是不是取消成功
【寫作提綱】
I. 前言
A. 通過前言表達我每次的文章內容是什麼東西
II. 取消訂單介面實現
A. 集結生活之中的場景來解析他的邏輯
III. 查詢訂單介面實現
A. 完善取消訂單介面當中已經實現了的功能
IV. 測試
A. 通過測試用例一步步排查編寫是否存在BUG
你的壓力來源於無法自律,只是假裝努力,現狀跟不上內心欲望,所以你焦慮又恐慌。——楊不易