1.商品新增
当我们点击新增商品按钮:
就会出现一个弹窗:
里面把商品的数据分为了4部分来填写:
-
基本信息:主要是一些简单的文本数据,包含了SPU和SpuDetail的部分数据,如
- 商品分类:是SPU中的
cid1,cid2,cid3属性 - 品牌:是spu中的
brandId属性 - 标题:是spu中的
title属性 - 子标题:是spu中的
subTitle属性 - 售后服务:是SpuDetail中的
afterService属性 - 包装列表:是SpuDetail中的
packingList属性
- 商品分类:是SPU中的
-
商品描述:是SpuDetail中的
description属性,数据较多,所以单独放一个页面 -
规格参数:商品规格信息,对应SpuDetail中的
genericSpec属性 -
SKU属性:spu下的所有Sku信息
对应到页面中的四个stepper-content:
1.2.基本数据
我们先来看下基本数据:
1.2.1.商品分类
商品分类信息查询我们之前已经做过,所以这里的级联选框已经实现完成:
1.2.2.品牌选择
1.2.2.1页面
品牌也是一个下拉选框,不过其选项是不确定的,只有当用户选择了商品分类,才会把这个分类下的所有品牌展示出来。
所以页面编写了watch函数,监控商品分类的变化,每当商品分类值有变化,就会发起请求,查询品牌列表:
选择商品分类后,可以看到请求发起:
1.2.2.2后台接口
页面需要去后台查询品牌信息,我们自然需要提供:
请求方式:GET
请求路径:/brand/cid/{cid}
请求参数:cid
响应数据:品牌集合
Controller:
@GetMapping("cid/{cid}")
public ResponseEntity<List<Brand>> queryBrandsByCid(@PathVariable("cid")Long cid){
List<Brand> brands = this.brandService.queryBrandsByCid(cid);
if (CollectionUtils.isEmpty(brands)) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(brands);
}
Service:
public List<Brand> queryBrandsByCid(Long cid) {
return this.brandMapper.selectBrandByCid(cid);
}
Mapper:
@Select("SELECT b.* from tb_brand b INNER JOIN tb_category_brand cb on b.id=cb.brand_id where cb.category_id=#{cid}")
List<Brand> selectBrandByCid(Long cid);
1.3.商品描述
商品描述信息比较复杂,而且图文并茂,甚至包括视频。
这样的内容,一般都会使用富文本编辑器。
1.3.1.什么是富文本编辑器
效果:
新增商品信息:
Controller:
@PostMapping("goods")
public ResponseEntity<Void> addGoods(@RequestBody SpuBo spuBo){
this.goodService.addGoods(spuBo);
return ResponseEntity.status(HttpStatus.CREATED).build();
}
Service:
public void addGoods(SpuBo spuBo) {
//先增加Spu表中的内容
spuBo.setId(null);
spuBo.setValid(true);
spuBo.setSaleable(true);
spuBo.setCreateTime(new Date());
spuBo.setLastUpdateTime(spuBo.getCreateTime());
this.spuMapper.insertSelective(spuBo);
//在增加Spu_Detao表中的内容
SpuDetail spuDetail = spuBo.getSpuDetail();
spuDetail.setSpuId(spuBo.getId());
this.spuDetailMapper.insertSelective(spuDetail);
//在增加Sku和Sku_Stock表中的内容
List<Sku> skus = spuBo.getSkus();
skus.forEach(sku -> {
sku.setId(null);
sku.setSpuId(spuBo.getId());
sku.setCreateTime(new Date());
sku.setLastUpdateTime(sku.getCreateTime());
this.skuMapper.insertSelective(sku);
Stock stock = new Stock();
stock.setSkuId(sku.getId());
stock.setStock(sku.getStock());
this.stockMapper.insertSelective(stock);
});
}
完成测试:数据已经正常存入到表中
2.商品修改
2.1.编辑按钮点击事件
在商品详情页,每一个商品后面,都会有一个编辑按钮:
可以看到这里发起了两个请求,在查询商品详情和sku信息。
因为在商品列表页面,只有spu的基本信息:id、标题、品牌、商品分类等。比较复杂的商品详情(spuDetail)和sku信息都没有,编辑页面要回显数据,就需要查询这些内容。
因此,接下来我们就编写后台接口,提供查询服务接口。
Controller:
@GetMapping("sku/list")
public ResponseEntity<List<Sku>> queryBySkuList(@RequestParam("id")Long spuId){
List<Sku> spuList= this.goodService.queryBySkuId(spuId);
if (spuList==null || CollectionUtils.isEmpty(spuList)){
return ResponseEntity.badRequest().build();
}
return ResponseEntity.ok(spuList);
}
Service:
public List<Sku> queryBySkuId(Long spuId) {
Sku sku=new Sku();
sku.setSpuId(spuId);
List<Sku> skuList = this.skuMapper.select(sku);
skuList.forEach(sku1 -> {
Stock stock=new Stock();
stock.setSkuId(sku1.getId());
Stock stock1 = this.stockMapper.selectByPrimaryKey(stock);
sku1.setStock(stock1.getStock());
});
return skuList;
}
完成测试:
2.5.页面提交
这里的保存按钮与新增其实是同一个,因此提交的逻辑也是一样的,这里不再赘述。
随便修改点数据,然后点击保存,可以看到浏览器已经发出请求:
编写接口:
Controller:
@PutMapping("goods")
private ResponseEntity<Void> EditGoods(@RequestBody SpuBo spuBo){
this.goodService.editGoods(spuBo);
return ResponseEntity.noContent().build();
}
Service:
public void editGoods(SpuBo spuBo) {
//删除Stock
Sku record=new Sku();
record.setSpuId(spuBo.getId());
List<Sku> skuList = this.skuMapper.select(record);
skuList.forEach(sku -> {
//删除Stock
this.stockMapper.deleteByPrimaryKey(sku.getId());
});
//删除Sku
Sku sku=new Sku();
sku.setSpuId(spuBo.getId());
this.skuMapper.delete(sku);
//更新Sku和Stock
saveSkuAndStock(spuBo);
//新增Spu
spuBo.setCreateTime(null);
spuBo.setLastUpdateTime(new Date());
spuBo.setSaleable(null);
spuBo.setValid(null);
this.spuMapper.updateByPrimaryKeySelective(spuBo);
//新增SpuDetail
this.spuDetailMapper.updateByPrimaryKeySelective(spuBo.getSpuDetail());
}
完成测试:
3.搭建前台系统
后台系统的内容暂时告一段落,有了商品,接下来我们就要在页面展示商品,给用户提供浏览和购买的入口,那就是我们的门户系统。
门户系统面向的是用户,安全性很重要,而且搜索引擎对于单页应用并不友好。因此我们的门户系统不再采用与后台系统类似的SPA(单页应用)。
依然是前后端分离,不过前端的页面会使用独立的html,在每个页面中使用vue来做页面渲染。
3.1.静态资源
webpack打包多页应用配置比较繁琐,项目结构也相对复杂。这里为了简化开发(毕竟我们不是专业的前端人员),我们不再使用webpack,而是直接编写原生的静态HTML。
这个直接新建一个模块,并把页面全部复制进去就可以了
3.2.live-server
没有webpack,我们就无法使用webpack-dev-server运行这个项目,实现热部署。
所以,这里我们使用另外一种热部署方式:live-server,
3.2.1.简介
3.2.2.安装和运行参数
安装,使用npm命令即可,这里建议全局安装,以后任意位置可用
npm install -g live-server
运行时,直接输入命令:
live-server
完成测试: