<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      pay-spring-boot 開(kāi)箱即用的Java支付模塊,整合支付寶支付、微信支付

      關(guān)于

      使用本模塊,可輕松實(shí)現(xiàn)支付寶支付、微信支付對(duì)接,從而專(zhuān)注于業(yè)務(wù),無(wú)需關(guān)心第三方邏輯。

      模塊完全獨(dú)立,無(wú)支付寶、微信SDK依賴(lài)。

      基于Spring Boot。

      依賴(lài)Redis。

       

      我能做什么

      支付寶:電腦網(wǎng)站支付、手機(jī)網(wǎng)站支付、掃碼支付、APP支付。

      微信:電腦網(wǎng)站支付(同掃碼支付)、手機(jī)網(wǎng)站支付(微信外H5支付)、掃碼支付、APP支付、JSAPI支付(微信內(nèi)H5支付)。

      統(tǒng)一支付方法。

      異步回調(diào)封裝。

      訂單狀態(tài)查詢(xún)。

      退款。

      公對(duì)私轉(zhuǎn)賬。

      請(qǐng)確保支付寶、微信帳號(hào)已經(jīng)申請(qǐng)了相應(yīng)業(yè)務(wù)、權(quán)限

       

      模塊集成

      只需要簡(jiǎn)單的、非侵入式的配置,即可集成到項(xiàng)目中。

       

      添加模塊到Maven項(xiàng)目中

      父項(xiàng)目中添加pay-spring-boot模塊依賴(lài)(pom.xml):

      1 <modules>
      2     ...
      3     <module>pay-spring-boot</module>
      4     ...
      5 </modules>

       

      修改pay-spring-boot的父項(xiàng)目(pom.xml):

      1 <parent>
      2     <groupId>yourself parent groupId</groupId>
      3     <artifactId>yourself parent artifactId</artifactId>
      4     <version>yourself parent version</version>
      5 </parent>

       

      支付憑證

      application.yml(或application-*.yml,視項(xiàng)目具體情況而定)中添加如下配置:

      pay:
        wx:
          appid: wx1d96c6yxxc0d192a
          mchid: 1519719912
          key: A6nvI8Xp6A6nvI8Xp6A6nvI8Xp6
          notifyURL: https://xxx.com/wxpay/notify
          certPath: /data/cert/wx/apiclient_cert.p12
          certPassword: 1517923901
        ali:
          appid: 2019138363328891
          privateKey: MIIEuwIBADANBgkqhkiG9w...
          notifyURL: https://xxx.com/alipay/notify

       

      關(guān)于配置項(xiàng)的具體含義參考AliPayConfigWxPayConfig兩個(gè)類(lèi),里邊有詳細(xì)說(shuō)明。

       

      注入Redis連接池

      在項(xiàng)目中創(chuàng)建一個(gè)Redis連接池工廠實(shí)現(xiàn)類(lèi),名稱(chēng)無(wú)所謂,必須實(shí)現(xiàn)RedisResourceFactory接口,然后添加@ResourceFactoryComponent注解,例如:

       1 @ResourceFactoryComponent
       2 public class DefaultRedisResourceFactory implements RedisResourceFactory {
       3     @Override
       4     public JedisPool getJedisPool() {
       5         /*
       6           框架不關(guān)心JedisPool是怎么來(lái)的
       7           這里的RedisService是我自己實(shí)現(xiàn)的服務(wù)
       8           根據(jù)項(xiàng)目實(shí)際情況換成你自己的實(shí)現(xiàn)
       9         */
      10         return RedisService.getPool();
      11     }
      12 }

       

      如何支付

      一般來(lái)說(shuō),項(xiàng)目中會(huì)有不同的支付場(chǎng)景,比如:購(gòu)買(mǎi)商品、充值等支付業(yè)務(wù)。

      現(xiàn)在用商品購(gòu)買(mǎi)舉例,通過(guò)這個(gè)例子展示如何使用框架。

       

      創(chuàng)建支付適配器

      支付適配器是支付模塊和數(shù)據(jù)訪問(wèn)層的橋梁,適配器將支付結(jié)果抽象成支付成功(doPaySuccess)支付失敗(doPayFail)退款成功(doRefundSuccess)退款失敗(doRefundFail)四種情況,代表了四個(gè)狀態(tài)。

      建議不同的場(chǎng)景使用不同的適配器,不要所有業(yè)務(wù)邏輯都放一起。

      創(chuàng)建訂單的操作,也建議放在適配器中實(shí)現(xiàn)。

      以下是商品適配器例子:

       1 @Service
       2 public class GoodsTradeService extends AbstractPayAdaptor {
       3     
       4     @Autowired
       5     private GoodsTradeManager goodsTradeManager;
       6 ?
       7     /**
       8      * 創(chuàng)建訂單
       9      * @param id 商品id
      10      * @return
      11      */
      12     public Message createOrder(long id){
      13         
      14     }
      15 ?
      16     @Override
      17     public void doPaySuccess(String outTradeNo) {
      18         //支付成功,這里一般要更新數(shù)據(jù)庫(kù)的狀態(tài)
      19     }
      20 ?
      21     @Override
      22     public void doPayFail(String outTradeNo) {
      23         //支付失敗,這里一般要更新數(shù)據(jù)庫(kù)的狀態(tài)
      24     }
      25 ?
      26     @Override
      27     public void doRefundSuccess(String outTradeNo) {
      28         //退款成功,這里一般要更新數(shù)據(jù)庫(kù)的狀態(tài)
      29     }
      30 ?
      31     @Override
      32     public void doRefundFail(String outTradeNo) {
      33         //退款失敗,這里一般要更新數(shù)據(jù)庫(kù)的狀態(tài)
      34     }
      35 }

       

      看起來(lái)非常簡(jiǎn)單,繼承AbstractPayAdaptor抽象類(lèi),然后通過(guò)@Service注解交給Spring管理,為什么要交給Spring呢?因?yàn)檫@里你需要注入數(shù)據(jù)訪問(wèn)層的實(shí)例(Dao),不然怎么操作數(shù)據(jù)庫(kù),只不過(guò)我這沒(méi)有寫(xiě)而已~

      這里有一個(gè)GoodsTradeManager,是接下來(lái)要介紹的支付管理器,先不管它。

      仔細(xì)觀察會(huì)發(fā)現(xiàn),示例中的適配器名稱(chēng)叫GoodsTradeService,為什么我不管他叫GoodsTradePayAdaptor呢?從支付框架的角度看,這的確是一個(gè)適配器實(shí)現(xiàn),但從業(yè)務(wù)的角度看,它是商品訂單的服務(wù)中心,不僅要處理訂單狀態(tài),還要承擔(dān)創(chuàng)建訂單的職責(zé),它底層(數(shù)據(jù)庫(kù)層)關(guān)聯(lián)的本來(lái)就是一個(gè)訂單表,把它稱(chēng)作訂單服務(wù),更加容易理解。

      因此,所謂的適配器,就是用來(lái)適配支付框架和數(shù)據(jù)訪問(wèn)層的。

       

      創(chuàng)建支付管理器

      有了適配器,就有了數(shù)據(jù)訪問(wèn)的能力,再配上一個(gè)管理器作為統(tǒng)一調(diào)度中心,那么支付這事就搞定了,實(shí)現(xiàn)一個(gè)管理器非常容易:

       1 @PayManagerComponent
       2 public class GoodsTradeManager extends AbstractPayManager {
       3 ?
       4     @Autowired
       5     private GoodsTradeService goodsTradeService;
       6 ?
       7     @Override
       8     public String getTradeType() {
       9         return "0";
      10     }
      11 ?
      12     @Override
      13     public AbstractPayAdaptor getPayAdaptor() {
      14         return goodsTradeService;
      15     }
      16 }

       

      首先繼承AbstractPayManager,然后使用@PayManagerComponent注解注冊(cè)管理器,這沒(méi)什么神奇的,只不過(guò)是告訴框架這里有一個(gè)管理器,并且把這個(gè)管理器交給Spring維護(hù)。

      getTradeType方法返回長(zhǎng)度為1的字符串,建議取值范圍[0-9a-z],類(lèi)型會(huì)拼接到訂單號(hào)中,所以不建議使用特殊字符。因此,一個(gè)項(xiàng)目中最多可創(chuàng)建36個(gè)不同的管理器。

      getPayAdaptor方法返回上一步創(chuàng)建的適配器,管理器中包含了適配器。

      因此,所謂的管理器,管理的目標(biāo)就是適配器,同時(shí)擔(dān)負(fù)起統(tǒng)一支付調(diào)度的重任,管理器是支付模塊的窗口。

      最佳實(shí)踐是:每對(duì)管理器-適配器對(duì)應(yīng)一種支付業(yè)務(wù)

       

      發(fā)起支付

      接下來(lái)就可以發(fā)起支付了,非常簡(jiǎn)單,先來(lái)看一個(gè)支付寶掃碼支付示例:

      1 Trade trade = AliTrade
      2                 .qrcodePay()
      3                 .subject("商品標(biāo)題")
      4                 .body("商品描述")
      5                 .outTradeNo(goodsTradeManager.newTradeNo("你自己的用戶(hù)唯一標(biāo)識(shí)"))
      6                 .totalAmount("0.01")
      7                 .build();
      8 TradeToken<String> token = goodsTradeManager.qrcodePay(trade);
      9 String url = token.value();

       

      先通過(guò)AliTrade構(gòu)造器的qrcodePay方法創(chuàng)建一個(gè)掃碼支付訂單,然后調(diào)用管理器的qrcodePay方法生成訂單憑證,不同的支付產(chǎn)品的訂單憑證可能不同,你可以自由選擇泛型,掃碼支付的憑證就是一個(gè)url鏈接,因此我使用的String類(lèi)型,調(diào)用憑證的value方法,即可獲得憑證內(nèi)容,憑證內(nèi)容直接返回給前端(網(wǎng)頁(yè)或APP),前端即可調(diào)起支付。

      goodsTradeManager上一步已經(jīng)創(chuàng)建好,直接@Autowired注入即可。

      newTradeNo方法非常重要,它可以幫你生成一個(gè)訂單號(hào),也就是商戶(hù)訂單號(hào),在我的設(shè)計(jì)中,為了省去繁瑣的全局唯一訂單號(hào)生成,將訂單號(hào)和用戶(hù)關(guān)聯(lián)起來(lái),規(guī)避了訂單號(hào)唯一性問(wèn)題,用戶(hù)唯一標(biāo)識(shí)根據(jù)你的系統(tǒng)自由選擇,建議長(zhǎng)度在[6-10]之間,并且為固定長(zhǎng)度,不能使用特殊字符,用戶(hù)唯一標(biāo)識(shí)會(huì)直接拼接到訂單號(hào)中,長(zhǎng)度不固定或太長(zhǎng)的話(huà),訂單號(hào)會(huì)非常難看,不規(guī)范,如需更多了解,直接看代碼注釋。

      AliTrade構(gòu)造器所有的屬性均與支付寶官方文檔相對(duì)應(yīng),具體含義參考代碼注釋或者支付寶官方文檔。

      訂單的類(lèi)型AliTrade.qrcodePay和管理器方法goodsTradeManager.qrcodePay必須配套使用。

       

      再來(lái)看一個(gè)微信H5支付的例子:

       1 Trade trade = WxTrade
       2                 .webMobilePay()
       3                 .body("商品標(biāo)題")
       4                 .outTradeNo(goodsTradeManager.newTradeNo("你自己的用戶(hù)唯一標(biāo)識(shí)"))
       5                 .totalFee("1")
       6                 .spbillCreateIp("127.0.0.1")
       7                 .sceneInfo("商品測(cè)試場(chǎng)景")
       8                 .build();
       9 TradeToken<String> token = goodsTradeManager.webMobilePay(trade);
      10 String url = token.value();

       

      只不過(guò)是把AliTrade換成了WxTrade,然后調(diào)用WxTrade.webMobilePay構(gòu)造器,加上配套的goodsTradeManager.webMobilePay即可完成微信H5支付。

      微信H5支付的憑證也是一個(gè)url,直接交給前端處理即可。

      由此可以看出,我們只需要關(guān)心訂單構(gòu)造器,將訂單構(gòu)造好,直接調(diào)用管理器對(duì)應(yīng)的方法即可,管理器不關(guān)心支付寶還是微信,只需要接收一個(gè)配套的訂單,最后拿到訂單憑證,就算是完工了。

      依此類(lèi)推,即可完成其它類(lèi)型的支付業(yè)務(wù)。

       

      異步回調(diào)

      涉及錢(qián)的事沒(méi)有小事,別忘了還有支付結(jié)果異步回調(diào)

      前端的支付結(jié)果回調(diào)是同步回調(diào),僅供參考,必須以后端的結(jié)果為準(zhǔn)

      支付寶回調(diào):

       1 @PostMapping(value = "/notify")
       2 public void notify(HttpServletRequest request, HttpServletResponse response){
       3     /*
       4         解析請(qǐng)求參數(shù)
       5      */
       6     Map<String, String> params = NoticeManagers.getDefaultManager().receiveAliParams(request);
       7 
       8     /*
       9         封裝
      10      */
      11     AliPayNoticeInfo info = new AliPayNoticeInfo();
      12     TradeStatus status = NoticeManagers.getDefaultManager().execute(params, info);
      13 
      14     /*
      15         持久化回調(diào)數(shù)據(jù)
      16      */
      17     //TODO: 強(qiáng)烈建議將AliPayNoticeInfo持久化到數(shù)據(jù)庫(kù)中,以備不時(shí)之需,當(dāng)然你也可以忽略
      18 
      19     /*
      20         業(yè)務(wù)分發(fā)
      21      */
      22     AbstractPayManager payManager = (AbstractPayManager) PayManagers.find(status.getTradeNo());
      23     payManager.doTradeStatus(status);
      24 
      25     /*
      26         響應(yīng)
      27      */
      28     NoticeManagers.getDefaultManager().sendAliResponse(response);
      29 }

       

      微信回調(diào):

       1 @PostMapping(value = "/notify")
       2 public void notify(HttpServletRequest request, HttpServletResponse response){
       3     /*
       4         解析請(qǐng)求參數(shù)
       5      */
       6     Map<String, String> params = NoticeManagers.getDefaultManager().receiveWxParams(request);
       7 
       8     /*
       9         封裝
      10      */
      11     WxPayNoticeInfo info = new WxPayNoticeInfo();
      12     TradeStatus status = NoticeManagers.getDefaultManager().execute(params, info);
      13 
      14     /*
      15         持久化回調(diào)數(shù)據(jù)
      16      */
      17     //TODO: 強(qiáng)烈建議將WxPayNoticeInfo持久化到數(shù)據(jù)庫(kù)中,以備不時(shí)之需,當(dāng)然你也可以忽略
      18 
      19     /*
      20         業(yè)務(wù)分發(fā)
      21      */
      22     AbstractPayManager payManager = (AbstractPayManager) PayManagers.find(status.getTradeNo());
      23     payManager.doTradeStatus(status);
      24 
      25     /*
      26         響應(yīng)
      27      */
      28     NoticeManagers.getDefaultManager().sendWxResponse(response);
      29 }

       

      最基本的Spring MVC Controller代碼不用我教了吧。

      定義一個(gè)控制器,接收HTTP請(qǐng)求、響應(yīng)對(duì)象,通過(guò)框架解析出參數(shù)和訂單狀態(tài),然后將訂單狀態(tài)分發(fā)給適配器,實(shí)現(xiàn)訂單狀態(tài)更新,最后給支付寶、微信一個(gè)響應(yīng),告訴他們已經(jīng)接收到請(qǐng)求。

      回調(diào)處理非常規(guī)范化,基本不需要做什么改動(dòng)(直接Copy),唯一需要做的,也是非常重要的,就是根據(jù)你自己項(xiàng)目的實(shí)際情況,以恰當(dāng)?shù)姆绞匠志没卣{(diào)數(shù)據(jù)。

      這里的@PostMapping請(qǐng)求路徑,就是配置在application.yml中的notifyURL,必須保證公網(wǎng)可以無(wú)障礙訪問(wèn)。

       

      主動(dòng)同步訂單狀態(tài)

      用來(lái)彌補(bǔ)特殊原因造成的異步回調(diào)丟失,異步回調(diào)不是100%可靠的

      由于需要請(qǐng)求支付寶、微信服務(wù)器,所以速度較慢。

      支付寶訂單:

      1 Trade trade = AliTrade.query().outTradeNo("商戶(hù)訂單號(hào)").build();
      2 TradeStatus status = goodsTradeManager.status(trade);
      3 status.isPaySuccess(); //是否支付成功,其它狀態(tài)不一一列舉,自行看代碼

       

      微信訂單:

      1 Trade trade = WxTrade.basic().outTradeNo("商戶(hù)訂單號(hào)").build();
      2 TradeStatus status = goodsTradeManager.status(trade);
      3 status.isPaySuccess(); //是否支付成功,其它狀態(tài)不一一列舉,自行看代碼

       

      如何轉(zhuǎn)賬

      公對(duì)私轉(zhuǎn)賬

      由公司帳號(hào)向個(gè)人帳號(hào)轉(zhuǎn)賬。

      支付寶轉(zhuǎn)賬:

       1 /*
       2     構(gòu)造轉(zhuǎn)賬訂單
       3  */
       4 AliTransferTrade transferTrade = AliTransferTrade
       5                                         .transfer()
       6                                         .outBizNo("商戶(hù)轉(zhuǎn)賬唯一訂單號(hào)")
       7                                         .payeeAccount("收款人支付寶帳號(hào)")
       8                                         .amount("0.01")
       9                                         .build();
      10 
      11 /*
      12     轉(zhuǎn)賬
      13  */
      14 try{
      15     AliTransfer.getInstance().transfer(transferTrade);
      16 }catch (TransferException e){
      17     // 轉(zhuǎn)賬失敗處理邏輯...
      18 }

       

      轉(zhuǎn)賬方法無(wú)返回值,不發(fā)生異常代表轉(zhuǎn)賬成功,發(fā)生異常代表轉(zhuǎn)賬失敗,自行處理。

      訂單參數(shù)含義參考支付寶官方文檔或代碼注釋。

       

      微信轉(zhuǎn)賬:

       1 /*
       2     構(gòu)造轉(zhuǎn)賬訂單
       3  */
       4 WxTransferTrade transferTrade = WxTransferTrade
       5                                         .transfer()
       6                                         .partnerTradeNo("商戶(hù)轉(zhuǎn)賬唯一訂單號(hào)")
       7                                         .openid("收款人openid")
       8                                         .amount("1")
       9                                         .spbillCreateIp("127.0.0.1")  //這里是調(diào)用接口的服務(wù)器公網(wǎng)IP,自行獲取
      10                                         .build();
      11 /*
      12     轉(zhuǎn)賬
      13  */
      14 try{
      15     WxTransfer.getInstance().transfer(transferTrade);
      16 }catch (TransferException e){
      17     // 轉(zhuǎn)賬失敗處理邏輯...
      18 }

       

      轉(zhuǎn)賬方法無(wú)返回值,不發(fā)生異常代表轉(zhuǎn)賬成功,發(fā)生異常代表轉(zhuǎn)賬失敗,自行處理。

      訂單參數(shù)含義參考微信官方文檔或代碼注釋。

       

      轉(zhuǎn)賬狀態(tài)查詢(xún)

      支付寶:

       1 /*
       2     構(gòu)造轉(zhuǎn)賬查詢(xún)訂單
       3  */
       4 AliTransferTrade transferTrade = AliTransferTrade
       5                                         .query()
       6                                         .outBizNo("商戶(hù)轉(zhuǎn)賬唯一訂單號(hào)")
       7                                         .build();
       8 /*
       9     轉(zhuǎn)賬查詢(xún)
      10  */
      11 TransferStatus status = AliTransfer.getInstance().status(transferTrade);;
      12 status.isSuccess();  //轉(zhuǎn)賬成功,其他狀態(tài)自行查看代碼,不一一列舉

       

      微信:

       1 /*
       2     構(gòu)造轉(zhuǎn)賬查詢(xún)訂單
       3  */
       4 WxTransferTrade transferTrade = WxTransferTrade
       5                                         .custom()
       6                                         .partnerTradeNo("商戶(hù)轉(zhuǎn)賬唯一訂單號(hào)")
       7                                         .build();
       8 /*
       9     轉(zhuǎn)賬查詢(xún)
      10  */
      11 TransferStatus status = WxTransfer.getInstance().status(transferTrade);;
      12 status.isSuccess();  //轉(zhuǎn)賬成功,其他狀態(tài)自行查看代碼,不一一列舉

       

      附加工具

      獲取客戶(hù)端IP地址

      微信支付大部分場(chǎng)景需要客戶(hù)端IP地址,可以通過(guò)本模塊PayHttpUtil.getRealClientIp方法獲取。

      如果獲取不到,請(qǐng)檢查代理軟件是否正確設(shè)置了X-Forwarded-For

       

      其他

      如有疑問(wèn),歡迎積極反饋,直接提Issues別客氣。

       

      pay-spring-boot項(xiàng)目地址

       

       

      posted @ 2019-05-11 16:43  楊元  閱讀(9312)  評(píng)論(4)    收藏  舉報(bào)
      主站蜘蛛池模板: 中文字幕在线亚洲日韩6页| 扶余县| 熟女一区| 最新中文字幕av无码专区不 | 西西大胆午夜人体视频| 日本熟妇色xxxxx| 亚洲国产成人资源在线| 罗江县| 国产一区二区三区精品综合| 人人入人人爱| 老熟妇欲乱一区二区三区| 2020年最新国产精品正在播放| 盖州市| 国产成人av免费观看| 偷拍精品一区二区三区| 在线高清免费不卡全码| 亚洲av成人久久18禁| 婷婷丁香五月亚洲中文字幕| 国产亚洲精品久久久久秋霞| 日韩精品一区二区在线视| 99久久国产综合精品成人影院| 闵行区| 国产成人亚洲无码淙合青草 | 国产美女被遭强高潮免费一视频| 国产白嫩护士被弄高潮| 亚洲国内精品一区二区| 欧美性猛交xxxx富婆| 亚洲第一极品精品无码久久| 国产婷婷精品av在线| 国内精品一区二区在线观看| 欧美videosdesexo吹潮| 亚洲成人资源在线观看| 国产95在线 | 欧美| 饥渴少妇高潮正在播放| 极品尤物被啪到呻吟喷水| 国产精品久久久久久久久久久久| 国产亚洲精品黑人粗大精选| 中文字幕理伦午夜福利片| 国产日韩精品中文字幕| 五月丁香六月狠狠爱综合| 亚洲成在人线AⅤ中文字幕|