欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Springboot整合微信支付(訂單過(guò)期取消及商戶主動(dòng)查單)

 更新時(shí)間:2022年07月01日 09:30:15   作者:肇事司機(jī)趙四  
本文主要介紹了Springboot整合微信支付(訂單過(guò)期取消及商戶主動(dòng)查單),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

一:?jiǎn)栴}引入

前面講到用戶支付完成之后微信支付服務(wù)器會(huì)發(fā)送回調(diào)通知給商戶,商戶要能夠正常處理這個(gè)回調(diào)通知并返回正確的狀態(tài)碼給微信支付后臺(tái)服務(wù)器,不然微信支付后臺(tái)服務(wù)器就會(huì)在一段時(shí)間之內(nèi)重復(fù)發(fā)送回調(diào)通知給商戶。具體流程見(jiàn)下圖:

在這里插入圖片描述

那么這時(shí)候問(wèn)題就來(lái)了,微信后臺(tái)發(fā)送回調(diào)通知次數(shù)也是有限制的,而且,微信支付開(kāi)發(fā)文檔中這樣說(shuō)到:對(duì)后臺(tái)通知交互時(shí),如果微信收到商戶的應(yīng)答不符合規(guī)范或超時(shí),微信認(rèn)為通知失敗,微信會(huì)通過(guò)一定的策略定期重新發(fā)起通知,盡可能提高通知的成功率,但微信不保證通知最終能成功。也就是說(shuō)我們不能單單通過(guò)微信支付的回調(diào)通知來(lái)被動(dòng)地更新訂單狀態(tài),假如接收微信回調(diào)通知失敗但是這時(shí)候用戶是已經(jīng)付了款的,而商戶這邊卻顯示未付款狀態(tài),假如沒(méi)有作進(jìn)一步處理就會(huì)造成一些不必要的麻煩。這時(shí)候就需要商戶主動(dòng)向微信支付后臺(tái)查詢訂單狀態(tài)。

二:處理流程

在這里插入圖片描述

一開(kāi)始我采用的策略并不是延遲隊(duì)列,而是采用定時(shí)器定時(shí)查詢數(shù)據(jù)庫(kù)來(lái)實(shí)現(xiàn)商戶主動(dòng)查單并實(shí)現(xiàn)訂單過(guò)期自動(dòng)取消功能,但是這一做法十分不友好,體現(xiàn)在下面幾個(gè)方面:

  • 定時(shí)查詢數(shù)據(jù)庫(kù)會(huì)加大數(shù)據(jù)庫(kù)負(fù)擔(dān)
  • 假如數(shù)據(jù)量很大,頻繁查詢數(shù)據(jù)庫(kù)消耗的時(shí)間較多
  • 會(huì)造成時(shí)間誤差,定時(shí)時(shí)間過(guò)長(zhǎng)誤差大,定時(shí)時(shí)間過(guò)短查詢又太頻繁

假如我設(shè)定的定時(shí)時(shí)間是5分鐘查詢一次,那么假如定時(shí)器還有1秒就要去查詢一次,但是有一批訂單還有2秒才到期,這時(shí)候定時(shí)器就處理不到這批訂單。等下次再進(jìn)行處理時(shí)候這批訂單已經(jīng)過(guò)期差不多5分鐘了,這顯然是很大的一個(gè)缺陷。此外假如很長(zhǎng)一段時(shí)間都沒(méi)有用戶下單,但是由于定時(shí)器并不知道什么時(shí)候有用戶下單什么時(shí)候沒(méi)有用戶下單,它只是個(gè)一到點(diǎn)就開(kāi)始定時(shí)查詢的無(wú)感情機(jī)器,這樣就會(huì)產(chǎn)生一些不必要的開(kāi)銷。

實(shí)現(xiàn)訂單過(guò)期自動(dòng)刪除的策略有很多,其中一種就是我上面提到的數(shù)據(jù)庫(kù)輪詢方法,此外,還可以采用的策略有:JDK的延遲隊(duì)列、時(shí)間輪算法、redis緩存、使用消息隊(duì)列等等,我選用的策略是采用RabbitMQ的延遲隊(duì)列來(lái)實(shí)現(xiàn),至于延遲隊(duì)列的實(shí)現(xiàn)細(xì)節(jié)我將在下一篇文章講解,這里僅介紹訂單處理部分。

處理策略為商戶下單之后生成訂單存入數(shù)據(jù)庫(kù)并將該訂單號(hào)存入延遲隊(duì)列,此時(shí)訂單狀態(tài)為“未支付”,假如接收微信回調(diào)成功并且驗(yàn)證到用戶已付款,這時(shí)候就更新數(shù)據(jù)庫(kù)中該訂單狀態(tài)為“已付款”。當(dāng)延遲隊(duì)列到期進(jìn)行消費(fèi)時(shí),根據(jù)延遲隊(duì)列中的訂單號(hào)先在數(shù)據(jù)庫(kù)中進(jìn)行查詢,假如這時(shí)候數(shù)據(jù)庫(kù)中該訂單狀態(tài)為“已支付”,這時(shí)候就不需要進(jìn)行處理,假如訂單狀態(tài)為“未支付”,商戶程序應(yīng)主動(dòng)向微信支付后臺(tái)進(jìn)行訂單狀態(tài)查詢,如果訂單狀態(tài)為已支付,這時(shí)候就不需要進(jìn)行處理,如果訂單狀態(tài)為未支付,這時(shí)候就將訂單狀態(tài)改為“已取消”。一開(kāi)始我的做法為無(wú)論數(shù)據(jù)庫(kù)中該訂單狀態(tài)是否已支付都向微信支付后臺(tái)進(jìn)行訂單狀態(tài)查詢,然后再根據(jù)查詢結(jié)果做進(jìn)一步處理,顯然這種做法存在缺陷,就是每一筆訂單都主動(dòng)向微信支付后臺(tái)進(jìn)行查詢會(huì)消耗很大的網(wǎng)絡(luò)帶寬,而且假如已經(jīng)成功接收到微信支付回調(diào)通知的訂單并不需要進(jìn)行再次查詢確認(rèn)。

三:代碼實(shí)現(xiàn)

3.1:orderServiceImpl.java

/**
* 提交訂單
* @param orders
* @param session
*/
@Override
@Transactional
public Orders createOrder(Orders orders, HttpSession session) {
    //獲取當(dāng)前用戶信息
    Long userId = (Long) session.getAttribute("user");
    //查詢地址數(shù)據(jù)
    Long addressBookId = orders.getAddressBookId();
    AddressBook addressBook = addressBookService.getById(addressBookId);
    if(addressBook == null) {
        throw new CustomException("用戶地址信息有誤,不能下單");
    }
    //獲取當(dāng)前用戶購(gòu)物車(chē)數(shù)據(jù)
    LambdaQueryWrapper<ShoppingCart> SCLqw = new LambdaQueryWrapper<>();
    SCLqw.eq(ShoppingCart::getUserId,userId);
    List<ShoppingCart> shoppingCartList = shoppingCartService.list(SCLqw);
    //生成訂單號(hào)
    long orderId = IdWorker.getId();
    //設(shè)置訂單號(hào)
    orders.setNumber(String.valueOf(orderId));
    //設(shè)置訂單狀態(tài)(待付款)
    orders.setStatus(1);
    //設(shè)置下單用戶id
    orders.setUserId(userId);
    //設(shè)置下單時(shí)間
    orders.setOrderTime(LocalDateTime.now());
    //設(shè)置付款時(shí)間
    orders.setCheckoutTime(LocalDateTime.now());
    //設(shè)置實(shí)收金額
    AtomicInteger amount = new AtomicInteger(0);
    for(ShoppingCart shoppingCart : shoppingCartList) {
        amount.addAndGet(shoppingCart.getAmount().multiply(new BigDecimal(100)).multiply(new BigDecimal(shoppingCart.getNumber())).intValue());
    }
    orders.setAmount(BigDecimal.valueOf(amount.get()));
    //設(shè)置用戶信息
    User user = userService.getById(userId);
    orders.setPhone(addressBook.getPhone());
    orders.setAddress(addressBook.getDetail());
    orders.setUserName(user.getPhone());
    orders.setConsignee(addressBook.getConsignee());
    //保存單條訂單信息
    this.save(orders);
    //設(shè)置訂單詳細(xì)信息
    List<OrderDetail> orderDetailList = new ArrayList<>();
    for(ShoppingCart shoppingCart : shoppingCartList) {
        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setName(shoppingCart.getName());
        orderDetail.setImage(shoppingCart.getImage());
        orderDetail.setOrderId(orderId);
        orderDetail.setDishId(shoppingCart.getDishId());
        orderDetail.setSetmealId(shoppingCart.getSetmealId());
        orderDetail.setDishFlavor(shoppingCart.getDishFlavor());
        orderDetail.setNumber(shoppingCart.getNumber());
        AtomicInteger detailAmount = new AtomicInteger(0);
        detailAmount.addAndGet(shoppingCart.getAmount().multiply(new BigDecimal(shoppingCart.getNumber())).intValue());
        orderDetail.setAmount(BigDecimal.valueOf(detailAmount.get()));
        orderDetailList.add(orderDetail);
    }
    //批量保存訂單詳細(xì)數(shù)據(jù)
    orderDetailService.saveBatch(orderDetailList);
    //清空購(gòu)物車(chē)數(shù)據(jù)
    shoppingCartService.remove(SCLqw);
    
    //設(shè)置延遲隊(duì)列,過(guò)期時(shí)間為5分鐘
    log.info("訂單編號(hào):{}進(jìn)入延遲隊(duì)列...",orders.getNumber());
    delayProducer.publish(orders.getNumber(),String.valueOf(orders.getId()),
            DelayMessageConfig.DELAY_EXCHANGE_NAME,DelayMessageConfig.ROUTING_KEY_ORDER,1000*60*5);
            
    return orders;
}

3.2:RabbitmqDelayConsumer.java

/**
* 監(jiān)聽(tīng)訂單延遲隊(duì)列
* @param orderNo
* @throws Exception
*/
@RabbitListener(queues = {"plugin.delay.order.queue"})
public void orderDelayQueue(String orderNo, Message message, Channel channel) throws Exception {
    log.info("訂單延遲隊(duì)列開(kāi)始消費(fèi)...");
    try {
        //處理訂單
        wxPayService.checkOrderStatus(orderNo);
        //告訴服務(wù)器收到這條消息 已經(jīng)被我消費(fèi)了 可以在隊(duì)列刪掉 這樣以后就不會(huì)再發(fā)了 否則消息服務(wù)器以為這條消息沒(méi)處理掉 后續(xù)還會(huì)在發(fā)
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        log.info("消息接收成功");
    } catch (Exception e) {
        e.printStackTrace();
        //消息重新入隊(duì)
        channel.basicNack(message.getMessageProperties().getDeliveryTag(), false,true);
        log.info("消息接收失敗,重新入隊(duì)");
    }
}

3.3:WxPayServiceImpl.java

/**
* 商戶主動(dòng)查詢訂單狀態(tài)
* 當(dāng)核實(shí)到訂單超時(shí)未支付則取消訂單
* 當(dāng)核實(shí)到訂單已支付則更新訂單狀態(tài)
*/
@Transactional(rollbackFor = Exception.class)
@Override
public void checkOrderStatus(String orderNo) throws Exception {
    log.info("根據(jù)訂單號(hào)核實(shí)訂單狀態(tài)==>{}",orderNo);
    
    log.info("在數(shù)據(jù)庫(kù)中查詢訂單狀態(tài)....");
    Integer status = ordersService.getOrderStatus(orderNo);
    if(status != 1) {
        //訂單不是”未支付“狀態(tài)
        log.info("訂單不是”未支付“狀態(tài),無(wú)需進(jìn)行進(jìn)一步處理");
        return;
    }
    
    String result = this.queryOrder(orderNo);
    Gson gson = new Gson();
    Map<String,String> map = gson.fromJson(result, HashMap.class);
    
    //獲取訂單狀態(tài)
    String tradeState = map.get("trade_state");
    //判斷訂單狀態(tài)
    if(WxTradeState.NOTPAY.getType().equals(tradeState)) {
        log.info("核實(shí)到訂單超時(shí)未支付==>{}",orderNo);
        //關(guān)閉訂單
        log.info("訂單已自動(dòng)取消");
        this.closeOrder(orderNo);
        //更新本地訂單狀態(tài)
        ordersService.updateStatusByOrderNo(orderNo,"5");
    }
    else if(WxTradeState.SUCCESS.getType().equals(tradeState)) {
        log.info("核實(shí)到訂單已支付==>{}",orderNo);
        Integer orderStatus = ordersService.getOrderStatus(orderNo);
        if(orderStatus != null && orderStatus != 2) {
            //更新本地訂單狀態(tài)
            ordersService.updateStatusByOrderNo(orderNo,"2");
            //保存訂單記錄
            paymentInfoService.saveInfo(result);
        }
    }
    else if(WxTradeState.CLOSED.getType().equals(tradeState)) {
        log.info("核實(shí)到訂單已取消==>{}",orderNo);
        Integer orderStatus = ordersService.getOrderStatus(orderNo);
        if(orderStatus != null && orderStatus != 5) {
            //更新本地訂單狀態(tài)
            ordersService.updateStatusByOrderNo(orderNo,"5");
            //保存訂單記錄
            paymentInfoService.saveInfo(result);
        }
    }
}

/**
* 查詢訂單
* @param orderNo
* @return
*/
@Override
public String queryOrder(String orderNo) throws Exception {
    log.info("查單接口調(diào)用===>{}",orderNo);
    //構(gòu)建請(qǐng)求鏈接
    String url = String.format(WxApiType.ORDER_QUERY_BY_NO.getType(),orderNo);
    url = wxPayConfig.getDomain().concat(url).concat("?mchid=").concat(wxPayConfig.getMchId());
    URIBuilder uriBuilder = new URIBuilder(url);
    HttpGet httpGet = new HttpGet(uriBuilder.build());
    httpGet.addHeader("Accept","application/json");

    CloseableHttpResponse response = wxPayClient.execute(httpGet);
    
    return EntityUtils.toString(response.getEntity());
}

到此這篇關(guān)于Springboot整合微信支付(訂單過(guò)期取消及商戶主動(dòng)查單)的文章就介紹到這了,更多相關(guān)Springboot 微信支付內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java 關(guān)于eclipse導(dǎo)入項(xiàng)目發(fā)生的問(wèn)題及解決方法(推薦)

    Java 關(guān)于eclipse導(dǎo)入項(xiàng)目發(fā)生的問(wèn)題及解決方法(推薦)

    下面小編就為大家分享一篇Java 關(guān)于eclipse導(dǎo)入項(xiàng)目發(fā)生的問(wèn)題及解決方法(推薦),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2017-12-12
  • IDEA2022版本創(chuàng)建maven?web項(xiàng)目的兩種方式詳解

    IDEA2022版本創(chuàng)建maven?web項(xiàng)目的兩種方式詳解

    創(chuàng)建maven?web項(xiàng)目有兩種方式,一種是使用骨架方式,一種是不使用骨架的方式,本文結(jié)合實(shí)例代碼給大家介紹了IDEA2022版本創(chuàng)建maven?web項(xiàng)目的兩種方式,需要的朋友可以參考下
    2023-02-02
  • JAVA設(shè)計(jì)模式之訪問(wèn)者模式原理與用法詳解

    JAVA設(shè)計(jì)模式之訪問(wèn)者模式原理與用法詳解

    這篇文章主要介紹了JAVA設(shè)計(jì)模式之訪問(wèn)者模式,簡(jiǎn)單說(shuō)明了訪問(wèn)者模式的原理,并結(jié)合實(shí)例分析了java訪問(wèn)者模式的定義與用法,需要的朋友可以參考下
    2017-08-08
  • SpringBoot中實(shí)現(xiàn)多數(shù)據(jù)源連接和切換的方案

    SpringBoot中實(shí)現(xiàn)多數(shù)據(jù)源連接和切換的方案

    在Spring Boot中,通過(guò)AbstractRoutingDataSource實(shí)現(xiàn)多數(shù)據(jù)源連接是一種常見(jiàn)的做法,這種技術(shù)允許你在運(yùn)行時(shí)動(dòng)態(tài)地切換數(shù)據(jù)源,從而支持對(duì)多個(gè)數(shù)據(jù)庫(kù)的操作,本文給大家介紹了SpringBoot中實(shí)現(xiàn)多數(shù)據(jù)源連接和切換的方案,需要的朋友可以參考下
    2024-11-11
  • Hibernate實(shí)現(xiàn)悲觀鎖和樂(lè)觀鎖代碼介紹

    Hibernate實(shí)現(xiàn)悲觀鎖和樂(lè)觀鎖代碼介紹

    這篇文章主要介紹了Hibernate實(shí)現(xiàn)悲觀鎖和樂(lè)觀鎖的有關(guān)內(nèi)容,涉及hibernate的隔離機(jī)制,以及實(shí)現(xiàn)悲觀鎖和樂(lè)觀鎖的代碼實(shí)現(xiàn),需要的朋友可以了解下。
    2017-09-09
  • Java線程池實(shí)現(xiàn)原理詳解

    Java線程池實(shí)現(xiàn)原理詳解

    在面向?qū)ο缶幊讨?,?chuàng)建和銷毀對(duì)象是很費(fèi)時(shí)間的,因?yàn)閯?chuàng)建一個(gè)對(duì)象要獲取內(nèi)存資源或者其它更多資源,在Java中更是如此,虛擬機(jī)將試圖跟蹤每一個(gè)對(duì)象,以便能夠在對(duì)象銷毀后進(jìn)行垃圾回收,本文將對(duì)Java線程池實(shí)現(xiàn)原理進(jìn)行詳細(xì)介紹,需要的朋友可以參考下
    2023-07-07
  • quartz定時(shí)執(zhí)行任務(wù),并配置web.xml的操作方法

    quartz定時(shí)執(zhí)行任務(wù),并配置web.xml的操作方法

    下面小編就為大家?guī)?lái)一篇quartz定時(shí)執(zhí)行任務(wù),并配置web.xml的操作方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-07-07
  • IDEA怎么生成UML類圖的實(shí)現(xiàn)

    IDEA怎么生成UML類圖的實(shí)現(xiàn)

    這篇文章主要介紹了IDEA怎么生成UML類圖的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • IDEA中配置操作Git的詳細(xì)圖文教程

    IDEA中配置操作Git的詳細(xì)圖文教程

    這篇文章給大家詳細(xì)介紹在IDEA中配置Git,IDEA中操作Git的詳細(xì)教程,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2020-10-10
  • SpringCloudAlibaba整合Feign實(shí)現(xiàn)遠(yuǎn)程HTTP調(diào)用的簡(jiǎn)單示例

    SpringCloudAlibaba整合Feign實(shí)現(xiàn)遠(yuǎn)程HTTP調(diào)用的簡(jiǎn)單示例

    這篇文章主要介紹了SpringCloudAlibaba 整合 Feign 實(shí)現(xiàn)遠(yuǎn)程 HTTP 調(diào)用,文章中使用的是OpenFeign,是Spring社區(qū)開(kāi)發(fā)的組件,需要的朋友可以參考下
    2021-09-09

最新評(píng)論