谷粒商城 Day04 sku与spu接口

Day04 sku与spu接口

一、答疑

1、Docker

① 如果在创建容器的时候,没有进行端口映射和卷的挂载,后来又想添加,我们如何做呢?

docker update 不行

把docker容器的核心内容docker cp出来,再启动一个新容器挂载

② 如何创建nacos的容器镜像呢,和Sentinel完全不一样?

FROM alpine
COPY ./nacos /app/nacos

ENTRYPOINT [“sh”,"/app/nacos/bin/startup.sh"]

2、SQL

① 怎么优化SQL的sendingdata的时间?感觉很影响整体速度。

select 不写* ,查少量列

select where 限制好,只查到核心内容

② 一条读写sql语句的执行过程就是按照架构图上面的顺序吗?

连接器 —> 语法分析器 —> 优化器 —> 执行器


二、品牌的CRUD

1、新增品牌

文档

接口http://api.gmall.com/admin/product/baseTrademark/save
请求参数{tmName: “锤子。”, logoUrl: “/static/default.jpg”}
请求方式post
例:http://api.gmall.com/admin/product/baseTrademark/save
返回值{code: 200, message: “成功”, data: null, ok: true}

BaseTrademarkController

/**
 * 添加品牌
 * 请求参数:{tmName: "锤子。", logoUrl: "/static/default.jpg"}
 * @param baseTrademark
 * @return
 */
@PostMapping("/baseTrademark/save")
public Result baseTrademarkSave(@RequestBody BaseTrademark baseTrademark){
    log.info("baseTrademark:{}",baseTrademark);

    baseTrademarkService.save(baseTrademark);

    return Result.ok();
}

对照 BaseTrademark

BaseTrademark

@Data
@ApiModel(description = "商标品牌")
@TableName("base_trademark")
public class BaseTrademark extends BaseEntity {
   
   private static final long serialVersionUID = 1L;
   
   @ApiModelProperty(value = "属性值")
   @TableField("tm_name")
   private String tmName;

   @ApiModelProperty(value = "品牌logo的图片路径")
   @TableField("logo_url")
   private String logoUrl;

}

2、修改品牌

文档

接口http://api.gmall.com/admin/product/baseTrademark/update
请求参数baseTrademark的json字符串
请求方式put
例:http://api.gmall.com/admin/product/baseTrademark/update
返回值{code: 200, message: “成功”, data: null, ok: true}

BaseTrademarkController

/**
 * 修改品牌
 * @param baseTrademark
 * @return
 */
@PutMapping("/baseTrademark/update")
public Result baseTrademarkUpdate(@RequestBody BaseTrademark baseTrademark){
    baseTrademarkService.updateById(baseTrademark);
    return Result.ok();
}

3、删除品牌

文档

接口http://api.gmall.com/admin/product/baseTrademark/remove/{id}
请求参数品牌Id
请求方式delete
例:http://api.gmall.com/admin/product/baseTrademark/remove/1
返回值{code: 200, message: “成功”, data: null, ok: true}

BaseTrademarkController

/**
 * 删除品牌
 * @param id
 * @return
 */
@DeleteMapping("/baseTrademark/remove/{id}")
public Result baseTrademarkRemove(@PathVariable("id") Long id){
    baseTrademarkService.removeById(id);
    return Result.ok();
}

4、根据Id获取品牌

文档

接口http://api.gmall.com/admin/product/baseTrademark/get/{id}
请求参数品牌Id
请求方式get
例:http://api.gmall.com/admin/product/baseTrademark/get/1
返回值{
“code”: 200,
“message”: “成功”,
“data”: {
“id”: 1,
“tmName”: “苹果”,
“logoUrl”: “http://192.168.200.128:8080/group1/M00/00/00/wKjIgF5r8hSELUs1AAAAAIyTSXk960.png”
},
“ok”: true
}
{
  "code": 200,
  "message": "成功",
  "data": {
    "id": 1,
    "tmName": "苹果",
    "logoUrl": "http://192.168.200.128:8080/group1/M00/00/00/wKjIgF5r8hSELUs1AAAAAIyTSXk960.png"
  },
  "ok": true
}

BaseTrademarkController

/**
 * 按照id获取品牌
 * @param id
 * @return
 */
@GetMapping("/baseTrademark/get/{id}")
public Result<BaseTrademark> baseTrademarkGet(@PathVariable("id") Long id){

    BaseTrademark trademarkServiceById = baseTrademarkService.getById(id);

    return Result.ok(trademarkServiceById);
}

三、SPU的CRUD

1、获取spu分页列表

文档

接口http://api.gmall.com/admin/product/{page}/{limit}?category3Id=61
请求参数page:第几页limit:每页数量category3Id:三级分类ID
请求方式get
例:http://api.gmall.com/admin/product/1/10?category3Id=61
返回值{
“code”:200,
“message”:“成功”,
“data”:{
“records”:[
{
“id”:2,
“spuName”:“华为 HUAWEI Mate 30 5G”,
“description”:“品牌: 华为(HUAWEI) 商品名称:华为Mate 30 5G商品编号:100009177424商品毛重:0.6kg商品产地:中国大陆CPU型号:其他运行内存:8GB机身存储:128GB存储卡:NM存储卡摄像头数量:后置三摄后摄主摄像素:4000万像素前摄主摄像素:2400万像素主屏幕尺寸(英寸):6.62英寸 备注:显示屏采用圆角设计,按照标准矩形测量时,屏幕的对角线长度是6.62英寸(实际可视区域略小)分辨率:全高清FHD+屏幕比例:其它屏幕比例屏幕前摄组合:刘海屏电池容量(mAh):4200mAh(典型值) 备注:电池额定容量为4100mAh充电器:5V/2A;9V/2A;10V/4A机身颜色:亮黑色热点:5G游戏性能:发烧级操作系统:Android(安卓)”,
“category3Id”:61,
“tmId”:2,
“spuSaleAttrList”:null,
“spuImageList”:null
},

],
“total”:2,
“size”:10,
“current”:1,
“pages”:1
},
“ok”:true
}
{
    "code":200,
    "message":"成功",
    "data":{
        "records":[
            {
                "id":2,
                "spuName":"华为 HUAWEI Mate 30 5G",
                "description":"品牌: 华为(HUAWEI) 商品名称:华为Mate 30 5G商品编号:100009177424商品毛重:0.6kg商品产地:中国大陆CPU型号:其他运行内存:8GB机身存储:128GB存储卡:NM存储卡摄像头数量:后置三摄后摄主摄像素:4000万像素前摄主摄像素:2400万像素主屏幕尺寸(英寸):6.62英寸 备注:显示屏采用圆角设计,按照标准矩形测量时,屏幕的对角线长度是6.62英寸(实际可视区域略小)分辨率:全高清FHD+屏幕比例:其它屏幕比例屏幕前摄组合:刘海屏电池容量(mAh):4200mAh(典型值) 备注:电池额定容量为4100mAh充电器:5V/2A;9V/2A;10V/4A机身颜色:亮黑色热点:5G游戏性能:发烧级操作系统:Android(安卓)",
                "category3Id":61,
                "tmId":2,
                "spuSaleAttrList":null,
                "spuImageList":null
            },],
        "total":2,
        "size":10,
        "current":1,
        "pages":1
    },
    "ok":true
}
① SpuController

新建 com.atguigu.gmall.product.controller.SpuController

/**
 * SPU操作类
 */
@RequestMapping("/admin/product")
@RestController
public class SpuController {
    
    @Autowired
    SpuInfoService spuInfoService;
    
    /**
     * 分页查询SpuInfo信息
     *
     * @param category3Id
     * @param page
     * @param limit
     * @return
     */
    //http://api.gmall.com/admin/product/{page}/{limit}?category3Id=61
    //get
    @GetMapping("/{page}/{limit}")
    public Result<Page<SpuInfo>> spuInfoPageList(
            @RequestParam("category3Id") Long category3Id,
            @PathVariable("page") Long page,
            @PathVariable("limit") Long limit) {

        Page<SpuInfo> spuInfoPage = new Page<>(page, limit);

        QueryWrapper<SpuInfo> spuInfoQueryWrapper = new QueryWrapper<>();
        spuInfoQueryWrapper.eq("category3_id", category3Id);

        Page<SpuInfo> infoPage = spuInfoService.page(spuInfoPage, spuInfoQueryWrapper);

        return Result.ok(infoPage);
    }
}
② SpuInfoService

新建 com.atguigu.gmall.product.service.SpuInfoService

public interface SpuInfoService extends IService<SpuInfo> {

}
③ SpuInfoServiceImpl

新建 com.atguigu.gmall.product.service.impl.SpuInfoServiceImpl

@Service
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoMapper, SpuInfo> implements SpuInfoService {

}
④ SpuInfoMapper

新建 com.atguigu.gmall.product.mapper.SpuInfoMapper

public interface SpuInfoMapper extends BaseMapper<SpuInfo> {
}
⑤ SpuInfoMapper.xml

新建 service/service-product/src/main/resources/mapper/SpuInfoMapper.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="com.atguigu.gmall.product.mapper.SpuInfoMapper">

</mapper>

对照着 SpuInfo

⑥ SpuInfo
@Data
@ApiModel(description = "SpuInfo")
@TableName("spu_info")
public class SpuInfo extends BaseEntity {
   
   private static final long serialVersionUID = 1L;
   
   @ApiModelProperty(value = "商品名称")
   @TableField("spu_name")
   private String spuName;

   @ApiModelProperty(value = "商品描述(后台简述)")
   @TableField("description")
   private String description;

   @ApiModelProperty(value = "三级分类id")
   @TableField("category3_id")
   private Long category3Id;

   @ApiModelProperty(value = "品牌id")
   @TableField("tm_id")
   private Long tmId;

   // 销售属性集合
   @TableField(exist = false)
   private List<SpuSaleAttr> spuSaleAttrList;

   // 商品的图片集合
   @TableField(exist = false)
   private List<SpuImage> spuImageList;

}

效果

image-20210919200314574

2、获取销售属性

文档

接口http://api.gmall.com/admin/product/baseSaleAttrList
请求参数
请求方式get
例:http://api.gmall.com/admin/product/baseSaleAttrList
返回值{
“code”:200,
“message”:“成功”,
“data”:[
{
“id”:1,
“name”:“选择颜色”
},
{
“id”:2,
“name”:“选择版本”
},
{
“id”:3,
“name”:“选择套装”
}
],
“ok”:true
}
{
    "code":200,
    "message":"成功",
    "data":[
        {
            "id":1,
            "name":"选择颜色"
        },
        {
            "id":2,
            "name":"选择版本"
        },
        {
            "id":3,
            "name":"选择套装"
        }
    ],
    "ok":true
}
① BaseSaleAttrController

新建 com.atguigu.gmall.product.controller.BaseSaleAttrController

@RequestMapping("/admin/product/")
@RestController
public class BaseSaleAttrController {

    @Autowired
    BaseSaleAttrInfoService saleAttrInfoService;

    /**
     * 查询所有销售属性名
     * @return
     */
    @GetMapping("/baseSaleAttrList")
    public Result<List<BaseSaleAttr>> getBaseSaleAttrList(){

        List<BaseSaleAttr> list = saleAttrInfoService.list();

        return Result.ok(list);
    }
}
② BaseSaleAttrInfoService

新建 com.atguigu.gmall.product.service.BaseSaleAttrInfoService

public interface BaseSaleAttrInfoService extends IService<BaseSaleAttr> {
}
③ BaseSaleAttrInfoServiceImpl

新建 com.atguigu.gmall.product.service.impl.BaseSaleAttrInfoServiceImpl

@Service
public class BaseSaleAttrInfoServiceImpl extends ServiceImpl<BaseSaleAttrInfoMapper, BaseSaleAttr> implements BaseSaleAttrInfoService {

}
④ BaseSaleAttrInfoMapper

新建 com.atguigu.gmall.product.mapper.BaseSaleAttrInfoMapper

public interface BaseSaleAttrInfoMapper extends BaseMapper<BaseSaleAttr> {

}
⑤ BaseSaleAttrInfoMapper.xml

新建 service/service-product/src/main/resources/mapper/BaseSaleAttrInfoMapper.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="com.atguigu.gmall.product.mapper.BaseSaleAttrInfoMapper">

</mapper>

对照 BaseSaleAttr

⑥ BaseSaleAttr
@Data
@ApiModel(description = "销售属性")
@TableName("base_sale_attr")
public class BaseSaleAttr extends BaseEntity {
   
   private static final long serialVersionUID = 1L;
   
   @ApiModelProperty(value = "销售属性名称")
   @TableField("name")
   private String name;

}

3、获取品牌属性

① 数据库表的复习
(1)一对一
image-20210919201649812
(2)一对多
image-20210919201719486
(3)多对多
image-20210919202002233

获取品牌属性

接口http://api.gmall.com/admin/product/baseTrademark/getTrademarkList
请求参数
请求方式get
例:http://api.gmall.com/admin/product/baseTrademark/getTrademarkList
返回值{
“code”:200,
“message”:“成功”,
“data”:[
{
“id”:1,
“tmName”:“苹果”,
“logoUrl”:“http://127.0.0.1/assets/img/_/phone01.png”
},

],
“ok”:true
}
{
    "code":200,
    "message":"成功",
    "data":[
        {
            "id":1,
            "tmName":"苹果",
            "logoUrl":"http://127.0.0.1/assets/img/_/phone01.png"
        },],
    "ok":true
}
② BaseTrademarkController
/**
 * 获取所有
 * @return
 */
//http://api.gmall.com/admin/product/baseTrademark/getTrademarkList
@GetMapping("/baseTrademark/getTrademarkList")
public Result getBaseTrademarkList(){

    List<BaseTrademark> list = baseTrademarkService.list();
    return Result.ok(list);
}
image-20210919202438809

4、spu保存

① 分析传递的数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wooXlpco-1639309167470)(Day04 sku与spu接口.assets/image-20210919204946599.png)]

当我们点击保存的时候

image-20210919205022226 image-20210919205048742

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V3tITNRo-1639309167475)(Day04 sku与spu接口.assets/image-20210919205113070.png)]

对照着 spu_info 看

image-20210919205216247

对照着 spu_image 看

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NoG3uXj8-1639309167476)(Day04 sku与spu接口.assets/image-20210919205341090.png)]

② spu 数据结构图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Esq4YoWH-1639309167478)(Day04 sku与spu接口.assets/image-20210919205510024.png)]

③ 写 SQL
(1)查询某一个 spu 的销售属性

例如:查询 spu_id 为24的销售属性

image-20210919210644682
(2)查询某个 spu 的销售属性以及值的详情
image-20210919211613090
④ 分析流程和步骤
保存SPU
1、spu_info
2、spu_image : spu把后来所有sku要用的图片全部上传好,录入sku的时候sku自己选
3、spu_sale_attr、spu_sale_attr_value
先操作spu_sale_attr,保存以下值
	"baseSaleAttrId":"1",
	"saleAttrName":"选择颜色",
再操作spu_sale_attr_value
	spuSaleAttrValueList:[
		{
			"baseSaleAttrId":"1",
			"saleAttrValueName":"黑色"
		}
	]
注意:spu_sale_attr、spu_sale_attr_value有冗余存储项,
需要提前设置好值
image-20210919230017173
⑤ 文档
接口http://api.gmall.com/admin/product/saveSpuInfo
请求参数{
“id”:null,
“spuName”:“小米”,
“description”:“小米”,
“category3Id”:61,
“spuImageList”:[
{
“imgName”:“list.jpg”,
“imgUrl”:“http://47.93.118.241/group1/M00/00/00/L1128V47i9GARYUWAADxtUrmGBA961.jpg”
}
],
“spuSaleAttrList”:[
{
“baseSaleAttrId”:“1”,
“saleAttrName”:“选择颜色”,
“spuSaleAttrValueList”:[
{
“baseSaleAttrId”:“1”,
“saleAttrValueName”:“红色”
},
{
“baseSaleAttrId”:“1”,
“saleAttrValueName”:“白色”
}
]
}
],
“tmId”:4
}
请求方式Post
例:http://api.gmall.com/admin/product/saveSpuInfo
返回值{
“code”:200,
“message”:“成功”,
“data”:null,
“ok”:true
}

请求参数

{
    "id":null,
    "spuName":"小米",
    "description":"小米",
    "category3Id":61,
    "spuImageList":[
        {
            "imgName":"list.jpg",
            "imgUrl":"http://47.93.118.241/group1/M00/00/00/L1128V47i9GARYUWAADxtUrmGBA961.jpg"
        }
    ],
    "spuSaleAttrList":[
        {
            "baseSaleAttrId":"1",
            "saleAttrName":"选择颜色",
            "spuSaleAttrValueList":[
                {
                    "baseSaleAttrId":"1",
                    "saleAttrValueName":"红色"
                },
                {
                    "baseSaleAttrId":"1",
                    "saleAttrValueName":"白色"
                }
            ]
        }
    ],
    "tmId":4
}

返回值

{
    "code":200,
    "message":"成功",
    "data":null,
    "ok":true
}
⑥ 完成 spu 保存的接口
(1)SpuController
@Autowired
SpuInfoService spuInfoService;

@PostMapping("/saveSpuInfo")
public Result saveSpuInfo(@RequestBody SpuInfo spuInfo) {

    boolean b = spuInfoService.bigSaveSpuInfo(spuInfo);

    return Result.ok();
}
(2)SpuInfoService
boolean bigSaveSpuInfo(SpuInfo spuInfo);
(3)SpuInfoServiceImpl
    @Autowired
    SpuInfoMapper spuInfoMapper;

    @Autowired
    SpuImageMapper spuImageMapper;

    @Autowired
    SpuSaleAttrMapper spuSaleAttrMapper;

    @Autowired
    SpuSaleAttrValueMapper spuSaleAttrValueMapper;

	//TODO 前端提交三级分类id有bug
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean bigSaveSpuInfo(SpuInfo spuInfo) {

        //1、保存spu_info
        spuInfoMapper.insert(spuInfo);
        Long id = spuInfo.getId();

        //2、保存spu_image
        List<SpuImage> spuImageList = spuInfo.getSpuImageList();
        if (!CollectionUtils.isEmpty(spuImageList)) {
            for (SpuImage spuImage : spuImageList) {
                spuImage.setSpuId(id);
                spuImageMapper.insert(spuImage);
            }
        }

        //3、保存spu_sale_attr
        List<SpuSaleAttr> spuSaleAttrList = spuInfo.getSpuSaleAttrList();
        if (!CollectionUtils.isEmpty(spuSaleAttrList)) {
            for (SpuSaleAttr spuSaleAttr : spuSaleAttrList) {
                spuSaleAttr.setSpuId(id);
                spuSaleAttrMapper.insert(spuSaleAttr);

                //4、保存spu_sale_attr_value
                List<SpuSaleAttrValue> spuSaleAttrValueList = spuSaleAttr.getSpuSaleAttrValueList();
                if (!CollectionUtils.isEmpty(spuSaleAttrValueList)) {
                    for (SpuSaleAttrValue spuSaleAttrValue : spuSaleAttrValueList) {
                        // 回填 spuId
                        spuSaleAttrValue.setSpuId(id);
                        // 回填 saleAttrName
                        spuSaleAttrValue.setSaleAttrName(spuSaleAttr.getSaleAttrName());
                        spuSaleAttrValueMapper.insert(spuSaleAttrValue);
                    }
                }
            }
        }

        return id > 0;
    }

注意回填

这是前端发送的 JSON

image-20211208194310776

这是数据表的字段

image-20211208194349890

JSON 传递的有些字段没有一一匹配上,这个时候就需要我们手动回填了

1)前端会传递销售属性 id 和销售属性名
image-20210920082302857 image-20210920082432310

spu_sale_attr

image-20210920083626784
2)前端会传递销售属性值的 id 和销售属性值的名
image-20210920083343440

spu_sale_attr_value

image-20210920083805491

测试:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8faewd1i-1639309167480)(Day04 sku与spu接口.assets/image-20210920084010833.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IbxwUHkO-1639309167482)(Day04 sku与spu接口.assets/image-20210920084044506.png)]

数据库中也有了

image-20210920084114887

用 sql 查询一下

image-20210920084200025

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Os5FvdvW-1639309167484)(Day04 sku与spu接口.assets/image-20210920084221700.png)]

查询包含图片的时候

image-20210920084342763 image-20210920084434868
⑦ 商品保存三级分类id有bug

当我们选择一级分类的时候商品的 spu 信息就出来了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yniUeBZf-1639309167485)(Day04 sku与spu接口.assets/image-20210920084541876.png)]

在数据库中保存的三级分类的 id,它不是我们提交的

image-20210920084724900

我们先来做个测试,在图书、音响、电子书刊下的电子书刊下的电子书添加 spu 信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YtMIkBJO-1639309167486)(Day04 sku与spu接口.assets/image-20210920084849482.png)]

这个地方提交的三级分类 id 不对,前端把他写死了

image-20210920085050117

四、sku 的CRUD

1、前端页面分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RHCNLxKv-1639309167487)(Day04 sku与spu接口.assets/image-20210920085338796.png)]

当我们要详细定义信息的时候,点击右侧的添加SKU

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZbpRHcJw-1639309167488)(Day04 sku与spu接口.assets/image-20210920085743779.png)]

image-20211209092326062

① spuSaleAttrList
image-20210920085952115
② spuImageList
image-20210920090054829

我们为 spu 里面定义它详细的 sku 信息时,要我们之前保存的 spu 数据,那么我们就先来准备数据

2、根据spuId获取图片列表

① 文档
接口http://api.gmall.com/admin/product/spuImageList/{spuId}
请求参数spuId:spuId
请求方式Get
例:http://api.gmall.com/admin/product/spuImageList/4
返回值{
“code”:200,
“message”:“成功”,
“data”:[
{
“id”:33,
“spuId”:4,
“imgName”:“list.jpg”,
“imgUrl”:“http://47.93.118.241/group1/M00/00/00/L1128V47i9GARYUWAADxtUrmGBA961.jpg”
}
],
“ok”:true
}
{
    "code":200,
    "message":"成功",
    "data":[
        {
            "id":33,
            "spuId":4,
            "imgName":"list.jpg",
            "imgUrl":"http://47.93.118.241/group1/M00/00/00/L1128V47i9GARYUWAADxtUrmGBA961.jpg"
        }
    ],
    "ok":true
}
② SpuController
/**
 * 根据spuId获取图片列表
 *
 * @param spuId
 * @return
 */
@GetMapping("/spuImageList/{spuId}")
public Result<List<SpuImage>> spuImageList(
        @PathVariable("spuId") Long spuId) {

    QueryWrapper<SpuImage> spuImageQueryWrapper = new QueryWrapper<>();
    spuImageQueryWrapper.eq("spu_id", spuId);

    List<SpuImage> list = spuImageService.list(spuImageQueryWrapper);

    return Result.ok(list);
}

3、根据spuId获取销售属性

① 文档
接口http://api.gmall.com/admin/product/spuSaleAttrList/{spuId}
请求参数spuId:spuId
请求方式Get
例:http://api.gmall.com/admin/product/spuSaleAttrList/4
返回值{
“code”:200,
“message”:“成功”,
“data”:[
{
“id”:8,
“spuId”:4,
“baseSaleAttrId”:1,
“saleAttrName”:“选择颜色”,
“spuSaleAttrValueList”:[
{
“id”:18,
“spuId”:4,
“baseSaleAttrId”:1,
“saleAttrValueName”:“红色”,
“saleAttrName”:“选择颜色”,
“isChecked”:null
},

]
}
],
“ok”:true
}
{
    "code":200,
    "message":"成功",
    "data":[
        {
            "id":8,
            "spuId":4,
            "baseSaleAttrId":1,
            "saleAttrName":"选择颜色",
            "spuSaleAttrValueList":[
                {
                    "id":18,
                    "spuId":4,
                    "baseSaleAttrId":1,
                    "saleAttrValueName":"红色",
                    "saleAttrName":"选择颜色",
                    "isChecked":null
                },]
        }
    ],
    "ok":true
}
② 写 SQL
image-20210920104811718

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KjvUfuwm-1639309167491)(Day04 sku与spu接口.assets/image-20210920105847297.png)]

剔除重复的列

image-20210920112638690
③ SpuController
/**
 * 根据spuId获取商品销售属性列表
 * 每一组销售属性的组合,应该对应一个SKU
 * 颜色:黄、蓝
 * 内存:128,256
 * SKU: 2*2=4:
 * 黄+128  黄+256
 * 蓝+128  蓝+256
 * 我们在录入sku的时候,只需要录入我们的组合
 *
 * @param spuId
 * @return
 */
@GetMapping("/spuSaleAttrList/{spuId}")
public Result<List<SpuSaleAttr>> spuSaleAttrList(@PathVariable("spuId") Long spuId) {

    List<SpuSaleAttr> spuSaleAttrs = spuSaleAttrService.getSpuAttrAndValue(spuId);

    return Result.ok(spuSaleAttrs);
}
④ SpuSaleAttrService
public interface SpuSaleAttrService extends IService<SpuSaleAttr> {
    List<SpuSaleAttr> getSpuAttrAndValue(Long spuId);
}
⑤ SpuSaleAttrServiceImpl
/**
 * 按照spuId查出对应所有的销售属性名和值
 * @param spuId
 * @return
 */
@Override
public List<SpuSaleAttr> getSpuAttrAndValue(Long spuId) {

    return spuSaleAttrMapper.getSpuAttrAndValue(spuId);
}
⑥ SpuSaleAttrMapper
public interface SpuSaleAttrMapper extends BaseMapper<SpuSaleAttr> {

    List<SpuSaleAttr> getSpuAttrAndValue(Long spuId);
}
⑦ SpuSaleAttrMapper.xml

spu_sale_attr_value 的 id 需要起别名,否则 collection 中的 id 就和 resultMap 中 SpuSaleAttr 的 id 冲突了

collection 中 saleAttrName、baseSaleAttrId、spuId 沿用 resultMap 中的 SpuSaleAttr,这是一个小优化

    <resultMap id="SpuSaleAttrResultMap" type="com.atguigu.gmall.model.product.SpuSaleAttr">
        <id property="id" column="id"></id>
        <result property="spuId" column="spu_id"></result>
        <result property="baseSaleAttrId" column="base_sale_attr_id"></result>
        <result property="saleAttrName" column="sale_attr_name"></result>
        <collection property="spuSaleAttrValueList"
                    ofType="com.atguigu.gmall.model.product.SpuSaleAttrValue">
            <id property="id" column="sav_id"></id>
            <result property="saleAttrName" column="sale_attr_name"></result>
            <result property="baseSaleAttrId" column="base_sale_attr_id"></result>
            <result property="spuId" column="spu_id"></result>
            <result property="saleAttrValueName" column="sale_attr_value_name"></result>
        </collection>
    </resultMap>

    <select id="getSpuAttrAndValue" resultMap="SpuSaleAttrResultMap">
        SELECT ssa.*, ssav.id sav_id, ssav.sale_attr_value_name
        FROM spu_sale_attr ssa
                 LEFT JOIN spu_sale_attr_value ssav
                           ON ssa.spu_id = ssav.spu_id AND
                              ssa.base_sale_attr_id = ssav.base_sale_attr_id
        WHERE ssa.spu_id = #{spuId}
    </select>

小复习:

如果 resultMap 中是集合就用 collection 标签,如果是对象就用 association 标签

⑧ 效果
image-20210920114050904 image-20211209095606223

4、添加sku

① 逻辑分析
/**
 *   SPU:录入SPU,平台属性暂时没有参与,录入SKU的时候会有展示.
 *   SKU的录入:
 *       1、sku的详情:sku_info
 *       2、sku的图片:sku_image
 *          内容来自spu_image的一部分
 *       3、sku的属性
 *           3.1)、sku平台属性 : 来源于 base_attr_info  base_attr_value  sku_info
 *                  被记录在 sku_attr_value(他是base_attr_info  base_attr_value  sku_info的中间表)   价格: 0-499
 *           3.2)、sku销售属性 :来源于 spu_sale_attr_value
 *                  被记录在 sku_sale_attr_value (他是 sku_info spu_sale_attr_value的中间表)
 */

sku_info

image-20210920115325462
② sku 的数据库结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ci085CSe-1639309167493)(Day04 sku与spu接口.assets/image-20210920115629300.png)]

③ 数据分析

当一个 sku 录入完成之后准备保存

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hjbl8UKi-1639309167494)(Day04 sku与spu接口.assets/image-20210920120236662.png)]

拿到它要发送的源数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lh4H30IV-1639309167495)(Day04 sku与spu接口.assets/image-20210920120408872.png)]

image-20210920120528919
(1)对比 SkuInfo

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qOAYYckP-1639309167496)(Day04 sku与spu接口.assets/image-20210920121403509.png)]

(2)对比 skuImageList

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EzZamPMu-1639309167497)(Day04 sku与spu接口.assets/image-20210920121608651.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Sza45EnO-1639309167498)(Day04 sku与spu接口.assets/image-20210920121706617.png)]

注意点:这里的 skuId 前端不可能提交,只有 sku 保存了才有自增 id,所以要回填

image-20210920122014688
(3)对比 sku_sale_attr_value

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rGasPziK-1639309167500)(Day04 sku与spu接口.assets/image-20210920122239433.png)]

sale_attr_value_id 前端已经给我们传过来了,但是 sku_id 和 spu_id 没有传,因此我们要回填

(4)对比 spu_sale_attr_value

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8DQNWQTs-1639309167501)(Day04 sku与spu接口.assets/image-20210920122446585.png)]

④ SkuController
@RestController
@RequestMapping("/admin/product")
@Slf4j
public class SkuController {

    @Autowired
    SkuInfoService skuInfoService;

    /**
     *   SPU:录入SPU,平台属性暂时没有参与,录入SKU的时候会有展示.
     *   SKU的录入:
     *       1、sku的详情:sku_info
     *       2、sku的图片:sku_image
     *          内容来自spu_image的一部分
     *       3、sku的属性
     *           3.1)、sku平台属性 : 来源于 base_attr_info  base_attr_value  sku_info
     *                  被记录在 sku_attr_value(他是base_attr_info  base_attr_value  sku_info的中间表)   价格: 0-499
     *           3.2)、sku销售属性 :来源于 spu_sale_attr_value
     *                  被记录在 sku_sale_attr_value (他是 sku_info spu_sale_attr_value的中间表)
     */
    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/saveSkuInfo")
    public Result saveSkuInfo(@RequestBody SkuInfo skuInfo){
        log.info("sku保存信息:{}",skuInfo);

        boolean b = skuInfoService.bigSaveSkuInfo(skuInfo);

        return Result.ok();
    }
}
⑤ SkuInfoService
public interface SkuInfoService extends IService<SkuInfo> {
    
    boolean bigSaveSkuInfo(SkuInfo skuInfo);
}
⑥ SkuInfoServiceImpl
@Service
public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoMapper, SkuInfo> implements SkuInfoService {

    @Autowired
    SkuInfoMapper skuInfoMapper;

    @Autowired
    SkuImageMapper skuImageMapper;

    @Autowired
    SkuAttrValueMappper skuAttrValueMappper;

    @Autowired
    SkuSaleAttrValueMapper skuSaleAttrValueMapper;
    
    /**
     * 保存 SKU 信息
     * SPU:录入SPU,平台属性暂时没有参与,录入SKU的时候会有展示.
     * SKU的录入:
     * 1、sku的详情:sku_info
     * 2、sku的图片:sku_image
     * 内容来自spu_image的一部分
     * 3、sku的属性
     * 3.1)、sku平台属性 : 来源于 base_attr_info  base_attr_value  sku_info
     * 被记录在 sku_attr_value(他是base_attr_info  base_attr_value  sku_info的中间表)   价格: 0-499
     * 3.2)、sku销售属性 :来源于 spu_sale_attr_value
     * 被记录在 sku_sale_attr_value (他是 sku_info spu_sale_attr_value的中间表)
     */
    @Transactional
    @Override
    public boolean bigSaveSkuInfo(SkuInfo skuInfo) {

        //1、保存sku_info基础信息,数据校验
//        if (skuInfo.getPrice() == null){
//            return false;
//        }

        int insert = skuInfoMapper.insert(skuInfo);

        Long skuId = skuInfo.getId();
        //只要操作了数据库,赶紧告诉布隆,我插入了数据


        //2、保存sku图片信息   sku_image
        List<SkuImage> skuImageList = skuInfo.getSkuImageList();
        if (!CollectionUtils.isEmpty(skuImageList)) {
            for (SkuImage skuImage : skuImageList) {
                skuImage.setSkuId(skuId);
                skuImageMapper.insert(skuImage);
            }
        }

        //3、保存sku的平台属性对应的所有值 sku_attr_value
        //attr_id  value_id  sku_id
        // 1          2      sku_id
        List<SkuAttrValue> skuAttrValueList = skuInfo.getSkuAttrValueList();
        if (!CollectionUtils.isEmpty(skuAttrValueList)) {
            for (SkuAttrValue skuAttrValue : skuAttrValueList) {
                skuAttrValue.setSkuId(skuId);
                skuAttrValueMappper.insert(skuAttrValue);
            }
        }

        //4、保存sku的销售属性以及值信息 sku_sale_attr_value
        //  sku_id    spu_id   sale_attr_value_id来源于spu_sale_attr_value的id
        // "saleAttrValueId":"123", spu_sale_attr_value的id
        // "baseSaleAttrId ":"1", base_sale_attr的id
        List<SkuSaleAttrValue> skuSaleAttrValueList = skuInfo.getSkuSaleAttrValueList();
        if (!CollectionUtils.isEmpty(skuSaleAttrValueList)) {
            for (SkuSaleAttrValue skuSaleAttrValue : skuSaleAttrValueList) {
                //注意回填 spuId 和 skuId
                skuSaleAttrValue.setSkuId(skuId);
                skuSaleAttrValue.setSpuId(skuInfo.getSpuId());
                skuSaleAttrValueMapper.insert(skuSaleAttrValue);
            }
        }
        return true;
    }
}
⑦ 效果
image-20210920162717172

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2NhgTcoN-1639309167502)(Day04 sku与spu接口.assets/image-20210920162740128.png)]

⑧ 查询某个 sku 真正的平台属性值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7iQgGbFr-1639309167503)(Day04 sku与spu接口.assets/image-20210920163609406.png)]

⑨ 查询某个 sku 的销售属性值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y8bBupJ3-1639309167504)(Day04 sku与spu接口.assets/image-20210920164345980.png)]

⑩ 查询这个 sku 的所有图片
image-20210920164513690

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uJY80egw-1639309167506)(Day04 sku与spu接口.assets/image-20210920164604971.png)]

5、获取sku分页列表

① 文档
接口http://api.gmall.com/admin/product/list/{page}/{limit}
请求参数page:第几页limit:每页数量
请求方式get
例:http://api.gmall.com/admin/product/list/1/10
返回值{
“code”:200,
“message”:“成功”,
“data”:{
“records”:[
{
“id”:10,
“spuId”:2,
“price”:3999,
“skuName”:“华为 HUAWEI Mate 30 手机”,
“skuDesc”:“主体(mm) 9.2 运营商标志或内容 无”,
“weight”:“0.55”,
“tmId”:2,
“category3Id”:61,
“skuDefaultImg”:“http://192.168.200.128:8080/group1/M00/00/00/wKjIgF42TsmAZc7HAANJjSt4ynk994.jpg”,
“isSale”:0,
“skuImageList”:null,
“skuAttrValueList”:null,
“skuSaleAttrValueList”:null
},

],
“total”:11,
“size”:10,
“current”:1,
“pages”:2
},
“ok”:true
}
{
    "code":200,
    "message":"成功",
    "data":{
        "records":[
            {
                "id":10,
                "spuId":2,
                "price":3999,
                "skuName":"华为 HUAWEI Mate 30 手机",
                "skuDesc":"主体(mm) 9.2 运营商标志或内容 无",
                "weight":"0.55",
                "tmId":2,
                "category3Id":61,
                "skuDefaultImg":"http://192.168.200.128:8080/group1/M00/00/00/wKjIgF42TsmAZc7HAANJjSt4ynk994.jpg",
                "isSale":0,
                "skuImageList":null,
                "skuAttrValueList":null,
                "skuSaleAttrValueList":null
            },],
        "total":11,
        "size":10,
        "current":1,
        "pages":2
    },
    "ok":true
}
② SkuController
/**
 * 获取sku分页列表
 * @param page
 * @param limit
 * @return
 */

//http://api.gmall.com/admin/product/list/{page}/{limit}
@GetMapping("/list/{page}/{limit}")
public Result<Page<SkuInfo>> listSkuInfo(@PathVariable("page") Long page,
                                        @PathVariable("limit") Long limit){

    Page<SkuInfo> skuInfoPage = new Page<>(page, limit);

    Page<SkuInfo> infoPage = skuInfoService.page(skuInfoPage);

    return Result.ok(infoPage);
}
③ 效果
image-20210920165415824

6、上架和下架

① 上架文档
接口http://api.gmall.com/admin/product/onSale/{skuId}
请求参数skuId:skuId
请求方式Get
例:http://api.gmall.com/admin/product/onSale/11
返回值{
“code”:200,
“message”:“成功”,
“data”:null,
“ok”:true
}
② 下架文档
接口http://api.gmall.com/admin/product/cancelSale/{skuId}
请求参数skuId:skuId
请求方式Get
例:http://api.gmall.com/admin/product/cancelSale/11
返回值{
“code”:200,
“message”:“成功”,
“data”:null,
“ok”:true
}
③ SkuController
 /**
  * 上架
  * @param skuId
  * @return
  */
 //http://api.gmall.com/admin/product/onSale/{skuId}
 @GetMapping("/onSale/{skuId}")
 public Result onSale(@PathVariable("skuId") Long skuId){
     boolean b = skuInfoService.onSale(skuId);
     return Result.ok(b);
 }

 /**
  * 下架
  * @param skuId
  * @return
  */
 //http://api.gmall.com/admin/product/cancelSale/{skuId}
@GetMapping("/cancelSale/{skuId}")
public Result cancelSale(@PathVariable("skuId") Long skuId){
    boolean b = skuInfoService.cancelSale(skuId);
    return Result.ok(b);
}
④ SkuInfoService
boolean onSale(Long skuId);

boolean cancelSale(Long skuId);
⑤ SkuInfoServiceImpl
@Override
public boolean onSale(Long skuId) {
    // 1、上架修改数据库
    skuInfoMapper.updateSkuStatus(skuId, 1);
    
    // TODO 2、把商品信息同步到搜索引擎
    return true;
}

@Override
public boolean cancelSale(Long skuId) {
    //1、下架修改数据库
    skuInfoMapper.updateSkuStatus(skuId, 0);

    //TODO 2、把商品信息从搜索引擎移除
    return true;
}
⑥ SkuInfoMapper
void updateSkuStatus(@Param("skuId") Long skuId,
                     @Param("status") int status);
⑦ SkuInfoMapper.xml
<update id="updateSkuStatus">
    UPDATE sku_info SET is_sale = #{status}
    where id = #{skuId}
</update>
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值