Day04 sku与spu接口
一、答疑
1、Docker
① 如果在创建容器的时候,没有进行端口映射和卷的挂载,后来又想添加,我们如何做呢?
docker update 不行
把docker容器的核心内容docker cp出来,再启动一个新容器挂载
② 如何创建nacos的容器镜像呢,和Sentinel完全不一样?
FROM alpine
COPY ./nacos /app/nacosENTRYPOINT [“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;
}
效果
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)一对一
(2)一对多
(3)多对多
获取品牌属性
接口 | 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);
}
4、spu保存
① 分析传递的数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wooXlpco-1639309167470)(Day04 sku与spu接口.assets/image-20210919204946599.png)]
当我们点击保存的时候
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V3tITNRo-1639309167475)(Day04 sku与spu接口.assets/image-20210919205113070.png)]
对照着 spu_info 看
对照着 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的销售属性
(2)查询某个 spu 的销售属性以及值的详情
④ 分析流程和步骤
保存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有冗余存储项,
需要提前设置好值
⑤ 文档
接口 | 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
这是数据表的字段
JSON 传递的有些字段没有一一匹配上,这个时候就需要我们手动回填了
1)前端会传递销售属性 id 和销售属性名
spu_sale_attr
2)前端会传递销售属性值的 id 和销售属性值的名
spu_sale_attr_value
测试:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8faewd1i-1639309167480)(Day04 sku与spu接口.assets/image-20210920084010833.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IbxwUHkO-1639309167482)(Day04 sku与spu接口.assets/image-20210920084044506.png)]
数据库中也有了
用 sql 查询一下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Os5FvdvW-1639309167484)(Day04 sku与spu接口.assets/image-20210920084221700.png)]
查询包含图片的时候
⑦ 商品保存三级分类id有bug
当我们选择一级分类的时候商品的 spu 信息就出来了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yniUeBZf-1639309167485)(Day04 sku与spu接口.assets/image-20210920084541876.png)]
在数据库中保存的三级分类的 id,它不是我们提交的
我们先来做个测试,在图书、音响、电子书刊下的电子书刊下的电子书添加 spu 信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YtMIkBJO-1639309167486)(Day04 sku与spu接口.assets/image-20210920084849482.png)]
这个地方提交的三级分类 id 不对,前端把他写死了
四、sku 的CRUD
1、前端页面分析
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RHCNLxKv-1639309167487)(Day04 sku与spu接口.assets/image-20210920085338796.png)]
当我们要详细定义信息的时候,点击右侧的添加SKU
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZbpRHcJw-1639309167488)(Day04 sku与spu接口.assets/image-20210920085743779.png)]
① spuSaleAttrList
② spuImageList
我们为 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
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KjvUfuwm-1639309167491)(Day04 sku与spu接口.assets/image-20210920105847297.png)]
剔除重复的列
③ 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 标签
⑧ 效果
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
② 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)]
(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,所以要回填
(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;
}
}
⑦ 效果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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 的所有图片
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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);
}
③ 效果
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>