好好學習,天天向上
本文已收錄至我的Github倉庫DayDayUP:github.com/RobodLee/DayDayUP,歡迎Star
- 暢購商城(一):環境搭建
- 暢購商城(二):分布式檔案系統FastDFS
- 暢購商城(三):商品管理
- 暢購商城(四):Lua、OpenResty、Canal實作廣告快取與同步
- 暢購商城(五):Elasticsearch實作商品搜索
- 暢購商城(六):商品搜索
- 暢購商城(七):Thymeleaf實作靜態頁
- 暢購商城(八):微服務網關和JWT令牌
- 暢購商城(九):Spring Security Oauth2
- 暢購商城(十):購物車
- 暢購商城(十一):訂單
- 暢購商城(十二):接入微信支付
支付流程

為了實作支付的功能,這里選擇接入微信支付,流程就是我們通過訂單系統下單,然后訂單系統呼叫支付系統去向微信支付的服務器發送請求,然后獲取二維碼回傳給用戶,然后訂單系統就開始監聽MQ,用戶掃碼支付后,支付系統將支付狀態存進MQ中,訂單系統檢測到用戶已經付錢了,就將訂單設為已支付,然后存進MySQL中,可能會因為網路問題導致訂單系統獲取不到支付狀態,所以訂單系統會定時向微信支付服務器發送請求去查詢訂單狀態,
微信支付簡介
要想接入微信支付,就得有認證過的服務號,這個我沒有,所以申請不了,就用黑馬提供的賬號吧,我試了一下,可以用,
appid(公眾賬號ID):wx8397f8696b538317
mch_id(商戶號):1473426802
key(商戶密鑰):T6m9iK73b0kn9g5v426MKfHQH7X8rKwb
微信支付的開發檔案:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1
在這個官方的開發檔案里面介紹了微信支付相關的API并且提供了SDK,

這個SDK的內容不多,只有幾個類,我稍微介紹一下:
WXPayConfig:這是個抽象類,里面有幾個方法,是用來獲取核心引數的,比如公眾號id,商戶號,密鑰等,所以在使用的時候要先去實體化這個類將幾個重要引數配置進去,
WXPay:和訂單相關的方法都封裝在這個類里面,比如下單,查詢訂單,取消訂單等,里面有個方法fillRequestData(),每次執行下單等操作的時候都會去呼叫這個方法將WXPayConfig中的幾個核心引數封裝到請求引數的Map集合里,
WXPayRequest:這個是負責請求服務器的,WXPay也都是通過呼叫這個類中的方法去請求服務器的,執行相應方法的時候,會將WXPay傳過來的Map集合轉換成XML格式的字串,然后使用HttpClient向服務器發送請求,沒錯,微信支付是通過XML進行資料傳輸的,
WXPayUtil:這是個工具類,封裝了一些常用方法,比如Map轉XML,XML轉Map等,
在這個專案中用到的微信的Native支付,也就是掃碼支付,有兩種模式,我們用到的是模式二,

首先在暢購的訂單系統中生成訂單,然后將一些必要的引數傳入到微信支付的后臺,然后就會產生一個預支付的訂單,將支付鏈接回傳給我們,我們再根據支付鏈接生成二維碼傳給用戶,用戶掃碼支付后再將支付結果傳到我們的后臺,這樣整個支付的流程就結束了,
準備作業
介紹完了微信支付后,就來說一下專案中該怎么去集成微信支付,視頻中用的是第三方的依賴,我用的是官方的,微信支付的SDK在Maven的遠程倉庫里是沒有的,所以需要自己下載然后手動匯入,這里面有兩個坑有必要說一下,前面不是提到WXPayConfig是個抽象類么,那么用的時候肯定得去繼承才能實體化吧,但是里面的抽象方法都沒有權限修飾符,所以默認是包訪問權限,我們既然是Maven依賴這個SDK,那么我們寫的代碼自然不會和它在同一個包下,所以要先在這幾個抽象方法前面添加public修飾符,而且,微信提供的sdk檔案里還寫成了implements抽象類,真搞不懂微信怎么會犯這種錯~~~
現在就可以將這個SDK添加到我們本地的Maven倉庫里了,在解壓后的sdk的根目錄下執行mvn install命令,

當出現BUILD SUCCESS的字樣的時候,就說明已經成功添加到本地的Maven倉庫了,這時候第二個坑就來了,如果就這么添加到我們的專案中就有可能會出現Maven依賴沖突:

可以看到,出現沖突的包是slf4j-simple,而微信支付sdk恰好依賴了這個包,所以在匯入微信支付的時候把這個依賴排除掉即可,
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>3.0.9</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</exclusion>
</exclusions>
</dependency>
然后就可以創建支付的工程了,在changgou-service下創建一個Moudle名為changgou-service-wechatpay,然后將微信支付的依賴添加到這個工程下,啟動類沒啥好說的,組態檔如下:
server:
port: 18090
spring:
application:
name: wechatpay
main:
allow-bean-definition-overriding: true
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:7001/eureka
instance:
prefer-ip-address: true
feign:
hystrix:
enabled: true
#hystrix 配置
hystrix:
command:
default:
execution:
timeout:
#如果enabled設定為false,則請求超時交給ribbon控制
enabled: true
isolation:
strategy: SEMAPHORE
#微信支付資訊配置
wechat:
# 應用id
app_id: wx8397f8696b538317
# 商戶號id
mch_id: 1473426802
# 密鑰
key: T6m9iK73b0kn9g5v426MKfHQH7X8rKwb
# 支付回呼地址
notify_url: http://www.itcast.cn
這里配置了appid,mch_id,key,notify_url這幾個引數,用的時候直接讀取就可以了,這樣支付微服務就搭建好了,
微信支付二維碼生成
添加一個Controller層的類WeChatPayController,然后再創建一個入口方法,因為二維碼支付叫做Native支付,所以這里就起名為createNative了,接收一個Order引數,視頻中用的是Map接收引數,但是既然是創建訂單,直接用Order作為引數可讀性不是好很多嗎,
//創建二維碼
@RequestMapping(value = https://www.cnblogs.com/robod/p/"/create/native")
public Result createNative(@RequestBody Order order){
Map resultMap = weChatPayService.createNative(order);
return new Result(true, StatusCode.OK,"創建二維碼預付訂單成功!",resultMap);
}
寫完了Controller就可以寫Service層了,視頻中是用HttpClient呼叫微信支付的遠程介面,既然微信已經提供了sdk,為什么還要重復造輪子呢?所以我就沒和視頻中寫的一樣,而是直接使用微信的sdk,雖然底層用的也是HttpClient,
首先需要將WXPayConfig給實作一下,
public class MyWXPayConfig extends WXPayConfig {
private String appId;
private String mchId;
private String key;
public MyWXPayConfig(String appId, String mchId, String key) {
this.appId = appId;
this.mchId = mchId;
this.key = key;
}
@Override
public String getAppID() {
return appId;
}
@Override
public String getMchID() {
return mchId;
}
@Override
public String getKey() {
return key;
}
@Override
public InputStream getCertStream() {
return null;
}
@Override
public int getHttpConnectTimeoutMs() {
return 8000;
}
@Override
public int getHttpReadTimeoutMs() {
return 10000;
}
@Override
public IWXPayDomain getWXPayDomain() {
IWXPayDomain iwxPayDomain = new IWXPayDomain() {
@Override
public void report(String domain, long elapsedTimeMillis, Exception ex) {
}
@Override
public DomainInfo getDomain(WXPayConfig config) {
return new IWXPayDomain.DomainInfo(WXPayConstants.DOMAIN_API, true);
}
};
return iwxPayDomain;
}
}
然后在WeChatPayServiceImpl撰寫相應的代碼,
@Value("${wechat.appid}")
private String appId;
@Value("${wechat.mch_id}")
private String mcnId;
@Value("${wechat.key}")
private String key;
@Value("${wechat.notify_url}")
private String notifyUrl;
@Override
public Map<String, String> createNative(Order order) {
try {
Map<String, String> map = new HashMap<>(16);
map.put("body", "騰訊充值中心-QQ會員充值"); //商品描述
map.put("out_trade_no", order.getId()); //商戶訂單號
map.put("total_fee", String.valueOf((int)(order.getTotalMoney() * 100))); //標價金額,單位為分
map.put("spbill_create_ip", "127.0.0.1"); //終端IP
map.put("trade_type", "NATIVE "); //交易型別,JSAPI -JSAPI支付,NATIVE -Native支付,APP -APP支付
Map<String, String> response = wxpay.unifiedOrder(map);
if (response == null || response.size() == 0) {
throw new RuntimeException("下單失敗");
}
return response;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
這里用到了**@Value注解將組態檔中的幾個引數注入了進來,然后將創建訂單的幾個引數添加到Map集合中,鍵的名稱在檔案中有說明,不能改變,金額的單位是分,我們傳過來的是元,所以需要乘100,微信要求金額是整數,所以再強轉成int,然后就去創建MyWXPayConfig的實體,將三個引數傳入進入,然后去創建WXPay的物件,將config和notifyUrl傳入進去,然后呼叫unifiedOrder()**方法把map傳入進去就可以創建訂單了,其實內部就是把appid這幾個引數放在了我們傳入的map中,所以在這里放入到map中也是OK的,

測驗一下,OK了,成功創建了訂單,也拿到了二維碼的地址,接下來只要把code_url轉換成二維碼圖片就可以了,
如果是做測驗,隨便在網上找個二維碼生成器,然后把code_url復制過去就行了,在專案中是用qrious生成,
<html>
<head>
<title>二維碼入門小demo</title>
<!--1.引入js 2. 創建一個img標簽 用來存盤顯示二維碼的圖片 3.創建js物件 4.設定js物件的配置項-->
<script src=https://www.cnblogs.com/robod/p/"qrious.js"> </script>
<body>






