<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                下單簡單的分成幾個步驟: 1. 用戶點擊“立即購買”或“購物車-結算”進入到“確認訂單”頁面 2. 在“確認訂單”頁面選擇收貨地址,優惠券等,重新計算運費、訂單價格 3. 提交訂單,選擇支付方式進行支付 4. 支付完畢 ## 第一步: 1. 用戶點擊“立即購買”或“購物車-結算”進入到“確認訂單”頁面,相關url`/p/order/confirm` 我們希望能夠有個統一下單的接口,不太希望“立即購買”和“購物車-結算”兩個不同的接口影響到后面所有的流程,畢竟誰也不想一個差不多一樣的接口,要寫兩遍,所以我們看下我們的系統是如何做的。 ```java public class OrderParam { @ApiModelProperty(value = "購物車id 數組") private List<Long> basketIds; @ApiModelProperty(value = "立即購買時提交的商品項") private OrderItemParam orderItem; } ``` 這里使用了兩種情況: - 假設`basketIds` 不為空,則說明是從購物車進入 - 假設`orderItem` 不為空,則說明是從立即購買進入 通過`basketService.getShopCartItemsByOrderItems(orderParam.getBasketIds(),orderParam.getOrderItem(),userId)` 這個方法對兩種情況進行組合,此時并不能將購物車商品刪除,因為刪除購物車中的商品,是在第三步提交訂單的時候進行的,不然用戶點擊返回鍵,看到購物車里面的東西還沒提交訂單,東西就消失了,會感覺很奇怪。 我們重新回到`controller`層,我們看到了一行熟悉的代碼`basketService.getShopCarts` ```java @PostMapping("/confirm") @ApiOperation(value = "結算,生成訂單信息", notes = "傳入下單所需要的參數進行下單") public ResponseEntity<ShopCartOrderMergerDto> confirm(@Valid @RequestBody OrderParam orderParam) { // 根據店鋪組裝購車中的商品信息,返回每個店鋪中的購物車商品信息 List<ShopCartDto> shopCarts = basketService.getShopCarts(shopCartItems); } ``` 這行代碼我們再《購物車的設計》這篇已經著重講過了,但是我們在這為什么還需要這個東西呢? 很簡單,無論是點擊“立即購買”或“購物車-結算”,事實上都是通過用戶計算過一遍金額了,而且甚至有滿減滿折之類的活動,都是通過了統一的計算的。而這一套計算的流程,我們并不希望重新寫一遍。所以當然是能夠使用之前計算的金額,那是最好的咯。 ## 第二步: 2. 在“確認訂單”頁面選擇收貨地址,優惠券等,重新計算運費、訂單價格 我們知道無論是在第一步還是第二步,本質上還是在確認訂單的頁面,其中訂單頁面的數據結構并沒有發生任何的變化,所以其實第一步第二步是可以寫在一起的。所以我們可以看到`OrderParam` 還多了兩個參數 ```java public class OrderParam { @ApiModelProperty(value = "地址ID,0為默認地址",required=true) @NotNull(message = "地址不能為空") private Long addrId; @ApiModelProperty(value = "用戶是否改變了優惠券的選擇,如果用戶改變了優惠券的選擇,則完全根據傳入參數進行優惠券的選擇") private Integer userChangeCoupon; @ApiModelProperty(value = "優惠券id數組") private List<Long> couponIds; } ``` 但是有個問題,就是在于用戶點擊立即購買的時候,沒有地址,那樣如何計算運費呢?答案就是使用默認地址進行計算呀~ 我們看下計算訂單的事件,事實上有很多營銷活動的時候,訂單的計算也是非常的復雜的,所以我們和購物車一樣,采用事件的驅動,一個接一個的對訂單進行“裝飾”,最后生成`ShopCartOrderMergerDto`一個合并的對象 ```java @PostMapping("/confirm") @ApiOperation(value = "結算,生成訂單信息", notes = "傳入下單所需要的參數進行下單") public ResponseEntity<ShopCartOrderMergerDto> confirm(@Valid @RequestBody OrderParam orderParam) { for (ShopCartDto shopCart : shopCarts) { applicationContext.publishEvent(new ConfirmOrderEvent(shopCartOrder,orderParam,shopAllShopCartItems)); } } ``` 我們看下`ConfirmOrderListener` 這個事件里面的默認監聽器,這里 ```java public class ConfirmOrderListener { @EventListener(ConfirmOrderEvent.class) @Order(ConfirmOrderOrder.DEFAULT) public void defaultConfirmOrderEvent(ConfirmOrderEvent event) { ShopCartOrderDto shopCartOrderDto = event.getShopCartOrderDto(); OrderParam orderParam = event.getOrderParam(); String userId = SecurityUtils.getUser().getUserId(); // 訂單的地址信息 UserAddr userAddr = userAddrService.getUserAddrByUserId(orderParam.getAddrId(), userId); double total = 0.0; int totalCount = 0; double transfee = 0.0; for (ShopCartItemDto shopCartItem : event.getShopCartItems()) { // 獲取商品信息 Product product = productService.getProductByProdId(shopCartItem.getProdId()); // 獲取sku信息 Sku sku = skuService.getSkuBySkuId(shopCartItem.getSkuId()); if (product == null || sku == null) { throw new YamiShopBindException("購物車包含無法識別的商品"); } if (product.getStatus() != 1 || sku.getStatus() != 1) { throw new YamiShopBindException("商品[" + sku.getProdName() + "]已下架"); } totalCount = shopCartItem.getProdCount() + totalCount; total = Arith.add(shopCartItem.getProductTotalAmount(), total); // 用戶地址如果為空,則表示該用戶從未設置過任何地址相關信息 if (userAddr != null) { // 每個產品的運費相加 transfee = Arith.add(transfee, transportManagerService.calculateTransfee(shopCartItem, userAddr)); } shopCartItem.setActualTotal(shopCartItem.getProductTotalAmount()); shopCartOrderDto.setActualTotal(Arith.sub(total, transfee)); shopCartOrderDto.setTotal(total); shopCartOrderDto.setTotalCount(totalCount); shopCartOrderDto.setTransfee(transfee); } } } ``` 值得留意的是,有那么一行代碼 ```java // 用戶地址如果為空,則表示該用戶從未設置過任何地址相關信息 if (userAddr != null) { // 每個產品的運費相加 transfee = Arith.add(transfee, transportManagerService.calculateTransfee(shopCartItem, userAddr)); } ``` 運費是根據用戶地址進行計算,當然還包括運費模板啦,想了解運費模板的,可以參考運費模板相關的章節。 那么有人就問了,那么優惠券呢?優惠券是有另一個監聽器進行監聽計算價格啦,購買了專業版或以上的版本就能看到源碼咯~ 我們看看返回給前端的訂單信息: ```java @Data public class ShopCartOrderMergerDto implements Serializable{ @ApiModelProperty(value = "實際總值", required = true) private Double actualTotal; @ApiModelProperty(value = "商品總值", required = true) private Double total; @ApiModelProperty(value = "商品總數", required = true) private Integer totalCount; @ApiModelProperty(value = "訂單優惠金額(所有店鋪優惠金額相加)", required = true) private Double orderReduce; @ApiModelProperty(value = "地址Dto", required = true) private UserAddrDto userAddr; @ApiModelProperty(value = "每個店鋪的購物車信息", required = true) private List<ShopCartOrderDto> shopCartOrders; @ApiModelProperty(value = "整個訂單可以使用的優惠券列表", required = true) private List<CouponOrderDto> coupons; } ``` 這里又有一段我們熟悉的代碼: ```java @ApiModelProperty(value = "每個店鋪的購物車信息", required = true) private List<ShopCartOrderDto> shopCartOrders; ``` 沒錯這里返回的數據格式,和購物車的格式是一樣的,因為第一步當中已經說明,訂單來自于購物車的計算,所以會在基礎上條件新的數據,基本上就是返回給前端的數據了。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看