1. 程式人生 > >暢購商城(十二):接入微信掃碼支付

暢購商城(十二):接入微信掃碼支付

> **好好學習,天天向上** > > 本文已收錄至我的Github倉庫[**DayDayUP**](https://github.com/RobodLee/DayDayUP):github.com/RobodLee/DayDayUP,歡迎Star + [暢購商城(一):環境搭建](https://blog.csdn.net/weixin_43461520/article/details/107095045) + [暢購商城(二):分散式檔案系統FastDFS](https://blog.csdn.net/weixin_43461520/article/details/107137843) + [暢購商城(三):商品管理](https://blog.csdn.net/weixin_43461520/article/details/107243543) + [暢購商城(四):Lua、OpenResty、Canal實現廣告快取與同步](https://blog.csdn.net/weixin_43461520/article/details/107348436) + [暢購商城(五):Elasticsearch實現商品搜尋](https://blog.csdn.net/weixin_43461520/article/details/107466286) + [暢購商城(六):商品搜尋](https://blog.csdn.net/weixin_43461520/article/details/107579868) + [暢購商城(七):Thymeleaf實現靜態頁](https://blog.csdn.net/weixin_43461520/article/details/107728072) + [暢購商城(八):微服務閘道器和JWT令牌](https://blog.csdn.net/weixin_43461520/article/details/107817503) + [暢購商城(九):Spring Security Oauth2](https://blog.csdn.net/weixin_43461520/article/details/108144023) + [暢購商城(十):購物車](https://blog.csdn.net/weixin_43461520/article/details/108268837) + [暢購商城(十一):訂單](https://blog.csdn.net/weixin_43461520/article/details/108319715) + [暢購商城(十二):接入微信支付](https://blog.csdn.net/weixin_43461520/article/details/108524375) ## 支付流程 ![](https://gitee.com/RobodLee/image_store/raw/master/Java/暢購商城12:接入微信支付/支付流程.png) 為了實現支付的功能,這裡選擇接入微信支付。流程就是我們通過訂單系統下單,然後訂單系統呼叫支付系統去向微信支付的伺服器傳送請求,然後獲取二維碼返回給使用者,然後訂單系統就開始監聽MQ。使用者掃碼支付後,支付系統將支付狀態存進MQ中。訂單系統檢測到使用者已經付錢了,就將訂單設為已支付,然後存進MySQL中。可能會因為網路問題導致訂單系統獲取不到支付狀態,所以訂單系統會定時向微信支付伺服器傳送請求去查詢訂單狀態。 ## 微信支付簡介 要想接入微信支付,就得有認證過的服務號,這個我沒有,所以申請不了。就用黑馬提供的賬號吧,我試了一下,可以用。 ```properties appid(公眾賬號ID):wx8397f8696b538317 mch_id(商戶號):1473426802 key(商戶金鑰):T6m9iK73b0kn9g5v426MKfHQH7X8rKwb ``` > 微信支付的開發文件:[https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1](https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1) 在這個官方的開發文件裡面介紹了微信支付相關的API並且提供了SDK。 ![](https://gitee.com/RobodLee/image_store/raw/master/Java/暢購商城12:接入微信支付/微信支付sdk目錄結構.png) 這個SDK的內容不多,只有幾個類,我稍微介紹一下: + WXPayConfig:這是個抽象類,裡面有幾個方法,是用來獲取核心引數的,比如公眾號id,商戶號,金鑰等,所以在使用的時候要先去例項化這個類將幾個重要引數配置進去。 + WXPay:和訂單相關的方法都封裝在這個類裡面,比如下單,查詢訂單,取消訂單等。裡面有個方法**fillRequestData()**,每次執行下單等操作的時候都會去呼叫這個方法將WXPayConfig中的幾個核心引數封裝到請求引數的Map集合裡。 + WXPayRequest:這個是負責請求伺服器的,WXPay也都是通過呼叫這個類中的方法去請求伺服器的,執行相應方法的時候,會將WXPay傳過來的Map集合轉換成XML格式的字串,然後使用HttpClient向伺服器傳送請求。沒錯,微信支付是通過XML進行資料傳輸的。 + WXPayUtil:這是個工具類,封裝了一些常用方法,比如Map轉XML,XML轉Map等。 在這個專案中用到的微信的Native支付,也就是掃碼支付,有兩種模式,我們用到的是模式二。 ![](https://gitee.com/RobodLee/image_store/raw/master/Java/暢購商城12:接入微信支付/微信掃碼支付模式二時序圖.png) 首先在暢購的訂單系統中生成訂單,然後將一些必要的引數傳入到微信支付的後臺,然後就會產生一個預支付的訂單,將支付連結返回給我們,我們再根據支付連結生成二維碼傳給使用者。使用者掃碼支付後再將支付結果傳到我們的後臺,這樣整個支付的流程就結束了。 ## 準備工作 介紹完了微信支付後,就來說一下專案中該怎麼去整合微信支付。視訊中用的是第三方的依賴,我用的是官方的。微信支付的SDK在Maven的遠端倉庫裡是沒有的,所以需要自己下載然後手動匯入。這裡面有兩個坑有必要說一下,前面不是提到**WXPayConfig**是個抽象類麼,那麼用的時候肯定得去繼承才能例項化吧。但是裡面的抽象方法都沒有許可權修飾符,所以預設是包訪問許可權,我們既然是Maven依賴這個SDK,那麼我們寫的程式碼自然不會和它在同一個包下,所以要先在這幾個抽象方法前面新增**public**修飾符。而且,微信提供的sdk文件裡還寫成了implements抽象類,真搞不懂微信怎麼會犯這種錯~~~ 現在就可以將這個SDK新增到我們本地的Maven倉庫裡了,在解壓後的sdk的根目錄下執行`mvn install`命令。 ![](https://gitee.com/RobodLee/image_store/raw/master/Java/暢購商城12:接入微信支付/mvninstallsdk.png) 當出現**BUILD SUCCESS**的字樣的時候,就說明已經成功新增到本地的Maven倉庫了。這時候第二個坑就來了,如果就這麼新增到我們的專案中就有可能會出現Maven依賴衝突: ![](https://gitee.com/RobodLee/image_store/raw/master/Java/暢購商城12:接入微信支付/maven依賴衝突.png) 可以看到,出現衝突的包是**slf4j-simple**,而微信支付sdk恰好依賴了這個包,所以在匯入微信支付的時候把這個依賴排除掉即可。 ```xml ``` 然後就可以建立支付的工程了。在changgou-service下建立一個Moudle名為**changgou-service-wechatpay**,然後**將微信支付的依賴新增到這個工程下**,啟動類沒啥好說的,配置檔案如下: ```yml 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作為引數可讀性不是好很多嗎。 ```java //建立二維碼 @RequestMapping(value = "/create/native") public Result createNative(@RequestBody Order order){