整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          使用 Vue.js 開發購物車功能2

          物車一般包含商品名稱、單價、數量等信息,數量可以任意新增或減少,商品項也可刪除,還可以支持全選或多選:

          最終效果

          我們把這個小項目分為三個文件:

          • index.html (頁面)
          • index.js (Vue 腳本)
          • style.css (樣式)

          1 index.js

          首先在 js 中初始化 Vue 實例,整體模板如下:

          var app = new Vue({
           el: '#app',
           data: {
           ...
           },
           mounted: function () {
           ...
           },
           computed: {
           ...
           },
           methods: {
           ...
           }
          });
          

          一般來說,這里的 data 來源于服務端數據,這里為了簡便,所以直接定義好的數據:

          data: {
           /**
           * 購物車中的商品列表
           */
           list: [
           {
           id: 1,
           name: '韓國進口海牌海苔',
           price: 39.9,
           count: 1
           },
           {
           id: 2,
           name: '印尼進口 Nabati 麗巧克(Richoco)休閑零食 巧克力味 威化餅干',
           price: 11.8,
           count: 1
           },
           {
           id: 3,
           name: '菲律賓進口 道吉草 奶油夾',
           price: 6.5,
           count: 1
           }
           ],
           //選中的商品列表,用于計算總價
           checkList: []
           }
          
          • list 用于展示 購物車中的商品列表。
          • checkList 用于表示勾選中的商品列表,后面,我們會利用它來計算選中商品的總價。
          mounted: function () {
           //默認全選
           this.checkAll();
           this.checkAllElement(document.querySelector(".checkAll"));
          }
          

          當 mounted 時,默認全選購物車內的所有商品。

          computed: {
           /**
           * 總價
           * @returns {string}
           */
           totalPrice: function () {
           var total = 0;
           for (var i = 0; i < this.checkList.length; i++) {
           var item = this.checkList[i];
           total += item.price * item.count;
           }
           return total.toLocaleString();
           }
          }
          

          在計算屬性中,我們定義了總價的計算方式,它會綁定勾選的 checkList 來計算總價。之所以使用 toLocaleString 方法,是因為小數部分會自動四舍五入,而且還會以千分位表示出來,很方便哦O(∩_∩)O~

          methods: {
           /**
           * 減少購買數量
           * @param index
           */
           reduceCount: function (index) {
           if (this.list[index].count === 1) return;
           this.list[index].count--;
           },
           /**
           * 增加購買數量
           * @param index
           */
           addCount: function (index) {
           this.list[index].count++;
           },
           /**
           * 移除商品
           * @param index
           */
           remove: function (index) {
           console.log("remove-index:" + index);
           this.list.splice(index, 1);
           //獲取商品序號
           var id = index + 1;
           //移除實際參與計算的商品
           var $checkList = this.checkList;
           for (var i = 0; i < $checkList.length; i++) {
           var item = $checkList[i];
           if (item.id == id) {
           $checkList.splice(i, 1);
           }
           }
           },
           /**
           * 全選或全不選
           * @param event
           */
           checkAllOrNot: function (event) {
           if (event.target.checked) {//全選
           this.checkAll();
           console.log("checkList:" + this.checkList);
           } else { // 全不選
           console.log("全不選");
           this.checkInItems('noCheckAll');
           this.checkList.splice(0);//清空數組
           }
           },
           /**
           * 全選
           */
           checkAll: function () {
           console.log("全選");
           this.checkInItems('checkAll');
           this.checkList = this.list.concat();//復制商品列表
           },
           /**
           * 全選或全不選
           * @param type checkAll:全選;其他:全不選
           */
           checkInItems: function (type) {
           var items = document.querySelectorAll('.checkItem');
           for (var i = 0; i < items.length; i++) {
           var item = items[i];
           if (type === 'checkAll') {
           item.checked = true;
           } else {
           item.checked = false;
           }
           }
           },
           /**
           * 勾選或不勾選
           */
           checkItem: function (event, index) {
           console.log("checkItem");
           var element = event.target;
           var $allCheck = document.querySelector(".checkAll");
           if (element.checked) {//勾選,加入已選擇列表
           this.checkList.push(this.list[index]);
           this.checkAllElement($allCheck);
           } else {//不勾選,從已選擇列表中去除
           this.checkList.splice(index, 1);
           $allCheck.checked = false;
           }
           },
           /**
           * 勾選全選框
           * @param element
           */
           checkAllElement: function (element) {
           //如果所有的商品都已被勾選,則勾選全選框
           if (this.checkList.length == this.list.length) {
           element.checked = true;
           }
           }
          }
          

          在 methods 中,我們定義了以下功能方法:

          • 減少與增加購買數量。在減少購買數量方法中,我們對當前所對應商品的數量進行了二次確認,讓代碼變得更加健壯(HTML 模板可能被修改,button 被替換為 div 或者 span,那么 disabled 樣式就變得無效啦)。
          • 移除某件商品。因為購物車中的商品列表與實際勾選的商品列表數量上有可能存在差異,所以我們必須通過找到商品 ID 再進行刪除。
          • 勾選相關操作(全選、全不選、單選、單不選等)

          2 style.css

          [v-cloak] {
           display: none;
          }
          table {
           border: 1px solid #e9e9e9;
           border-collapse: collapse;
           border-spacing: 0;
           empty-cells: show;
          }
          th {
           font: bold 12px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
           color: #4f6b72;
           border-right: 1px solid #C1DAD7;
           border-bottom: 1px solid #C1DAD7;
           border-top: 1px solid #C1DAD7;
           letter-spacing: 2px;
           text-transform: uppercase;
           text-align: left;
           padding: 6px 6px 6px 12px;
           background: #CAE8EA;
          }
          td {
           border-right: 1px solid #C1DAD7;
           border-bottom: 1px solid #C1DAD7;
           background: #fff;
           font-size:14px;
           padding: 6px 6px 6px 12px;
           color: #4f6b72;
          }
          

          這里定義了 v-cloak 樣式,用于解決網絡慢時的閃屏問題。還定義了表格的相關樣式。

          3 index.html

          接著在 index.html 中引入 Vue 腳本與樣式文件。基本模板如下:

          <!DOCTYPE html>
          <html lang="en">
          <head>
           <meta charset="UTF-8">
           <title>購物車</title>
           <link rel="stylesheet" type="text/css" href="style.css">
          </head>
          <body>
          <div id="app" v-cloak>
           ...
          </div>
          <script src="https://cdn.bootcss.com/vue/2.2.2/vue.min.js"></script>
          <script src="index.js"></script>
          </body>
          </html>
          

          因為有可能購物車中的商品被全部刪除,所以我們在此加了判斷,如果列表為空,則給出友好提示:

          <template v-if="list.length">
           ...
          </template>
          <!--當購物車為空時,則提示-->
          <div v-else>購物車內暫時沒有商品</div>
          

          接著用 table 來展示購物車內的商品列表:

          <table>
           <thead>
           <tr>
           <th><input id="checkAll" type="checkbox" class="checkAll" @click="checkAllOrNot($event)"></th>
           <th>序號</th>
           <th>商品</th>
           <th>單價</th>
           <th>數量</th>
           <th>操作</th>
           </tr>
           </thead>
           <tbody>
           <tr v-for="(item,index) in list">
           <td><input type="checkbox" class="checkItem" @click="checkItem($event,index)"></td>
           <td>{{index+1}}</td>
           <td>{{item.name}}</td>
           <td>{{item.price}}</td>
           <td>
           <button @click="reduceCount(index)" :disabled="item.count===1">-</button>
           {{item.count}}
           <button @click="addCount(index)">+</button>
           </td>
           <td>
           <button @click="remove(index)">刪除</button>
           </td>
           </tr>
           </tbody>
          </table>
          <div>總價:¥{{totalPrice}}</div>
          
          • 使用 v-for 指令,循環迭代出商品列表。
          • 表格內的每一個勾選框與按鈕都綁定了相應的事件。全選框與每一行的勾選框還傳入了原生 DOM 事件 $event,用于獲取當前所操作的元素。
          • *這里對減少商品數量的按鈕進行了判斷,當相應商品的數量只剩下一個時,綁定 disabled 樣式,讓它變成不可用。

          4 演示

          、后端TS版搭起MVC架構的web服務器

          注意點:

          1.用TS寫node服務器需要先下node API的TS庫

          2.通過引入文件,通過回調方式,將參數傳入引入文件進行不同層的聯動操作

          3.事件偵聽,拋發的方式完成路由操作

          項目目錄說明:

          1.main:
              0)入口文件
              1)創建了main單例,在當前頁面執行main實例的init方法,即直接node main.js開啟服務
              2)init方法中根據引入的sever類,創建server對象開啟web服務
              3)main類,創建時即注冊了購物車增刪改查操作的事件以及對應的觸發函數dataHandler
              4)因為所有的觸發函數是同一個,根據傳進來事件類型的不同而去創建command對象并執行其exec方法
          2.sever:
              0)負責web服務
              1)接收處理接口請求傳過來的data數據及type接口類型
              2)拋發給main的實例去處理type類型,data數據,同時將http的req,res也傳遞出去
          3.command:
              0)主要用來處理各種業務邏輯,連接Model層等,工作類似于controller層(這里包括ResDataShow,ResGoodsOperate,ResShoppingShow文件)
              1)這里只寫了部分功能的注釋,請查看ResGoodsOperate類的addGoods,deleteGoods,getShoppingItem,getShoppingIndex方法
          4.model:
              0)充當數據庫的角色,web服務只要不掛,這些數據就會一直保持動態更新(掛了,就恢復為初始值了)
              1)主要存放購物車表及商品表數據
              2)創建model的單例,外部主要操作的是model單例
          5.VO層:主要用來定義一些常量,或者說是配置文件,方便根據不同需求直接修改配置文件中的參數即可,不用去每個程序文件中修改
          6.Interface層:
              0)存放接口文件
              1)用于創建規范聲明數據類型(TS中不能隨便定義var xx={a:1,b:"2",c:false}這樣的數據)
              2)用于創建規范的類(如要求command層的類都必須要寫一個exec方法)
          

          后端架構圖:

          二、TS前端MVC架構

          項目目錄說明:

          1.入口文件:
              0)入口文件相當于直接掛載到對應的html頁面上,加載頁面時,就直接執行該文件,類似于三階段實際運行在生產環境的是dist靜態資源,這里的HTML頁面相當于public下的index.html,入口文件相當于是app.js,如ShoppingList.ts,GoodList.ts
              1)以ShoppingList.ts舉例,當渲染購物車列表頁面時,加載該文件,具體細節看該ts文件的注釋
          2.business:
              0)專門處理通信模塊,項目主要封裝AJAX類的post,get方法
              1)給外部其他層去進行ajax請求(主要是view層的shoppingTable中添加,刪除,選中等功能需要調用,這里不應該在view層內進行ajax請求,而是拋出事件在控制層進行數據請求)
              2)因為后臺只實現了商品列表和購物車功能,且接口必返回商品或者購物車數據,所以這里自動更新Model層的存的數據(因為view層視圖主要是根據Model層里的數據進行渲染的)
          3.component:
              1)寫一些用于View層的組件,注意因為TS中沒有事件拋發,所以用自己重寫的events層來拋發數據(如stepNumber組件)   
              2)用在command層,實際還是當成view層,做模板視圖作用
          4.events:上述的重構的事件拋發機制
          5.Interface:存放接口文件,用于規范聲明數據類型以及其他類
          6.utils:存放一些公用的工具ts文件
          7.vo:主要用來定義一些常量,或者說是配置文件,這里只寫了事件類型名稱,ajax后端接口的配置文件
          8.command:
              0)為了配合controller層而寫的一些命令類,主要作用是在其中的exec方法中寫業務邏輯
              1)以ShowShoppingCommand為例,每次觸發事件執行exec方法,作用是重新生成shoppingTable視圖
          9.controller
              0)項目的控制中心,充當觀察者的角色,其中還用到了抽象工廠模式+單例模式(本來打算用工廠模式)
              1)總結:controller相當于是整個前端項目的觀察者,繼承EmitterTarget類,
              2)必須具備有add, remove, dispatch三種方法, 而這三種方法相當于是基于EmitterTarget中的三種方法封裝的
              3)注意controller里的兩個屬性有不同的作用:commandList和list(繼承于EmitterTarget的屬性)
                commandList存放命令類型,對應命令操作的實例化對象數組(不同類的對象)
                list存放命令類型,對應命令操作的實例化對象的exec方法的數組(有點像commandList的底層實現)
              4)具體細節看MainController.ts文件的注釋
          10.model
              1)viewModel:主要用的是其單例,存放兩個屬性divCon容器和showTable模板,這里是用作前端引擎模板作用(根據ShowShoppingCommand.ts以及入口文件ShoppingList.ts推斷)
              2)mainModel:主要是存數據的作用,完成的目的是為了組件之間的通信以及利用set get寫組件的屬性對應渲染到dom上。
              3)每次操作(購物車的增刪改查)引起mainModel層存儲的數據變動(setter)(入口文件ShoppingList.ts綁定通知的事件)
              ->controller層執行command層的命令進行操作
              ->command層去執行調用viewModel
              ->viewModel去調用view層的模板重新渲染視圖到頁面
              ->view層渲染過程中請求mainModel層的數據(getter)
          11.view:展示插入到HTML頁面的主要內容,結合了Component層中的組件,Model層MainModel數據,business層的請求后臺接口操作,Utils層的工具方法,VO層的配置常量,interface層的接口規范,events層因為component層組件需要數據拋發接收,更多細節請看源碼ShoppingTable
          


          ==總結==

          1. TS和JS有很大不一樣的地方在于數據的規范型,所以各種地方都必須要涉及到去聲明數據類型是什么,需要引入已有的數據類型如ServerResponse,自定義創建如IRes這樣的接口。除此之外,我們只能通過斷言as或者聲明為any類型(迫于無奈的情況下)
          2. TS中沒有事件拋發,所以在上述前后端操作中需要用到的事件拋發都是自己重寫的
          3. controller層中本來是想某個命令類型對應的是命令類數組,但是因為TS沒有泛型類數組不能直接存類的數組,所以這里存的是類對應的實例化對象數組。==目的是想用工廠模式,每次調用命令時,根據命令類數組創建新的實例,這樣在數據刷新或者下一次觸發命令時,上一次的數據不會殘留造成污染。由于TS的缺陷,這里用的實例化對象即單例模式。==
          4. 數據模型和顯示模型是完全分離的,實現了組件之間的通信,以及數據改變而重新渲染頁面(單向渲染?)
          5. 這里的MVC模式實際上M V C三層之間數據是可以雙向通信的,后面改良的RMVP模式V和M層不進行數據通信
          6. TS版的MVC架構,即model層變動->view層改變的單向數據流有點像React的單向數據流
          7. view層和component層是可以獨立拿開復用的,不去操作任何數據,只有數據進入,數據拋出,==view層充當的是視圖模板引擎的角色==
          8. MVC和MVVM的不同:
            1)view層本身是沒有不做任何數據操作,view丟出的數據交給controller去改變model view接收數據,引起視圖模板改變,用戶操作view層,view層丟出數據,交給其它層,如果這個層是controller層這里就是MVC結構
            2)如果這里是丟出數據交給的是Model層的viewModel,則這里是MVVM結構,viewModel即是VM,不僅僅是存儲視圖的中心,還充當完成一部分controller層的職責

          前端架構圖:以ShoppingList的操作為例

          增sku到購物車

          上次課我們開發到了顯示商品詳情

          有點擊"添加到購物車"的按鈕

          但是沒有反應,我們完成添加購物車的功能就能實現這個效果了

          打開mall-order-webapi模塊

          業務邏輯中一些基本的注意事項

          • * 判斷用戶是否登錄,只有登錄后才能將商品新增到購物車
          • * 驗證購物車信息的完整性
          • * 業務邏輯層要判斷新增的sku是否在當前用戶的購物車表中已經存在
          • * 如果不存在是新增sku流程
          • * 如果已經存在,是修改數量的流程

          開發持久層

          持久層要按上面分析的業務邏輯,開發多個方法

          1. 判斷當前登錄用戶購物車中是否包含指定skuid商品的方法
          2. 新增sku到購物車表中
          3. 修改購物車指定sku數量的方法

          mapper包創建OmsCartMapper接口,編寫代碼如下

          @Repository
          public interface OmsCartMapper {
          // 判斷當前用戶的購物車列表中是否包含指定sku商品的方法
          OmsCart selectExistsCart(@Param("userId") Long userId,@Param("skuId") Long skuId);
          // 新增商品到購物車表中
          void saveCart(OmsCart omsCart);
          // 修改指定購物車商品的數量的方法
          void updateQuantityById(OmsCart omsCart);
          }

          對應的Mapper.xml文件

          <?xml version="1.0" encoding="UTF-8"?>
          <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
          <mapper namespace="cn.tedu.mall.order.mapper.OmsCartMapper">
          <!-- 通用查詢映射結果 -->
          <resultMap id="BaseResultMap" type="cn.tedu.mall.pojo.order.model.OmsCart">
          <id column="id" property="id" />
          <result column="user_id" property="userId" />
          <result column="sku_id" property="skuId" />
          <result column="title" property="title" />
          <result column="main_picture" property="mainPicture" />
          <result column="price" property="price" />
          <result column="quantity" property="quantity" />
          <result column="gmt_create" property="gmtCreate" />
          <result column="gmt_modified" property="gmtModified" />
          <result column="bar_code" property="barCode"/>
          <result column="data" property="data"/>
          </resultMap>
          <!-- 聲明一個全字符sql片段 -->
          <sql id="SimpleQueryFields">
          <if test="true">
          id,
          user_id,
          sku_id,
          title,
          main_picture,
          price,
          quantity,
          gmt_create,
          gmt_modified
          </if>
          </sql>
          <!-- 判斷當前用戶的購物車列表中是否包含指定sku商品的方法 -->
          <select id="selectExistsCart" resultType="cn.tedu.mall.pojo.order.model.OmsCart">
          select
          <include refid="SimpleQueryFields" />
          from
          oms_cart
          where
          user_id=#{userId}
          and
          sku_id=#{skuId}
          </select>
          <!-- 新增購物車信息 -->
          <insert id="saveCart" useGeneratedKeys="true" keyProperty="id">
          insert into oms_cart(
          user_id,
          sku_id,
          title,
          main_picture,
          price,
          quantity
          ) values(
          #{userId},
          #{skuId},
          #{title},
          #{mainPicture},
          #{price},
          #{quantity}
          )
          </insert>
          <!-- 根據購物車id修改數量 -->
          <update id="updateQuantityById" >
          update
          oms_cart
          set
          quantity=#{quantity}
          where
          id=#{id}
          </update>
          </mapper>

          開發業務邏輯層

          創建OmsCartServiceImpl類實現IOmsCartService接口

          實現其中方法,先實現新增購物車的方法即可

          需要注意,我們在業務邏輯層中需要使用用戶的信息

          要單獨編寫一個方法獲取用戶信息,

          @Service
          public class OmsCartServiceImpl implements IOmsCartService {
          @Autowired
          private OmsCartMapper omsCartMapper;
          @Override
          public void addCart(CartAddDTO cartDTO) {
          // 獲取當前登錄用戶的userId
          Long userId=getUserId();
          // 查詢這個userId的用戶是否已經將指定的sku添加到購物車
          OmsCart omsCart=omsCartMapper.selectExistsCart(userId,cartDTO.getSkuId());
          // 判斷查詢結果是否為null
          if(omsCart!=null){
          // 不等于null,表示當前用戶這個sku已經添加在購物車列表中
          // 我們需要做的就是修改它的數量,根據cartDTO對象的quantity屬性值添加
          omsCart.setQuantity(omsCart.getQuantity()+cartDTO.getQuantity());
          // 調用持久層方法修改數量
          omsCartMapper.updateQuantityById(omsCart);
          }else{
          // 如果omsCart是null 會運行else代碼塊
          // 去完成購物車對象的新增,先實例化OmsCart對象
          OmsCart newOmsCart=new OmsCart();
          // 將參數cartDTO的同名屬性賦值給newOmsCart
          BeanUtils.copyProperties(cartDTO,newOmsCart);
          // cartDTO對象中沒有userId屬性,需要單獨賦
          newOmsCart.setUserId(userId);
          // 執行新增
          omsCartMapper.saveCart(newOmsCart);
          }
          }
          
          @Override
          public JsonPage<CartStandardVO> listCarts(Integer page, Integer pageSize) {
          return null;
          }
          
          @Override
          public void removeCart(Long[] ids) {
          }
          
          @Override
          public void removeAllCarts() {
          }
          
          @Override
          public void removeUserCarts(OmsCart omsCart) {
          }
          
          @Override
          public void updateQuantity(CartUpdateDTO cartUpdateDTO) {
          }
          
          // 業務邏輯層獲得用戶信息的方法,因為多個方法需要獲得用戶信息,所以單獨編寫一個方法
          // 這個方法的實現是SpringSecurity提供的登錄用戶的容器
          // 方法的目標是獲得SpringSecurity用戶容器,從容器中獲得用戶信息
          public CsmallAuthenticationInfo getUserInfo(){
          // 獲得SpringSecurity容器對象
          UsernamePasswordAuthenticationToken authenticationToken=
          (UsernamePasswordAuthenticationToken)SecurityContextHolder.
          getContext().getAuthentication();
          // 判斷獲取的容器信息是否為空
          if(authenticationToken!=null){
          // 如果容器中有內容,證明當前容器中有登錄用戶信息
          // 我們獲取這個用戶信息并返回
          CsmallAuthenticationInfo csmallAuthenticationInfo=
          (CsmallAuthenticationInfo)authenticationToken.getCredentials();
          return csmallAuthenticationInfo;
          }
          throw new CoolSharkServiceException(ResponseCode.UNAUTHORIZED,"沒有登錄信息");
          }
          
          // 業務邏輯層中大多數方法都是獲得用戶id,所以編寫一個返回用戶id的方法
          public Long getUserId(){
          return getUserInfo().getId();
          }
          }

          開發控制層

          創建OmsCartController

          @RestController
          @RequestMapping("/oms/cart")
          @Api(tags = "購物車管理模塊")
          public class OmsCartController {
          @Autowired
          private IOmsCartService omsCartService;
          // 新增購物車信息的控制層方法
          @PostMapping("/add")
          @ApiOperation("新增購物車信息")
          // 判斷當前用戶是否具有普通用戶權限ROLE_user
          // sso模塊登錄時,會在用戶的權限列表中添加ROLE_user權限
          @PreAuthorize("hasRole('ROLE_user')")
          // cartAddDTO參數是需要經過SpringValidation框架驗證的
          // @Validated就是激活框架驗證功能,如果cartAddDTO不滿足驗證要求,會自動運行
          // 統一由異常處理類中的BingingException異常處理
          public JsonResult addCart(@Validated CartAddDTO cartAddDTO){
          omsCartService.addCart(cartAddDTO);
          return JsonResult.ok("成功添加到購物車");
          }
          }

          先注意sso模塊application-test.yml的地址和端口號(密碼有兩個)

          也要注意order模塊application-test.yml的地址和端口號

          都保證正確的前提下

          啟動 leaf passport order

          sso:10002

          order:10005

          先訪問10002登錄獲得JWT 用戶名jackson密碼123456

          先登錄看到JWT 然后復制JWT

          轉到10005 order模塊 文檔管理->全局參數設置->添加參數

          參數名:Authorization

          參數值:Bearer [粘貼JWT]

          然后刷新當前10005的界面

          然后進行發送請求即可成功!

          <dependency>
          <groupId>javax.xml.bind</groupId>
          <artifactId>jaxb-api</artifactId>
          <version>2.3.0</version>
          </dependency>

          SpringSecurity驗證規則

          SpringSecurity框架登錄后,一定會有一個權限列表

          在userDetails對象中

          我們登錄用戶的這個對象的值可能是

          {"authorities":["ROLE_user"],"id":1,"userType":"USER","username":"jackson"}

          sso模塊前臺用戶登錄時,會authorities屬性中添加ROLE_user權限

          而后臺管理用戶登錄時會向authorities屬性中添加下面屬性

          ["/pms/product/read","/pms/product/update","/pms/product/delete"]

          所以想要在控制器運行前判斷權限時就可以使用下面的寫法

          @PreAuthorize("hasAuthority('ROLE_user')")

          hasRole判斷是專用于判斷當前用戶角色的指令

          hasRole會自動在我們判斷的內容前添加ROLE_

          @PreAuthorize("hasRole('ROLE_user')")

          開發查詢購物車功能

          開發持久層

          OmsCartMapper添加方法如下

          // 根據當前用戶id查詢購物車列表
          List<CartStandardVO> selectCartsByUserId(Long userId);

          OmsCartMapper.xml添加對應內容

          <!-- 根據用戶id查詢購物車信息 -->
          <select id="selectCartsByUserId"
          resultType="cn.tedu.mall.pojo.order.vo.CartStandardVO">
          select
          <include refid="SimpleQueryFields" />
          from
          oms_cart
          where
          user_id=#{id}
          </select>

          開發業務邏輯層

          OmsCartServiceImpl業務實現

          返回值支持分頁結果,按分頁條件查詢

          // 根據用戶id分頁查詢當前用戶的購物車列表
          @Override
          public JsonPage<CartStandardVO> listCarts(Integer page, Integer pageSize) {
          // 獲得用戶id
          Long userId=getUserId();
          // 執行查詢前設置分頁條件
          PageHelper.startPage(page,pageSize);
          // 執行分頁查詢
          List<CartStandardVO> list=omsCartMapper.selectCartsByUserId(userId);
          // 實例化PageInfo對象獲得分頁信息后將它轉換為JsonPage返回
          return JsonPage.restPage(new PageInfo<>(list));
          }

          下面開發控制層,調用方法進行測試

          OmsCartController添加方法如下

          // 分頁查詢當前用戶購物車中的信息
          @GetMapping("/list")
          @ApiOperation("分頁查詢當前用戶購物車中的信息")
          @ApiImplicitParams({
          @ApiImplicitParam(value = "頁碼",name = "page",dataType = "int",example = "1"),
          @ApiImplicitParam(value = "每頁條數",name = "pageSize",
          dataType = "int",example = "5")
          })
            @PreAuthorize("hasRole('ROLE_user')")
          public JsonResult<JsonPage<CartStandardVO>> listCartByPage(
            // 當控制器參數可能為空,當空時,我們要給它賦默認值時,可以用下面的格式
            @RequestParam(required = false,defaultValue = WebConsts.DEFAULT_PAGE)
            Integer page,
            @RequestParam(required = false,defaultValue = WebConsts.DEFAULT_PAGE_SIZE)
          Integer pageSize
          ){
            // 控制層調用業務邏輯層代碼
            JsonPage<CartStandardVO> jsonPage=omsCartService.listCarts(page,pageSize);
            return JsonResult.ok(jsonPage);
          }

          啟動nacos\seata

          啟動leaf\sso\order模塊

          測試http://localhost:10005/doc.html

          刪除\清空購物車

          刪除購物車的持久層

          我們刪除購物車的功能支持同時刪除一個或多個購物車中的商品

          基本思路就是將一個要刪除的購物車商品的id數組傳入到Mapper中進行刪除

          在OmsCartMapper接口中添加放方法

          // 根據購物車的id刪除商品(支持刪除多個商品)
          int deleteCartsByIds(Long[] ids);

          對應的mapper.xml

          <!-- 根據id刪除購物車信息 -->
          <delete id="deleteCartsByIds">
          delete from
          oms_cart
          where
          id in
          <foreach collection="ids" item="id" separator="," open="(" close=")">
          #{id}
          </foreach>
          </delete>

          刪除購物車的業務邏輯層

          OmsCartServiceImpl添加方法

          // 按ids數組中的id值刪除cart表中信息
          @Override
          public void removeCart(Long[] ids) {
          // 刪除是包含返回值的
          int rows=omsCartMapper.deleteCartsByIds(ids);
          if(rows==0){
          throw new CoolSharkServiceException(ResponseCode.NOT_FOUND,
          "購物車中沒有您要刪除的商品");
          }
          }

          開發控制層代碼

          OmsCartController

          @PostMapping("/delete")
          @ApiOperation("根據用戶選擇的購物車商品刪除(支持批量)")
          @ApiImplicitParam(value = "刪除購物車的id",name="ids",required = true,
          dataType = "array")
          @PreAuthorize("hasRole('ROLE_user')")
          public JsonResult removeCartsByIds(Long[] ids){
          omsCartService.removeCart(ids);
          return JsonResult.ok();
          }

          開發清空當前登錄用戶購物車的功能

          <delete id="deleteCartsByUserId">
          delete from
          oms_cart
          where
          user_id=#{userId}
          </delete>
          @Override
          public void removeAllCarts() {
          }

          清空購物車功能

          Mapper接口

          // 刪除當前用戶購物車中所有內容
          int deleteCartsByUserId(Long userId);

          mapper.xml

          <!-- 刪除當前用戶購物車中所有內容 -->
          <delete id="deleteCartsByUserId">
          delete from
          oms_cart
          where
          user_id=#{userId}
          </delete>

          OmsCartServiceImpl

          // 清空當前登錄用戶購物車
          @Override
          public void removeAllCarts() {
          Long userId=getUserId();
          int rows=omsCartMapper.deleteCartsByUserId(userId);
          if(rows==0){
          throw new CoolSharkServiceException(ResponseCode.NOT_FOUND,"您的購物車中沒有商品");
          }
          }

          OmsCartController

          // 根據用戶id清空購物車
          @PostMapping("/delete/all")
          @ApiOperation("根據用戶id清空購物車")
          @PreAuthorize("hasRole('ROLE_user')")
          public JsonResult removeCartsByUserId(){
          omsCartService.removeAllCarts();;
          return JsonResult.ok("購物車已清空");
          }

          修改購物車商品數量

          開發業務邏輯層

          因為前面我們已經完成了修改購物車數量的持久層,所以不需要再編寫了,直接從業務層開始

          // 修改購物車商品數量的方法
          @Override
          public void updateQuantity(CartUpdateDTO cartUpdateDTO) {
          // 持久層中已經包含了修改數量的方法,但是參數是OmsCart
          // 將本方法的cartUpdateDTO參數值賦值給OmsCart再調用持久層方法即可
          OmsCart omsCart=new OmsCart();
          BeanUtils.copyProperties(cartUpdateDTO,omsCart);
          // 調用持久層實施修改
          omsCartMapper.updateQuantityById(omsCart);
          }

          控制層OmsCartController

          // 修改購物車數量
          @PostMapping("/update/quantity")
          @ApiOperation("修改購物車數量")
          @PreAuthorize("hasRole('ROLE_user')")
          public JsonResult updateQuantity(@Validated CartUpdateDTO cartUpdateDTO){
          omsCartService.updateQuantity(cartUpdateDTO);
          return JsonResult.ok("修改完成");
          }

          重啟order測試清空和修改購物車數量的功能

          學習記錄,如有侵權請聯系刪除


          主站蜘蛛池模板: 欧美日韩一区二区成人午夜电影| 亚洲AV无码第一区二区三区| 精品国产毛片一区二区无码| 亚洲福利一区二区三区| 亚洲国产成人久久综合一区77 | 国产免费播放一区二区| 中文字幕一区二区人妻| 精品一区二区三区3d动漫| 亚洲视频一区在线观看| 免费一区二区三区| 文中字幕一区二区三区视频播放| 日本人真淫视频一区二区三区| 亚洲伦理一区二区| 亚洲va乱码一区二区三区| 国产一区二区三区免费观在线| 无码精品一区二区三区免费视频| 亚洲av无码一区二区三区观看| 亚洲宅男精品一区在线观看| 国产AV午夜精品一区二区入口| 中文字幕一区二区在线播放| 日韩精品无码人妻一区二区三区 | 美女一区二区三区| 爆乳无码AV一区二区三区| 亚洲一区二区三区免费视频| 无码精品人妻一区二区三区漫画 | 亚洲片一区二区三区| 国产精品制服丝袜一区| 日韩一区二区三区射精| 午夜在线视频一区二区三区| 天天爽夜夜爽人人爽一区二区| av在线亚洲欧洲日产一区二区| 东京热无码av一区二区| 亚洲视频一区二区| 无码人妻精品一区二区三区东京热 | 美女视频一区二区| 无码一区二区三区在线观看| 99精品一区二区免费视频| 亚洲综合一区无码精品| 久久精品无码一区二区app| 老熟女高潮一区二区三区| 国产成人一区二区三区精品久久|