物車一般包含商品名稱、單價、數量等信息,數量可以任意新增或減少,商品項也可刪除,還可以支持全選或多選:
最終效果
我們把這個小項目分為三個文件:
首先在 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: [] }
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 中,我們定義了以下功能方法:
[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 樣式,用于解決網絡慢時的閃屏問題。還定義了表格的相關樣式。
接著在 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>
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方法)
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
上次課我們開發到了顯示商品詳情
有點擊"添加到購物車"的按鈕
但是沒有反應,我們完成添加購物車的功能就能實現這個效果了
打開mall-order-webapi模塊
業務邏輯中一些基本的注意事項
持久層要按上面分析的業務邏輯,開發多個方法
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框架登錄后,一定會有一個權限列表
在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測試清空和修改購物車數量的功能
學習記錄,如有侵權請聯系刪除
*請認真填寫需求信息,我們會在24小時內與您取得聯系。