乐优商城项目---day10-商品管理

88 阅读4分钟

1.商品新增

当我们点击新增商品按钮:

就会出现一个弹窗:

 

里面把商品的数据分为了4部分来填写:

  • 基本信息:主要是一些简单的文本数据,包含了SPU和SpuDetail的部分数据,如

    • 商品分类:是SPU中的cid1cid2cid3属性
    • 品牌:是spu中的brandId属性
    • 标题:是spu中的title属性
    • 子标题:是spu中的subTitle属性
    • 售后服务:是SpuDetail中的afterService属性
    • 包装列表:是SpuDetail中的packingList属性
  • 商品描述:是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.简介

地址;www.npmjs.com/package/liv…

3.2.2.安装和运行参数

安装,使用npm命令即可,这里建议全局安装,以后任意位置可用

npm install -g live-server

运行时,直接输入命令:

live-server

 

完成测试:

 

  今日总结: