[TOC] # 第2章 商品管理 ## 1 商品单位 商品单位就是对商品的所涉及到的单位数据进行维护。 ![image-20241108035149143](images/image-20241108035149143.png) ### 1.1 添加动态菜单 系统管理 -> 菜单管理 -> 新增 -> 主类目 基础数据 ![image-20241108032456538](images/image-20241108032456538.png) 商品单位 ![image-20241108032710014](images/image-20241108032710014.png) ### 1.2 获取商品单位分页列表 #### 1.2.1 ProductUnit ```java 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 ```java 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 list = productUnitService.selectProductUnitList(name); return getDataTable(list); } } ``` #### 1.2.3 IProductUnitService ```java List selectProductUnitList(String name); ``` #### 1.2.4 ProductUnitServiceImpl ```java @Override public List selectProductUnitList(String name) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.like(StringUtils.hasText(name), ProductUnit::getName, name); return baseMapper.selectList(queryWrapper); } ``` ### 1.3 获取商品单位详细信息 #### ProductUnitController ```java @Operation(summary = "获取商品单位详细信息") @GetMapping("/{id}") public AjaxResult getInfo( @Parameter(description = "商品单位id") @PathVariable("id") Long id) { return success(productUnitService.getById(id)); } ``` ### 1.4 新增商品单位 #### ProductUnitController ```java @Operation(summary = "新增商品单位") @PostMapping public AjaxResult add( @Parameter(description = "商品单位") @RequestBody ProductUnit productUnit) { productUnit.setCreateBy(SecurityUtils.getUsername()); return toAjax(productUnitService.save(productUnit)); } ``` ### 1.5 修改商品单位 #### ProductUnitController ```java @Operation(summary = "修改商品单位") @PutMapping public AjaxResult edit( @Parameter(description = "商品单位") @RequestBody ProductUnit productUnit) { productUnit.setUpdateBy(SecurityUtils.getUsername()); return toAjax(productUnitService.updateById(productUnit)); } ``` ### 1.6 删除商品单位 #### ProductUnitController ```java @Operation(summary = "删除商品单位") @DeleteMapping("/{ids}") public AjaxResult remove( @Parameter(description = "商品单位id列表") @PathVariable List ids) { return toAjax(productUnitService.removeBatchByIds(ids)); } ``` ## 2 商品分类 商品分类就是对商品的分类数据进行维护。分类表中的数据通过parent_id自关联。 ![image-20241108041602624](images/image-20241108041602624.png) ### 2.1 添加动态菜单 系统管理 -> 菜单管理 -> 商品管理 -> 新增 -> 菜单 商品分类 ![image-20241108035813552](images/image-20241108035813552.png) ### 2.2 列表树 下级分类采用`懒加载` ![70830820124](images/1708308201244.png) #### 2.2.1 Category **@TableField(exist = false)**:表示数据库中不存在这个列,只在实体类中定义 ```java 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 children;*/ } ``` #### 2.2.2 CategoryController ```java 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 ```java List treeSelect(Long parentId); ``` #### 2.2.4 CategoryServiceImpl ```java @Override public List treeSelect(Long parentId) { //根据parentId查找子节点 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(Category::getParentId, parentId); List categoryList = baseMapper.selectList(queryWrapper); if(!CollectionUtils.isEmpty(categoryList)){ categoryList.forEach(category -> { //查找当前节点是否有子节点 Long count = baseMapper.selectCount( new LambdaQueryWrapper() .eq(Category::getParentId, category.getId()) ); category.setHasChildren(count > 0); }); } return categoryList; } ``` ## 3 分类品牌 分类品牌管理就是将分类的数据和品牌的数据进行关联,分类数据和品牌数据之间的关系是多对多的关系,因此需要单独使用一张数据表来存储:`category_brand`表。 ![image-20241110233049058](images/image-20241110233049058.png) ### 3.1 添加动态菜单 系统管理 -> 菜单管理 -> 商品管理 -> 新增 -> 菜单 分类品牌 ![image-20241110225719634](images/image-20241110225719634.png) ### 3.2 分页列表 #### 3.2.1 CategoryBrand ```java 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 ```java 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 list = categoryBrandService.selectCategoryBrandList(); return getDataTable(list); } } ``` #### 3.2.3 ICategoryBrandService ```java List selectCategoryBrandList(); ``` #### 3.2.4 CategoryBrandServiceImpl ```java @Override public List selectCategoryBrandList() { return baseMapper.selectCategoryBrandList(); } ``` #### 3.2.5 CategoryBrandMapper ```java List selectCategoryBrandList(); ``` #### 3.2.6 CategoryBrandMapper.xml ```xml ``` ### 3.3 添加分类品牌 #### 3.3.1 BrandController 新增分类品牌时,页面中需要展示全部品牌列表: ```java @Operation(summary = "获取全部品牌") @GetMapping("/getBrandAll") public AjaxResult getBrandAll() { return success(brandService.list()); } ``` #### 3.3.2 CategoryBrandController ```java @Operation(summary = "新增分类品牌") @PostMapping public AjaxResult add( @Parameter(description = "分类品牌") @RequestBody CategoryBrand categoryBrand) { categoryBrand.setCreateBy(SecurityUtils.getUsername()); return toAjax(categoryBrandService.insertCategoryBrand(categoryBrand)); } ``` #### 3.3.3 ICategoryBrandService ```java int insertCategoryBrand(CategoryBrand categoryBrand); ``` #### 3.3.4 CategoryBrandServiceImpl ```java @Override public int insertCategoryBrand(CategoryBrand categoryBrand) { LambdaQueryWrapper 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 ```java @Operation(summary = "删除分类品牌") @DeleteMapping("/{ids}") public AjaxResult remove( @Parameter(description = "分类品牌id列表", example = "[1,2]") @PathVariable List 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](images/image-20241111003159888.png) ### 4.1 添加动态菜单 系统管理 -> 菜单管理 -> 商品管理 -> 新增 -> 菜单 商品规格 ![image-20241110235301866](images/image-20241110235301866.png) ### 4.2 分页列表 #### 4.2.1 ProductSpec ```java 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 ```java 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 list = productSpecService.selectProductSpecList(); return getDataTable(list); } } ``` #### 4.2.3 IProductSpecService ```java List selectProductSpecList(); ``` #### 4.2.4 ProductSpecServiceImpl ```java @Override public List selectProductSpecList() { return baseMapper.selectProductSpecList(); } ``` #### 4.2.5 ProductSpecMapper ```java List selectProductSpecList(); ``` #### 4.2.6 ProductSpecMapper.xml ```xml ``` ### 4.3 新增商品规格 #### ProductSpecController ```java @Operation(summary = "新增商品规格") @PostMapping public AjaxResult add( @Parameter(description = "商品规格") @RequestBody ProductSpec productSpec) { productSpec.setCreateBy(SecurityUtils.getUsername()); return toAjax(productSpecService.save(productSpec)); } ``` ![image-20241111004001781](images/image-20241111004001781.png) ![image-20241111003450382](images/image-20241111003450382.png) ### 4.4 删除商品规格 #### ProductSpecController ```java @Operation(summary = "删除商品规格") @DeleteMapping("/{ids}") public AjaxResult remove( @Parameter(description = "商品规格id列表", example = "[1,2]") @PathVariable List 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](images/image-20241111011012211.png) ### 5.3 分页列表 #### 5.3.1 Product ```java 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 ```java 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 list = productService.selectProductList(); return getDataTable(list); } } ``` #### 5.3.3 IProductService ```java List selectProductList(); ``` #### 5.3.4 ProductServiceImpl ```java @Override public List selectProductList() { return baseMapper.selectProductList(); } ``` #### 5.3.5 ProductMapper ```java List selectProductList(); ``` #### 5.3.6 ProductMapper.xml ```xml ``` ### 5.4 新增商品 #### 5.4.1 加载商品单位数据 需求:当添加商品的表单对话框展示出来以后,此时就需要从数据库中查询出来所有的商品单位数据,并将查询到的商品单位数据在商品单元下拉框中 ##### ProductUnitController ```java @Operation(summary = "获取全部单位") @GetMapping("/getUnitAll") public AjaxResult selectProductUnitAll() { return success(productUnitService.list()); } ``` #### 5.4.2 加载品牌数据 当用户选择了三级分类以后,此时需要将三级分类所对应的品牌数据查询出来在品牌下拉框中进行展示 ##### 1 CategoryBrandController ```java @Operation(summary = "根据分类id获取品牌列表") @GetMapping("/brandList/{categoryId}") public AjaxResult selectBrandListByCategoryId( @Parameter(description = "分类id") @PathVariable Long categoryId) { return success(categoryBrandService.selectBrandListByCategoryId(categoryId)); } ``` ##### 2 ICategoryBrandService ```java List selectBrandListByCategoryId(Long categoryId); ``` ##### 3 CategoryBrandServiceImpl ```java @Override public List selectBrandListByCategoryId(Long categoryId) { return baseMapper.selectBrandListByCategoryId(categoryId); } ``` ##### 4 CategoryBrandMapper ```java List selectBrandListByCategoryId(Long categoryId); ``` ##### 5 CategoryBrandMapper.xml ```xml ``` #### 5.4.3 加载商品规格数据 当用户选择了三级分类以后,此时需要将三级分类对应的商品规格数据查询出来 ##### 1 ProductSpecController ```java @Operation(summary = "根据分类id获取商品规格列表") @GetMapping("/productSpecList/{categoryId}") public AjaxResult selectProductSpecListByCategoryId( @Parameter(description = "分类id") @PathVariable Long categoryId) { return success(productSpecService.selectProductSpecListByCategoryId(categoryId)); } ``` ##### 2 IProductSpecService ```java List selectProductSpecListByCategoryId(Long categoryId); ``` ##### 3 ProductSpecServiceImpl ```java @Override public List selectProductSpecListByCategoryId(Long categoryId) { LambdaQueryWrapper 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 添加扩展属性 ```java @Schema(description = "商品sku列表") @TableField(exist = false) private List productSkuList; @Schema(description = "详情图片列表") @TableField(exist = false) private List detailsImageUrlList; ``` ##### 2 ProductSku ```java 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 ```java 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 ```java 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 ```java @Operation(summary = "新增商品") @PostMapping public AjaxResult add( @Parameter(description = "商品") @RequestBody Product product) { return toAjax(productService.insertProduct(product)); } ``` ##### 6 IProductService ```java int insertProduct(Product product); ``` ##### 7 ProductServiceImpl 因为`Spring`的默认的事务规则是遇到运行异常`(RuntimeException)`和程序错误`(Error)`才会回滚。如果想针对检查异常进行事务回滚,可以在`@Transactional`注解里使用 `rollbackFor`属性明确指定异常。 ```java @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 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 ```java @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 ```java void updateStatus(Long id, Integer status); ``` #### 5.5.3 ProductServiceImpl ```java @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() .eq(ProductSku::getProductId, id) .set(ProductSku::getStatus, status)); } ``` ### 5.6 删除商品 #### 5.6.1 ProductController ```java @Operation(summary = "删除商品") @DeleteMapping("/{ids}") public AjaxResult remove( @Parameter(description = "商品id列表") @PathVariable List ids) { return toAjax(productService.deleteProductByIds(ids)); } ``` #### 5.6.2 IProductService ```java int deleteProductByIds(List ids); ``` #### 5.6.3 ProductServiceImpl ```java @Transactional(rollbackFor = Exception.class) @Override public int deleteProductByIds(List ids) { // 删除商品 baseMapper.deleteBatchIds(ids); //查询skuIds(先查询) LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper() .in(ProductSku::getProductId, ids) .select(ProductSku::getId); List productSkuList = productSkuMapper.selectList(queryWrapper); List skuIds = productSkuList.stream().map(ProductSku::getId).collect(Collectors.toList()); // 删除商品sku(再删除) productSkuMapper.delete( new LambdaQueryWrapper() .in(ProductSku::getProductId, ids) ); //删除商品详情 productDetailsMapper.delete( new LambdaQueryWrapper() .in(ProductDetails::getProductId, ids) ); //删除商品库存 return skuStockMapper.delete( new LambdaQueryWrapper() .in(SkuStock::getSkuId, skuIds) ); } ```