尚硅谷_尚品甄选_第2章_商品管理.md 29 KB

[TOC]

第2章 商品管理

1 商品单位

商品单位就是对商品的所涉及到的单位数据进行维护。

image-20241108035149143

1.1 添加动态菜单

系统管理 -> 菜单管理 -> 新增 -> 主类目

基础数据

image-20241108032456538

商品单位

image-20241108032710014

1.2 获取商品单位分页列表

1.2.1 ProductUnit

package com.spzx.product.domain;

@Schema(description = "商品单位")
@Getter
@Setter
@TableName("product_unit")
public class ProductUnit extends BaseEntity {
    private static final long serialVersionUID = 1L;

    @Schema(description = "商品单位名称")
    private String name;
}

1.2.2 ProductUnitController

package com.spzx.product.controller;

@Tag(name = "商品单位")
@RestController
@RequestMapping("/productUnit")
public class ProductUnitController extends BaseController {
    
    @Autowired
    private IProductUnitService productUnitService;

    @Operation(summary = "获取分页列表")
    @GetMapping("/list")
    public TableDataInfo findPage(@Parameter(description = "商品单位名称") String name) {
        startPage();
        List<ProductUnit> list = productUnitService.selectProductUnitList(name);
        return getDataTable(list);
    }
}

1.2.3 IProductUnitService

List<ProductUnit> selectProductUnitList(String name);

1.2.4 ProductUnitServiceImpl

@Override
public List<ProductUnit> selectProductUnitList(String name) {
    LambdaQueryWrapper<ProductUnit> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.like(StringUtils.hasText(name), ProductUnit::getName, name);
    return baseMapper.selectList(queryWrapper);
}

1.3 获取商品单位详细信息

ProductUnitController

@Operation(summary = "获取商品单位详细信息")
@GetMapping("/{id}")
public AjaxResult getInfo(
    @Parameter(description = "商品单位id") 
    @PathVariable("id") Long id) {
    return success(productUnitService.getById(id));
}

1.4 新增商品单位

ProductUnitController

@Operation(summary = "新增商品单位")
@PostMapping
public AjaxResult add(
    @Parameter(description = "商品单位") 
    @RequestBody ProductUnit productUnit) {
    productUnit.setCreateBy(SecurityUtils.getUsername());
    return toAjax(productUnitService.save(productUnit));
}

1.5 修改商品单位

ProductUnitController

@Operation(summary = "修改商品单位")
@PutMapping
public AjaxResult edit(
    @Parameter(description = "商品单位") 
    @RequestBody ProductUnit productUnit) {
    productUnit.setUpdateBy(SecurityUtils.getUsername());
    return toAjax(productUnitService.updateById(productUnit));
}

1.6 删除商品单位

ProductUnitController

@Operation(summary = "删除商品单位")
@DeleteMapping("/{ids}")
public AjaxResult remove(
    @Parameter(description = "商品单位id列表") 
    @PathVariable List<Long> ids) {
    return toAjax(productUnitService.removeBatchByIds(ids));
}

2 商品分类

商品分类就是对商品的分类数据进行维护。分类表中的数据通过parent_id自关联。

image-20241108041602624

2.1 添加动态菜单

系统管理 -> 菜单管理 -> 商品管理 -> 新增 -> 菜单

商品分类

image-20241108035813552

2.2 列表树

下级分类采用懒加载

70830820124

2.2.1 Category

@TableField(exist = false):表示数据库中不存在这个列,只在实体类中定义

package com.spzx.product.domain;

@Schema(description = "商品分类")
@Getter
@Setter
@TableName("category")
public class Category extends BaseEntity
{
    private static final long serialVersionUID = 1L;

    @Schema(description = "分类名称")
    private String name;

    @Schema(description = "图标地址")
    private String imageUrl;

    @Schema(description = "上级分类id")
    private Long parentId;

    @Schema(description = "是否显示[0-不显示,1显示]")
    private Integer status;

    @Schema(description = "排序")
    private Long orderNum;

    @Schema(description = "是否有子节点")
    @TableField(exist = false)
    private Boolean hasChildren;

    /*@Schema(description = "子节点列表")
    @TableField(exist = false)
    private List<Category> children;*/
}

2.2.2 CategoryController

package com.spzx.product.controller;

@Tag(name = "商品分类")
@RestController
@RequestMapping("/category")
public class CategoryController extends BaseController {

    @Autowired
    private ICategoryService categoryService;

    @Operation(summary = "获取分类下拉树列表")
    @GetMapping("/treeSelect/{id}")
    public AjaxResult treeSelect(@Parameter(description = "分类id") @PathVariable Long id) {
        return success(categoryService.treeSelect(id));
    }
}

2.2.3 ICategoryService

List<Category> treeSelect(Long parentId);

2.2.4 CategoryServiceImpl

@Override
public List<Category> treeSelect(Long parentId) {
    //根据parentId查找子节点
    LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(Category::getParentId, parentId);
    List<Category> categoryList = baseMapper.selectList(queryWrapper);

    if(!CollectionUtils.isEmpty(categoryList)){
        categoryList.forEach(category -> {
            //查找当前节点是否有子节点
            Long count = baseMapper.selectCount(
                new LambdaQueryWrapper<Category>()
                .eq(Category::getParentId, category.getId())
            );
            category.setHasChildren(count > 0);
        });
    }
    return categoryList;
}

3 分类品牌

分类品牌管理就是将分类的数据和品牌的数据进行关联,分类数据和品牌数据之间的关系是多对多的关系,因此需要单独使用一张数据表来存储:category_brand表。

image-20241110233049058

3.1 添加动态菜单

系统管理 -> 菜单管理 -> 商品管理 -> 新增 -> 菜单

分类品牌

image-20241110225719634

3.2 分页列表

3.2.1 CategoryBrand

package com.spzx.product.domain;

@Schema(description = "分类品牌")
@Getter
@Setter
@TableName("category_brand")
public class CategoryBrand extends BaseEntity {

    private static final long serialVersionUID = 1L;

    @Schema(description = "品牌ID")
    @NotNull(message = "品牌ID不能为空")
    private Long brandId;

    @Schema(description = "分类ID")
    private Long categoryId;

    @Schema(description = "分类名称")
    @TableField(exist = false)
    private String categoryName;

    @Schema(description = "品牌名称")
    @TableField(exist = false)
    private String brandName;

    @Schema(description = "品牌图标")
    @TableField(exist = false)
    private String logo;
}

3.2.2 CategoryBrandController

package com.spzx.product.controller;

@Tag(name = "分类品牌")
@RestController
@RequestMapping("/categoryBrand")
public class CategoryBrandController extends BaseController {

    @Autowired
    private ICategoryBrandService categoryBrandService;

    @Operation(summary = "查询分类品牌列表")
    @GetMapping("/list")
    public TableDataInfo list() {
        startPage();
        List<CategoryBrand> list = categoryBrandService.selectCategoryBrandList();
        return getDataTable(list);
    }
}

3.2.3 ICategoryBrandService

List<CategoryBrand> selectCategoryBrandList();

3.2.4 CategoryBrandServiceImpl

@Override
public List<CategoryBrand> selectCategoryBrandList() {
    return baseMapper.selectCategoryBrandList();
}

3.2.5 CategoryBrandMapper

List<CategoryBrand> selectCategoryBrandList();

3.2.6 CategoryBrandMapper.xml

<select id="selectCategoryBrandList" resultType="com.spzx.product.domain.CategoryBrand">
    SELECT
    	cb.id,
    	cb.brand_id,
        cb.category_id,
    	cb.create_time,
    	b.name as brandName,
    	b.logo,
    	c.name as categoryName
    FROM category_brand cb
    	INNER JOIN category c ON cb.category_id = c.id
    	INNER JOIN brand b ON cb.brand_id = b.id
    WHERE c.del_flag = '0' AND b.del_flag = '0' AND cb.del_flag = '0'
</select>

3.3 添加分类品牌

3.3.1 BrandController

新增分类品牌时,页面中需要展示全部品牌列表:

@Operation(summary = "获取全部品牌")
@GetMapping("/getBrandAll")
public AjaxResult getBrandAll() {
    return success(brandService.list());
}

3.3.2 CategoryBrandController

@Operation(summary = "新增分类品牌")
@PostMapping
public AjaxResult add(
    @Parameter(description = "分类品牌") 
    @RequestBody CategoryBrand categoryBrand) {
    categoryBrand.setCreateBy(SecurityUtils.getUsername());
    return toAjax(categoryBrandService.insertCategoryBrand(categoryBrand));
}

3.3.3 ICategoryBrandService

int insertCategoryBrand(CategoryBrand categoryBrand);

3.3.4 CategoryBrandServiceImpl

@Override
public int insertCategoryBrand(CategoryBrand categoryBrand) {
    LambdaQueryWrapper<CategoryBrand> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper
        .eq(CategoryBrand::getCategoryId, categoryBrand.getCategoryId())
        .eq(CategoryBrand::getBrandId, categoryBrand.getBrandId());
    long count = baseMapper.selectCount(queryWrapper);
    if(count > 0) {
        throw new ServiceException("该分类下已有该品牌");
    }
    return baseMapper.insert(categoryBrand);
}

3.4 删除分类品牌

CategoryBrandController

@Operation(summary = "删除分类品牌")
@DeleteMapping("/{ids}")
public AjaxResult remove(
    @Parameter(description = "分类品牌id列表", example = "[1,2]") 
    @PathVariable List<Long> ids) {
    return toAjax(categoryBrandService.removeBatchByIds(ids));
}

4 商品规格

商品规格指的是商品属性、型号、尺寸、颜色等具体描述商品特点和属性的标准化信息。

以T恤衫为例,它的规格可能包括以下几个方面:

1、颜色:白色、黑色

2、尺码:S、M、L、XL

以手机为例,它的规格可能包括以下几个方面:

1、屏幕尺寸:5.5寸 、6.7寸

2、分辨率:1920x1080、2960x1440、2532x1170

3、运行内存:6GB、8GB、12GB

4、存储容量:64GB、128GB、256GB

image-20241111003159888

4.1 添加动态菜单

系统管理 -> 菜单管理 -> 商品管理 -> 新增 -> 菜单

商品规格

image-20241110235301866

4.2 分页列表

4.2.1 ProductSpec

package com.spzx.product.domain;

@Schema(description = "商品规格")
@Getter
@Setter
@TableName("product_spec")
public class ProductSpec extends BaseEntity {

    private static final long serialVersionUID = 1L;

    @Schema(description = "分类ID")
    private Long categoryId;

    @Schema(description = "规格名称")
    private String specName;

    @Schema(description = "规格值")
    private String specValue;
    
    @Schema(description = "分类名称")
    @TableField(exist = false)
    private String categoryName;
}

4.2.2 ProductSpecController

package com.spzx.product.controller;

@Tag(name = "商品规格")
@RestController
@RequestMapping("/productSpec")
public class ProductSpecController extends BaseController {
    
    @Autowired
    private IProductSpecService productSpecService;

    @Operation(summary = "查询商品规格列表")
    @GetMapping("/list")
    public TableDataInfo list() {
        startPage();
        List<ProductSpec> list = productSpecService.selectProductSpecList();
        return getDataTable(list);
    }
}

4.2.3 IProductSpecService

List<ProductSpec> selectProductSpecList();

4.2.4 ProductSpecServiceImpl

@Override
public List<ProductSpec> selectProductSpecList() {
    return baseMapper.selectProductSpecList();
}

4.2.5 ProductSpecMapper

List<ProductSpec> selectProductSpecList();

4.2.6 ProductSpecMapper.xml

<select id="selectProductSpecList" resultType="com.spzx.product.domain.ProductSpec">
    SELECT
    	ps.id,
    	ps.spec_name,
    	ps.spec_value,
    	ps.category_id,
    	c.name categoryName,
    	ps.create_time
    FROM product_spec ps
    	INNER JOIN category c ON ps.category_id = c.id
    WHERE ps.del_flag = '0' AND c.del_flag = '0'
</select>

4.3 新增商品规格

ProductSpecController

@Operation(summary = "新增商品规格")
@PostMapping
public AjaxResult add(
    @Parameter(description = "商品规格") 
    @RequestBody ProductSpec productSpec) {
    productSpec.setCreateBy(SecurityUtils.getUsername());
    return toAjax(productSpecService.save(productSpec));
}

image-20241111004001781

image-20241111003450382

4.4 删除商品规格

ProductSpecController

@Operation(summary = "删除商品规格")
@DeleteMapping("/{ids}")
public AjaxResult remove(
    @Parameter(description = "商品规格id列表", example = "[1,2]") 
    @PathVariable List<Long> ids) {
    return toAjax(productSpecService.removeBatchByIds(ids));
}

5 商品管理

商品管理就是对电商项目中所涉及到的商品数据进行维护。

数据库表:

  • 商品SPU表 product

  • 商品SKU表 product_sku

  • 商品详情表 product_details

  • 商品库存表 sku_stock

5.1 核心概念

5.1.1 SPU

SPU = Standard Product Unit (标准化产品单元),泛指一类商品,这种商品具有相同的属性。

5.1.2 SKU

SKU = stock keeping unit(库存量单位),SKU即库存进出计量的单位。也就是说一款商品,可以根据SKU来确定具体的货物存量。

以手机为例,假设有一款名为 "XPhone" 的手机品牌,它推出了一款型号为 "X10" 的手机。这款手机一共有以下几种属性:

1、颜色:黑色、白色、金色

2、存储容量:64GB、128GB

3、内存大小:4GB、6GB

那么,“X10” 这款手机就是这个商品的 SPU,根据不同的属性组合,可以形成多个不同的 SKU。如下所示:

SPU SKU 颜色 存储容量 内存大小
X10 SKU1 黑色 64GB 4GB
X10 SKU2 白色 64GB 4GB
X10 SKU3 金色 64GB 4GB
X10 SKU4 黑色 128GB 4GB
X10 SKU5 白色 128GB 4GB
X10 SKU6 金色 128GB 4GB
X10 SKU7 黑色 64GB 6GB
X10 SKU8 白色 64GB 6GB
X10 SKU9 金色 64GB 6GB
X10 SKU10 黑色 128GB 6GB
X10 SKU11 白色 128GB 6GB
X10 SKU12 金色 128GB 6GB

再以衣服为例,假设有一家服装网店推出了一款名为 "A衬衫" 的衣服。这款衣服一共有以下几种属性:

1、尺寸:S、M、L、XL

2、颜色:白色、黑色、灰色、蓝色

那么,“A衬衫” 这款衣服就是这个商品的 SPU,根据不同的属性组合,可以形成多个不同的 SKU。如下所示:

SPU SKU 尺寸 颜色
A衬衫 SKU1 S 白色
A衬衫 SKU2 M 白色
A衬衫 SKU3 L 白色
A衬衫 SKU4 XL 白色
A衬衫 SKU5 S 黑色
A衬衫 SKU6 M 黑色
A衬衫 SKU7 L 黑色
A衬衫 SKU8 XL 黑色
A衬衫 SKU9 S 灰色
A衬衫 SKU10 M 灰色
A衬衫 SKU11 L 灰色
A衬衫 SKU12 XL 灰色
A衬衫 SKU13 S 蓝色
A衬衫 SKU14 M 蓝色
A衬衫 SKU15 L 蓝色
A衬衫 SKU16 XL 蓝色

5.2 添加动态菜单

系统管理 -> 菜单管理 -> 商品管理 -> 新增 -> 菜单

商品列表

image-20241111011012211

5.3 分页列表

5.3.1 Product

package com.spzx.product.domain;

@Schema(description = "商品SPU")
@Getter
@Setter
@TableName("product")
public class Product extends BaseEntity {

    private static final long serialVersionUID = 1L;

    @Schema(description = "商品名称")
    private String name;

    @Schema(description = "品牌ID")
    private Long brandId;

    @Schema(description = "一级分类id")
    private Long category1Id;

    @Schema(description = "二级分类id")
    private Long category2Id;

    @Schema(description = "三级分类id")
    private Long category3Id;

    @Schema(description = "计量单位")
    private String unitName;

    @Schema(description = "轮播图")
    private String sliderUrls;

    @Schema(description = "商品规格json")
    private String specValue;

    @Schema(description = "状态:0-初始值,1-上架,-1-自主下架")
    private Integer status;

    @Schema(description = "品牌")
    @TableField(exist = false)
    private String brandName;
    
    @Schema(description = "一级分类")
    @TableField(exist = false)
    private String category1Name;
 
    @Schema(description = "二级分类")
    @TableField(exist = false)
    private String category2Name;

    @Schema(description = "三级分类")
    @TableField(exist = false)
    private String category3Name;
}

5.3.2 ProductController

package com.spzx.product.controller;

@Tag(name = "商品")
@RestController
@RequestMapping("/product")
public class ProductController extends BaseController {

    @Autowired
    private IProductService productService;

    @Operation(summary = "查询商品列表")
    @GetMapping("/list")
    public TableDataInfo list() {
        startPage();
        List<Product> list = productService.selectProductList();
        return getDataTable(list);
    }
}

5.3.3 IProductService

List<Product> selectProductList();

5.3.4 ProductServiceImpl

@Override
public List<Product> selectProductList() {
    return baseMapper.selectProductList();
}

5.3.5 ProductMapper

List<Product> selectProductList();

5.3.6 ProductMapper.xml

<select id="selectProductList" resultType="com.spzx.product.domain.Product">
    select
    	p.id,
    	p.name,
    	p.unit_name,
    	p.slider_urls,
    	p.status,
    	b.name brandName ,
    	c1.name category1Name ,
    	c2.name category2Name ,
    	c3.name category3Name
    from product p
    	LEFT JOIN brand b on b.id = p.brand_id and b.del_flag = 0
    	LEFT JOIN category c1 on c1.id = p.category1_id and c1.del_flag = '0'
    	LEFT JOIN category c2 on c2.id = p.category2_id and c2.del_flag = '0'
    	LEFT JOIN category c3 on c3.id = p.category2_id and c3.del_flag = '0'
    WHERE p.del_flag = '0'
</select>

5.4 新增商品

5.4.1 加载商品单位数据

需求:当添加商品的表单对话框展示出来以后,此时就需要从数据库中查询出来所有的商品单位数据,并将查询到的商品单位数据在商品单元下拉框中

ProductUnitController
@Operation(summary = "获取全部单位")
@GetMapping("/getUnitAll")
public AjaxResult selectProductUnitAll() {
    return success(productUnitService.list());
}

5.4.2 加载品牌数据

当用户选择了三级分类以后,此时需要将三级分类所对应的品牌数据查询出来在品牌下拉框中进行展示

1 CategoryBrandController
@Operation(summary = "根据分类id获取品牌列表")
@GetMapping("/brandList/{categoryId}")
public AjaxResult selectBrandListByCategoryId(
    @Parameter(description = "分类id") 
    @PathVariable Long categoryId) {
    return success(categoryBrandService.selectBrandListByCategoryId(categoryId));
}
2 ICategoryBrandService
List<Brand> selectBrandListByCategoryId(Long categoryId);
3 CategoryBrandServiceImpl
@Override
public List<Brand> selectBrandListByCategoryId(Long categoryId) {
    return baseMapper.selectBrandListByCategoryId(categoryId);
}
4 CategoryBrandMapper
List<Brand> selectBrandListByCategoryId(Long categoryId);
5 CategoryBrandMapper.xml
<select id="selectBrandListByCategoryId" resultType="com.spzx.product.domain.Brand">
    SELECT b.id,
      	b.name,
      	b.logo
    FROM brand b
    	INNER JOIN category_brand cb ON b.id = cb.brand_id
    WHERE cb.category_id = #{categoryId}
    	AND b.del_flag = '0'
    	AND cb.del_flag = '0'
</select>

5.4.3 加载商品规格数据

当用户选择了三级分类以后,此时需要将三级分类对应的商品规格数据查询出来

1 ProductSpecController
@Operation(summary = "根据分类id获取商品规格列表")
@GetMapping("/productSpecList/{categoryId}")
public AjaxResult selectProductSpecListByCategoryId(
    @Parameter(description = "分类id") 
    @PathVariable Long categoryId) {
    return success(productSpecService.selectProductSpecListByCategoryId(categoryId));
}
2 IProductSpecService
List<ProductSpec> selectProductSpecListByCategoryId(Long categoryId);
3 ProductSpecServiceImpl
@Override
public List<ProductSpec> selectProductSpecListByCategoryId(Long categoryId) {
    LambdaQueryWrapper<ProductSpec> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(ProductSpec::getCategoryId, categoryId);
    return baseMapper.selectList(queryWrapper);
}

5.4.4 保存商品数据接口

思路分析:

1、前端提交过来的数据,包含了SPU的基本数据,SKU的列表数据,商品详情数据,商品库存数据

2、保存数据的时候需要操作四张表:product、product_sku、product_detail、sku_stock

1 Product

添加扩展属性

@Schema(description = "商品sku列表")
@TableField(exist = false)
private List<ProductSku> productSkuList;

@Schema(description = "详情图片列表")
@TableField(exist = false)
private List<String> detailsImageUrlList;
2 ProductSku
package com.spzx.product.domain;

@Schema(description = "商品sku")
@Getter
@Setter
@TableName("product_sku")
public class ProductSku extends BaseEntity {

    private static final long serialVersionUID = 1L;

    @Schema(description = "商品编号")
    private String skuCode;

    @Schema(description = "sku名称")
    private String skuName;

    @Schema(description = "商品ID")
    private Long productId;

    @Schema(description = "缩略图路径")
    private String thumbImg;

    @Schema(description = "售价")
    private BigDecimal salePrice;

    @Schema(description = "市场价")
    private BigDecimal marketPrice;

    @Schema(description = "成本价")
    private BigDecimal costPrice;

    @Schema(description = "sku规格信息json")
    private String skuSpec;

    @Schema(description = "重量")
    private BigDecimal weight;

    @Schema(description = "体积")
    private BigDecimal volume;

    @Schema(description = "线上状态:0-初始值,1-上架,-1-自主下架")
    private Integer status;

    // 扩展的属性
    @Schema(description = "sku库存")
    @TableField(exist = false)
    private Integer stockNum;
}
3 ProductDetails
package com.spzx.product.domain;

@Schema(description = "商品详情")
@Getter
@Setter
@TableName("product_details")
public class ProductDetails extends BaseEntity {

    private static final long serialVersionUID = 1L;

    @Schema(description = "商品id")
    private Long productId;

    @Schema(description = "详情图片地址")
    private String imageUrls;
}
4 SkuStock
package com.spzx.product.domain;

@Schema(description = "商品sku库存")
@Getter
@Setter
@TableName("sku_stock")
public class SkuStock extends BaseEntity {

    private static final long serialVersionUID = 1L;

    @Schema(description = "skuID")
    private Long skuId;

    @Schema(description = "总库存数")
    private Integer totalNum;

    @Schema(description = "锁定库存数")
    private Integer lockNum;

    @Schema(description = "可用库存数")
    private Integer availableNum;
    
    @Schema(description = "销量")
    private Integer saleNum;

    @Schema(description = "线上状态:0-初始值,1-上架,-1-自主下架")
    private Integer status;
}
5 ProductController
@Operation(summary = "新增商品")
@PostMapping
public AjaxResult add(
    @Parameter(description = "商品")
    @RequestBody Product product) {
    return toAjax(productService.insertProduct(product));
}
6 IProductService
int insertProduct(Product product);
7 ProductServiceImpl

因为Spring的默认的事务规则是遇到运行异常(RuntimeException)和程序错误(Error)才会回滚。如果想针对检查异常进行事务回滚,可以在@Transactional注解里使用 rollbackFor属性明确指定异常。

@Autowired
private ProductSkuMapper productSkuMapper;

@Autowired
private ProductDetailsMapper productDetailsMapper;

@Autowired
private SkuStockMapper skuStockMapper;

@Transactional(rollbackFor = Exception.class)
@Override
public int insertProduct(Product product) {
    baseMapper.insert(product);

    List<ProductSku> productSkuList = product.getProductSkuList();
    for (int i = 0, size = productSkuList.size(); i < size; i++) {
        ProductSku productSku = productSkuList.get(i);
        productSku.setSkuCode(product.getId() + "_" + i);
        productSku.setProductId(product.getId());
        String skuName = product.getName() + " " + productSku.getSkuSpec();
        productSku.setSkuName(skuName);
        productSku.setStatus(0);
        productSkuMapper.insert(productSku);

        //添加商品库存
        SkuStock skuStock = new SkuStock();
        skuStock.setSkuId(productSku.getId());
        skuStock.setTotalNum(productSku.getStockNum());
        skuStock.setLockNum(0);
        skuStock.setAvailableNum(productSku.getStockNum());
        skuStock.setSaleNum(0);
        skuStockMapper.insert(skuStock);
    }

    ProductDetails productDetails = new ProductDetails();
    productDetails.setProductId(product.getId());
    productDetails.setImageUrls(String.join(",", product.getDetailsImageUrlList()));
    productDetailsMapper.insert(productDetails);

    return 1;
}

5.5 更新上下架状态

5.5.1 ProductController

@Operation(summary = "更新上下架状态")
@GetMapping("/updateStatus/{id}/{status}")
public AjaxResult updateStatus(
    @Parameter(description = "商品id") @PathVariable Long id,
    @Parameter(description = "状态") @PathVariable Integer status) {
    
    if(status != 1 && status != -1){
        //throw new ServiceException("非法参数");
        return AjaxResult.error("非法参数");
    }
    
    productService.updateStatus(id, status);
    return success();
}

5.5.2 IProductService

void updateStatus(Long id, Integer status);

5.5.3 ProductServiceImpl

@Transactional(rollbackFor = Exception.class)
@Override
public void updateStatus(Long id, Integer status) {
    Product product = new Product();
    product.setId(id);
    product.setStatus(status);
    baseMapper.updateById(product);
    
    //更新sku的status
    productSkuMapper.update(
        null,
        new LambdaUpdateWrapper<ProductSku>()
        .eq(ProductSku::getProductId, id)
        .set(ProductSku::getStatus, status));
}

5.6 删除商品

5.6.1 ProductController

@Operation(summary = "删除商品")
@DeleteMapping("/{ids}")
public AjaxResult remove(
    @Parameter(description = "商品id列表") 
    @PathVariable List<Long> ids) {
    return toAjax(productService.deleteProductByIds(ids));
}

5.6.2 IProductService

int deleteProductByIds(List<Long> ids);

5.6.3 ProductServiceImpl

@Transactional(rollbackFor = Exception.class)
@Override
public int deleteProductByIds(List<Long> ids) {

    // 删除商品
    baseMapper.deleteBatchIds(ids);

    //查询skuIds(先查询)
    LambdaQueryWrapper<ProductSku> queryWrapper = new LambdaQueryWrapper<ProductSku>()
        .in(ProductSku::getProductId, ids)
        .select(ProductSku::getId);
    List<ProductSku> productSkuList = productSkuMapper.selectList(queryWrapper);
    List<Long> skuIds = productSkuList.stream().map(ProductSku::getId).collect(Collectors.toList());

    // 删除商品sku(再删除)
    productSkuMapper.delete(
        new LambdaQueryWrapper<ProductSku>()
        .in(ProductSku::getProductId, ids)
    );

    //删除商品详情
    productDetailsMapper.delete(
        new LambdaQueryWrapper<ProductDetails>()
        .in(ProductDetails::getProductId, ids)
    );

    //删除商品库存
    return skuStockMapper.delete(
        new LambdaQueryWrapper<SkuStock>()
        .in(SkuStock::getSkuId, skuIds)
    );
}