8.新增商品_修改商品回显_提交修改商品

总结

1.点击分类,连级查询分类功能

  • 分类表有id字段和父分类pid字段,根据父分类pid查询id。id又是子类的父分类pid。

2.根据父分类查询品牌功能

  • 注意:分类和品牌是多对多关系,根据父分类id查询品牌,需要多表查询inner join on

3.新增商品功能

  • 表单需要提交哪些数据:肯定涉及到spu, sku表, 新增表单:新增的是一个系列,系列下面有很多sku商品。
    • spu表:品牌id,商品分类id,副标题subTitile,标题title。
    • spuDetail表:json对象,售后服务,商品描述,包装列表…
    • sku表:title标题,images图片,price价格,stock库存,ownSpec特有规格参数,indexes特有规格参数下标

3.1.实体类

  • Spu, SpuBo, Stock, Sku下有Stock
    8.新增商品_修改商品回显_提交修改商品_第1张图片
    3.2.GoodsController
    • 表单请求,有很多请求参数,将请求参数封装到SpuBo对象: cname, bname, spuDetail, skus。SpuBo对象去接收传过来的字段数据

3.3.GoodsService

  • 不仅要将添加数据到spu表,还要添加到spu_detail表,sku表,stock表
    • 根据接收到的SpuBo对象,提取数据,保存到各实体对象中:Spu对象,sku对象,SpuDetal对象,stock对象
      • 注意要补全接收数据SpuBo没有的参数到各对象中。
      • 如:spu自增的id设为null, 创建时间等
    • mapper将对象添加到数据库中
    • 逻辑:
    • 补全spu对象:spuBo.setId(null),spuBo.setSaleable(true)… spu到数据库
    • 补全spuDetail对象,由spuId得到spuDetail对象, spuDetail到数据库
    • 补全skus, 由spuId得到skus对象, skus到数据库
    • 补全stock, 由skuId得到stcok对象, stock到数据库

4.修改商品

  • 注意:修改商品包括两个功能:回显和提交
  • 编辑回显,即根据SpuId查询spu对象,SpuDetail,skus对象,得到系列商品基本信息(品牌标题分类等)和细节信息(商品详情,包装)和skus。

4.1 修改spu,回显数据
- GET请求:传递spuid,查询spu对象spuDetail和skus对象,将对象信息回显到表单
- GoodsController
- public ResponseEntity querySpuDetailBySpuId(@PathVariable(“spuId”)Long spuId)
- public ResponseEntity querySkusBySpuId(@RequestParam(“id”)Long spuId)
- GoodsService
- public SpuDetail querySpuDetailBySpuId(Long spuId)
- public List querySkusBySpuId(Long spuId) 还要forEach setstock
4.2 提交修改数据
- POST请求:传递SpuBo对象
- GoodsController
- public ResponseEntity updateGoods(@RequestBody SpuBo spuBo)
- GoodsService
- public void update(SpuBo spu)
- 注意:新增表单提交和编辑表单提交不一样的地方
- 编辑表单提交:
- 查询以前的skus, 如果存在,则删除,spuId得到skus,删除数据库中的skus
- 新增skus和库存, spuId得到skus
- 更新补全spu,更新spuDetail
- 新增表单提交:
- 补全spu
- 新增skus

商品新增

实现功能:新增商品——选择商品分类后——下拉菜单出现所有对应品牌
8.新增商品_修改商品回显_提交修改商品_第2张图片

功能:选择分类,显示品牌

Request URL: http://api.leyou.com/api/item/category/list?pid=0
Request URL: http://api.leyou.com/api/item/category/list?pid=74
Request URL: http://api.leyou.com/api/item/category/list?pid=75
Request URL: http://api.leyou.com/api/item/brand/cid/76
Request URL: http://api.leyou.com/api/item/spec/params?cid=76

根据父类pid查询子类,

根据分类id查询品牌名称,多表查询,tb_brand INNER JOIN tb_brand_ccategory

功能:提交表单,将新增的商品提交到数据库

提交的内容:
8.新增商品_修改商品回显_提交修改商品_第3张图片

8.新增商品_修改商品回显_提交修改商品_第4张图片

8.新增商品_修改商品回显_提交修改商品_第5张图片
8.新增商品_修改商品回显_提交修改商品_第6张图片
8.新增商品_修改商品回显_提交修改商品_第7张图片
要新增的表项:

点击提交,查看控制台提交的数据格式:

8.新增商品_修改商品回显_提交修改商品_第8张图片

整体是一个json格式数据,包含Spu表所有数据:

  • brandId:品牌id
  • cid1、cid2、cid3:商品分类id
  • subTitle:副标题
  • title:标题
  • spuDetail:是一个json对象,代表商品详情表数据
    • afterService:售后服务
    • description:商品描述
    • packingList:包装列表
    • specialSpec:sku规格属性模板
    • genericSpec:通用规格参数
  • skus:spu下的所有sku数组,元素是每个sku对象:
    • title:标题
    • images:图片
    • price:价格
    • stock:库存
    • ownSpec:特有规格参数
    • indexes:特有规格参数的下标

后台实现

实体类

SPU和SpuDetail实体类已经添加过,添加Sku和Stock对象:

Sku

@Table(name = "tb_sku")
public class Sku {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Long spuId;
    private String title;
    private String images;
    private Long price;
    private String ownSpec;// 商品特殊规格的键值对
    private String indexes;// 商品特殊规格的下标
    private Boolean enable;// 是否有效,逻辑删除用
    private Date createTime;// 创建时间
    private Date lastUpdateTime;// 最后修改时间
    @Transient
    private Integer stock;// 库存
}

注意:这里保存了一个库存字段,在数据库中是另外一张表保存的,方便查询。

Stock

@Table(name = "tb_stock")
public class Stock {
    @Id
    private Long skuId;
    private Integer seckillStock;// 秒杀可用库存
    private Integer seckillTotal;// 已秒杀数量
    private Integer stock;// 正常库存
}

GoodsController

结合浏览器页面控制台,可以发现:

请求方式:POST

请求路径:/goods

请求参数:Spu的json格式的对象,spu中包含spuDetail和Sku集合。这里我们该怎么接收?我们之前定义了一个SpuBo对象,作为业务对象。这里也可以用它,不过需要再扩展spuDetail和skus字段:

public class SpuBo extends Spu {

    String cname;// 商品分类名称
    String bname;// 品牌名称
    SpuDetail spuDetail;// 商品详情
    List<Sku> skus;// sku列表
}

返回类型:无

在GoodsController中添加新增商品的代码:

@PostMapping("goods")
public ResponseEntity<Void> saveGoods(@RequestBody SpuBo spuBo){
    this.goodsService.saveGoods(spuBo);
    return ResponseEntity.status(HttpStatus.CREATED).build();
}

注意:通过@RequestBody注解来接收Json请求

GoodsService

这里的逻辑比较复杂,我们除了要对SPU新增以外,还要对SpuDetail、Sku、Stock进行保存

/**
     * 新增商品
     * @param spuBo
     */
@Transactional
public void saveGoods(SpuBo spuBo) {
    // 新增spu
    // 设置默认字段
    spuBo.setId(null);
    spuBo.setSaleable(true);
    spuBo.setValid(true);
    spuBo.setCreateTime(new Date());
    spuBo.setLastUpdateTime(spuBo.getCreateTime());
    this.spuMapper.insertSelective(spuBo);

    // 新增spuDetail
    SpuDetail spuDetail = spuBo.getSpuDetail();
    spuDetail.setSpuId(spuBo.getId());
    this.spuDetailMapper.insertSelective(spuDetail);

    saveSkuAndStock(spuBo);
}

private void saveSkuAndStock(SpuBo spuBo) {
    spuBo.getSkus().forEach(sku -> {
        // 新增sku
        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);
    });
}

Mapper

通用Mapper

2.修改商品

2.1.编辑按钮点击事件

在商品详情页,每一个商品后面,都会有一个编辑按钮:
8.新增商品_修改商品回显_提交修改商品_第9张图片
点击这个按钮,就会打开一个商品编辑窗口,我们看下它所绑定的点击事件:(在item/Goods.vue)
8.新增商品_修改商品回显_提交修改商品_第10张图片
对应的方法:
8.新增商品_修改商品回显_提交修改商品_第11张图片
可以看到这里发起了两个请求,在查询商品详情和sku信息。

因为在商品列表页面,只有spu的基本信息:id、标题、品牌、商品分类等。比较复杂的商品详情(spuDetail)和sku信息都没有,编辑页面要回显数据,就需要查询这些内容。

因此,接下来我们就编写后台接口,提供查询服务接口。

2.2.查询SpuDetail接口

GoodsController

需要分析的内容:

  • 请求方式:GET
  • 请求路径:/spu/detail/{id}
  • 请求参数:id,应该是spu的id
  • 返回结果:SpuDetail对象
@GetMapping("spu/detail/{spuId}")
public ResponseEntity<SpuDetail> querySpuDetailBySpuId(@PathVariable("spuId")Long spuId){
    SpuDetail spuDetail = this.goodsService.querySpuDetailBySpuId(spuId);
    if (spuDetail == null) {
        return ResponseEntity.notFound().build();
    }
    return ResponseEntity.ok(spuDetail);
}

GoodsService

/**
     * 根据spuId查询spuDetail
     * @param spuId
     * @return
     */
public SpuDetail querySpuDetailBySpuId(Long spuId) {

    return this.spuDetailMapper.selectByPrimaryKey(spuId);
}

测试
8.新增商品_修改商品回显_提交修改商品_第12张图片

2.3.查询sku

分析

  • 请求方式:Get
  • 请求路径:/sku/list
  • 请求参数:id,应该是spu的id
  • 返回结果:sku的集合

GoodsController

@GetMapping("sku/list")
public ResponseEntity<List<Sku>> querySkusBySpuId(@RequestParam("id")Long spuId){
    List<Sku> skus = this.goodsService.querySkusBySpuId(spuId);
    if (CollectionUtils.isEmpty(skus)) {
        return ResponseEntity.notFound().build();
    }
    return ResponseEntity.ok(skus);
}

GoodsService

需要注意的是,为了页面回显方便,我们一并把sku的库存stock也查询出来

/**
     * 根据spuId查询sku的集合
     * @param spuId
     * @return
     */
public List<Sku> querySkusBySpuId(Long spuId) {
    Sku sku = new Sku();
    sku.setSpuId(spuId);
    List<Sku> skus = this.skuMapper.select(sku);
    skus.forEach(s -> {
        Stock stock = this.stockMapper.selectByPrimaryKey(s.getId());
        s.setStock(stock.getStock());
    });
    return skus;
}

测试:
8.新增商品_修改商品回显_提交修改商品_第13张图片

2.4.页面回显

随便点击一个编辑按钮,发现数据回显完成:

8.新增商品_修改商品回显_提交修改商品_第14张图片
8.新增商品_修改商品回显_提交修改商品_第15张图片
8.新增商品_修改商品回显_提交修改商品_第16张图片
8.新增商品_修改商品回显_提交修改商品_第17张图片

2.5.页面提交

这里的保存按钮与新增其实是同一个,因此提交的逻辑也是一样的,这里不再赘述。

随便修改点数据,然后点击保存,可以看到浏览器已经发出请求:
8.新增商品_修改商品回显_提交修改商品_第18张图片

2.6.后台实现

接下来,我们编写后台,实现修改商品接口。

2.6.1.GoodsController

  • 请求方式:PUT
  • 请求路径:/
  • 请求参数:Spu对象
  • 返回结果:无
@PutMapping("goods")
public ResponseEntity<Void> updateGoods(@RequestBody SpuBo spuBo){
    this.goodsService.updateGoods(spuBo);
    return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}

2.6.2.GoodsService

spu数据可以修改,但是SKU数据无法修改,因为有可能之前存在的SKU现在已经不存在了,或者以前的sku属性都不存在了。比如以前内存有4G,现在没了。

因此这里直接删除以前的SKU,然后新增即可。

代码:

@Transactional
public void update(SpuBo spu) {
    // 查询以前sku
    List<Sku> skus = this.querySkuBySpuId(spu.getId());
    // 如果以前存在,则删除
    if(!CollectionUtils.isEmpty(skus)) {
        List<Long> ids = skus.stream().map(s -> s.getId()).collect(Collectors.toList());
        // 删除以前库存
        Example example = new Example(Stock.class);
        example.createCriteria().andIn("skuId", ids);
        this.stockMapper.deleteByExample(example);

        // 删除以前的sku
        Sku record = new Sku();
        record.setSpuId(spu.getId());
        this.skuMapper.delete(record);

    }
    // 新增sku和库存
    saveSkuAndStock(spuBo);

    // 更新spu
    spu.setLastUpdateTime(new Date());
    spu.setCreateTime(null);
    spu.setValid(null);
    spu.setSaleable(null);
    this.spuMapper.updateByPrimaryKeySelective(spu);

    // 更新spu详情
    this.spuDetailMapper.updateByPrimaryKeySelective(spu.getSpuDetail());
}

2.6.3.mapper

与以前一样。

2.7.其它

商品的删除、上下架大家自行实现。

你可能感兴趣的:(springcloud项目)