整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

使用 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测试清空和修改购物车数量的功能

学习记录,如有侵权请联系删除