Browse Source

mall: code review 商品模块的代码

YunaiV 2 years ago
parent
commit
f4324a22f2
27 changed files with 226 additions and 214 deletions
  1. 16 17
      yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java
  2. 0 10
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/ProductBrandController.java
  3. 5 5
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/category/ProductCategoryController.java
  4. 3 3
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyController.java
  5. 30 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/ProductPropertyAndValueRespVO.java
  6. 3 4
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/ProductPropertyBaseVO.java
  7. 0 23
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/ProductPropertyRespVO.java
  8. 1 2
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuCreateOrUpdateReqVO.java
  9. 2 2
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java
  10. 2 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/SpuRespVO.java
  11. 1 1
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/category/AppCategoryController.java
  12. 3 3
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/property/ProductPropertyConvert.java
  13. 1 1
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/brand/ProductBrandMapper.java
  14. 4 6
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java
  15. 3 2
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/brand/ProductBrandService.java
  16. 9 8
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/brand/ProductBrandServiceImpl.java
  17. 10 9
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryService.java
  18. 28 20
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImpl.java
  19. 13 9
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyService.java
  20. 11 11
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java
  21. 5 4
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java
  22. 46 44
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java
  23. 2 2
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java
  24. 15 15
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java
  25. 3 3
      yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/brand/ProductBrandServiceImplTest.java
  26. 7 7
      yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImplTest.java
  27. 3 3
      yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java

+ 16 - 17
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java

@@ -10,30 +10,29 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
 public interface ErrorCodeConstants {
 
     // ========== 商品分类相关 1008001000 ============
-    ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1008001000, "商品分类不存在");
-    ErrorCode PRODUCT_CATEGORY_PARENT_NOT_EXISTS = new ErrorCode(1008001001, "父分类不存在");
-    ErrorCode PRODUCT_CATEGORY_PARENT_NOT_FIRST_LEVEL = new ErrorCode(1008001002, "父分类不能是二级分类");
-    ErrorCode PRODUCT_CATEGORY_EXISTS_CHILDREN = new ErrorCode(1008001003, "存在子分类,无法删除");
-    ErrorCode PRODUCT_CATEGORY_DISABLED = new ErrorCode(1008001004, "商品分类({})已禁用,无法使用");
-    ErrorCode PRODUCT_CATEGORY_LEVEL = new ErrorCode(1008001005, "商品需挂在三级分类下");
+    ErrorCode CATEGORY_NOT_EXISTS = new ErrorCode(1008001000, "商品分类不存在");
+    ErrorCode CATEGORY_PARENT_NOT_EXISTS = new ErrorCode(1008001001, "父分类不存在");
+    ErrorCode CATEGORY_PARENT_NOT_FIRST_LEVEL = new ErrorCode(1008001002, "父分类不能是二级分类");
+    ErrorCode CATEGORY_EXISTS_CHILDREN = new ErrorCode(1008001003, "存在子分类,无法删除");
+    ErrorCode CATEGORY_DISABLED = new ErrorCode(1008001004, "商品分类({})已禁用,无法使用");
+    ErrorCode CATEGORY_LEVEL_ERROR = new ErrorCode(1008001005, "商品分类不正确,原因:必须使用第三级的商品分类下");
 
-    // ========== 品牌相关编号 1008002000 ==========
-    ErrorCode PRODUCT_BRAND_NOT_EXISTS = new ErrorCode(1008002000, "品牌不存在");
+    // ========== 商品品牌相关编号 1008002000 ==========
+    ErrorCode BRAND_NOT_EXISTS = new ErrorCode(1008002000, "品牌不存在");
 
-    // ========== 规格名称 1008003000 ==========
+    // ========== 商品规格名称 1008003000 ==========
     ErrorCode PROPERTY_NOT_EXISTS = new ErrorCode(1008003000, "规格名称不存在");
 
     // ========== 规格值 1008004000 ==========
     ErrorCode PROPERTY_VALUE_NOT_EXISTS = new ErrorCode(1008004000, "规格值不存在");
 
-    // ========== 商品spu 1008005000 ==========
-    ErrorCode SPU_NOT_EXISTS = new ErrorCode(1008005000, "商品spu不存在");
+    // ========== 商品 SPU 1008005000 ==========
+    ErrorCode SPU_NOT_EXISTS = new ErrorCode(1008005000, "商品 SPU 不存在");
 
-    // ========== 商品sku 1008006000 ==========
-    ErrorCode SKU_NOT_EXISTS = new ErrorCode(1008006000, "商品sku不存在");
-    ErrorCode SKU_PROPERTIES_DUPLICATED = new ErrorCode(1008006001, "商品sku的属性组合存在重复");
+    // ========== 商品 SKU 1008006000 ==========
+    ErrorCode SKU_NOT_EXISTS = new ErrorCode(1008006000, "商品 SKU 不存在");
+    ErrorCode SKU_PROPERTIES_DUPLICATED = new ErrorCode(1008006001, "商品 SKU 的属性组合存在重复");
+    ErrorCode SPU_ATTR_NUMBERS_MUST_BE_EQUALS = new ErrorCode(1008006002, "一个 SPU 下的每个 SKU,其规格数必须一致");
+    ErrorCode SPU_SKU_NOT_DUPLICATE = new ErrorCode(1008006003, "一个 SPU 下的每个 SKU,必须不重复");
 
-    ErrorCode PRODUCT_SPU_ATTR_NUMBERS_MUST_BE_EQUALS = new ErrorCode(1008006002, "一个 Spu 下的每个 SKU ,其规格数必须一致");
-
-    ErrorCode PRODUCT_SPU_SKU_NOT_DUPLICATE = new ErrorCode(1008006003, "一个 SPU 下的每个 SKU ,必须不重复");
 }

+ 0 - 10
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/ProductBrandController.java

@@ -2,15 +2,9 @@ package cn.iocoder.yudao.module.product.controller.admin.brand;
 
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
-import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
 import cn.iocoder.yudao.module.product.controller.admin.brand.vo.*;
-import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryListReqVO;
-import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryRespVO;
 import cn.iocoder.yudao.module.product.convert.brand.ProductBrandConvert;
-import cn.iocoder.yudao.module.product.convert.category.ProductCategoryConvert;
 import cn.iocoder.yudao.module.product.dal.dataobject.brand.ProductBrandDO;
-import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO;
 import cn.iocoder.yudao.module.product.service.brand.ProductBrandService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
@@ -20,14 +14,11 @@ import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
-import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
-import java.io.IOException;
 import java.util.Comparator;
 import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
 
 @Api(tags = "管理后台 - 商品品牌")
 @RestController
@@ -88,5 +79,4 @@ public class ProductBrandController {
         return success(ProductBrandConvert.INSTANCE.convertList(list));
     }
 
-
 }

+ 5 - 5
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/category/ProductCategoryController.java

@@ -35,14 +35,14 @@ public class ProductCategoryController {
     @ApiOperation("创建商品分类")
     @PreAuthorize("@ss.hasPermission('product:category:create')")
     public CommonResult<Long> createProductCategory(@Valid @RequestBody ProductCategoryCreateReqVO createReqVO) {
-        return success(categoryService.createProductCategory(createReqVO));
+        return success(categoryService.createCategory(createReqVO));
     }
 
     @PutMapping("/update")
     @ApiOperation("更新商品分类")
     @PreAuthorize("@ss.hasPermission('product:category:update')")
     public CommonResult<Boolean> updateProductCategory(@Valid @RequestBody ProductCategoryUpdateReqVO updateReqVO) {
-        categoryService.updateProductCategory(updateReqVO);
+        categoryService.updateCategory(updateReqVO);
         return success(true);
     }
 
@@ -51,7 +51,7 @@ public class ProductCategoryController {
     @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
     @PreAuthorize("@ss.hasPermission('product:category:delete')")
     public CommonResult<Boolean> deleteProductCategory(@RequestParam("id") Long id) {
-        categoryService.deleteProductCategory(id);
+        categoryService.deleteCategory(id);
         return success(true);
     }
 
@@ -60,7 +60,7 @@ public class ProductCategoryController {
     @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
     @PreAuthorize("@ss.hasPermission('product:category:query')")
     public CommonResult<ProductCategoryRespVO> getProductCategory(@RequestParam("id") Long id) {
-        ProductCategoryDO category = categoryService.getProductCategory(id);
+        ProductCategoryDO category = categoryService.getCategory(id);
         return success(ProductCategoryConvert.INSTANCE.convert(category));
     }
 
@@ -68,7 +68,7 @@ public class ProductCategoryController {
     @ApiOperation("获得商品分类列表")
     @PreAuthorize("@ss.hasPermission('product:category:query')")
     public CommonResult<List<ProductCategoryRespVO>> getProductCategoryList(@Valid ProductCategoryListReqVO treeListReqVO) {
-        List<ProductCategoryDO> list = categoryService.getEnableProductCategoryList(treeListReqVO);
+        List<ProductCategoryDO> list = categoryService.getEnableCategoryList(treeListReqVO);
         list.sort(Comparator.comparing(ProductCategoryDO::getSort));
         return success(ProductCategoryConvert.INSTANCE.convertList(list));
     }

+ 3 - 3
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyController.java

@@ -62,7 +62,7 @@ public class ProductPropertyController {
     @ApiOperation("获得规格名称")
     @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
     @PreAuthorize("@ss.hasPermission('product:property:query')")
-    public CommonResult<ProductPropertyRespVO> getProperty(@RequestParam("id") Long id) {
+    public CommonResult<ProductPropertyAndValueRespVO> getProperty(@RequestParam("id") Long id) {
         return success(productPropertyService.getPropertyResp(id));
     }
 
@@ -70,7 +70,7 @@ public class ProductPropertyController {
     @ApiOperation("获得规格名称列表")
     @ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)
     @PreAuthorize("@ss.hasPermission('product:property:query')")
-    public CommonResult<List<ProductPropertyRespVO>> getPropertyList(@RequestParam("ids") Collection<Long> ids) {
+    public CommonResult<List<ProductPropertyAndValueRespVO>> getPropertyList(@RequestParam("ids") Collection<Long> ids) {
         List<ProductPropertyDO> list = productPropertyService.getPropertyList(ids);
         return success(ProductPropertyConvert.INSTANCE.convertList(list));
     }
@@ -78,7 +78,7 @@ public class ProductPropertyController {
     @GetMapping("/page")
     @ApiOperation("获得规格名称分页")
     @PreAuthorize("@ss.hasPermission('product:property:query')")
-    public CommonResult<PageResult<ProductPropertyRespVO>> getPropertyPage(@Valid ProductPropertyPageReqVO pageVO) {
+    public CommonResult<PageResult<ProductPropertyAndValueRespVO>> getPropertyPage(@Valid ProductPropertyPageReqVO pageVO) {
         return success(productPropertyService.getPropertyListPage(pageVO));
     }
 

+ 30 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/ProductPropertyAndValueRespVO.java

@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.product.controller.admin.property.vo;
+
+import cn.iocoder.yudao.module.product.controller.admin.propertyvalue.vo.ProductPropertyValueRespVO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.util.Date;
+import java.util.List;
+
+@ApiModel("管理后台 - 规格 + 规格值 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class ProductPropertyAndValueRespVO extends ProductPropertyBaseVO {
+
+    @ApiModelProperty(value = "规格的编号", required = true, example = "1024")
+    private Long id;
+
+    @ApiModelProperty(value = "创建时间", required = true)
+    private Date createTime;
+
+    /**
+     * 规格值的集合
+     */
+    private List<ProductPropertyValueRespVO> values;
+
+}

+ 3 - 4
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/ProductPropertyBaseVO.java

@@ -1,10 +1,9 @@
 package cn.iocoder.yudao.module.product.controller.admin.property.vo;
 
-import lombok.*;
-import java.util.*;
-import io.swagger.annotations.*;
-import javax.validation.constraints.*;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
 
+// TODO @芋艿:完整的 review 下规格
 /**
 * 规格名称 Base VO,提供给添加、修改、详细的子 VO 使用
 * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成

+ 0 - 23
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/ProductPropertyRespVO.java

@@ -1,23 +0,0 @@
-package cn.iocoder.yudao.module.product.controller.admin.property.vo;
-
-import cn.iocoder.yudao.module.product.controller.admin.propertyvalue.vo.ProductPropertyValueRespVO;
-import lombok.*;
-import java.util.*;
-import io.swagger.annotations.*;
-
-@ApiModel("管理后台 - 规格名称 Response VO")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class ProductPropertyRespVO extends ProductPropertyBaseVO {
-
-    @ApiModelProperty(value = "主键", required = true)
-    private Long id;
-
-    @ApiModelProperty(value = "创建时间")
-    private Date createTime;
-
-    @ApiModelProperty(value = "属性值")
-    private List<ProductPropertyValueRespVO> propertyValueList;
-
-}

+ 1 - 2
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuCreateOrUpdateReqVO.java

@@ -6,14 +6,13 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.ToString;
 
-import javax.validation.constraints.NotEmpty;
-
 @ApiModel("管理后台 - 商品 SKU 创建/更新 Request VO")
 @Data
 @EqualsAndHashCode(callSuper = true)
 @ToString(callSuper = true)
 public class ProductSkuCreateOrUpdateReqVO extends ProductSkuBaseVO {
 
+    // TODO @Luowenfeng:可以不用哈,如果基于规格匹配
     @ApiModelProperty(value = "商品 id 更新时须有", example = "1")
     private Long id;
 

+ 2 - 2
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java

@@ -36,14 +36,14 @@ public class ProductSpuController {
     @ApiOperation("创建商品 SPU")
     @PreAuthorize("@ss.hasPermission('product:spu:create')")
     public CommonResult<Long> createProductSpu(@Valid @RequestBody ProductSpuCreateReqVO createReqVO) {
-        return success(spuService.createProductSpu(createReqVO));
+        return success(spuService.createSpu(createReqVO));
     }
 
     @PutMapping("/update")
     @ApiOperation("更新商品 SPU")
     @PreAuthorize("@ss.hasPermission('product:spu:update')")
     public CommonResult<Boolean> updateSpu(@Valid @RequestBody ProductSpuUpdateReqVO updateReqVO) {
-        spuService.updateProductSpu(updateReqVO);
+        spuService.updateSpu(updateReqVO);
         return success(true);
     }
 

+ 2 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/SpuRespVO.java

@@ -35,6 +35,8 @@ public class SpuRespVO extends ProductSpuBaseVO {
     @ApiModelProperty(value = "分类id数组,一直递归到一级父节点", example = "[1,2,4]")
     private LinkedList<Long> categoryIds;
 
+    // TODO @芋艿:再琢磨下 这个 VO 类,其实变成 SpuRespVO 内嵌的 VO 类会更好一点;然后把 SpuRespVO 改成 SpuDetailSpuVO
+
     @ApiModelProperty(value = "规格属性修改和详情展示组合", example = "[{\"propertyId\":2,\"name\":\"内存\",\"propertyValues\":[{\"v1\":11,\"v2\":\"64G\"},{\"v1\":10,\"v2\":\"32G\"}]},{\"propertyId\":3,\"name\":\"尺寸\",\"propertyValues\":[{\"v1\":16,\"v2\":\"6.1\"},{\"v1\":15,\"v2\":\"5.7\"}]}]")
     private List<ProductPropertyViewRespVO> productPropertyViews;
 

+ 1 - 1
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/category/AppCategoryController.java

@@ -30,7 +30,7 @@ public class AppCategoryController {
     @GetMapping("/list")
     @ApiOperation("获得商品分类列表")
     public CommonResult<List<AppCategoryRespVO>> getProductCategoryList() {
-        List<ProductCategoryDO> list = categoryService.getEnableProductCategoryList();
+        List<ProductCategoryDO> list = categoryService.getEnableCategoryList();
         list.sort(Comparator.comparing(ProductCategoryDO::getSort));
         return success(ProductCategoryConvert.INSTANCE.convertList03(list));
     }

+ 3 - 3
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/property/ProductPropertyConvert.java

@@ -23,11 +23,11 @@ public interface ProductPropertyConvert {
 
     ProductPropertyDO convert(ProductPropertyUpdateReqVO bean);
 
-    ProductPropertyRespVO convert(ProductPropertyDO bean);
+    ProductPropertyAndValueRespVO convert(ProductPropertyDO bean);
 
-    List<ProductPropertyRespVO> convertList(List<ProductPropertyDO> list);
+    List<ProductPropertyAndValueRespVO> convertList(List<ProductPropertyDO> list);
 
-    PageResult<ProductPropertyRespVO> convertPage(PageResult<ProductPropertyDO> page);
+    PageResult<ProductPropertyAndValueRespVO> convertPage(PageResult<ProductPropertyDO> page);
 
     List<ProductPropertyExcelVO> convertList02(List<ProductPropertyDO> list);
 

+ 1 - 1
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/brand/ProductBrandMapper.java

@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.product.dal.mysql.brand;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
-import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandBaseVO;
 import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandListReqVO;
 import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandPageReqVO;
 import cn.iocoder.yudao.module.product.dal.dataobject.brand.ProductBrandDO;
@@ -27,4 +26,5 @@ public interface ProductBrandMapper extends BaseMapperX<ProductBrandDO> {
         return selectList(new LambdaQueryWrapperX<ProductBrandDO>()
                 .likeIfPresent(ProductBrandDO::getName, reqVO.getName()));
     }
+
 }

+ 4 - 6
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java

@@ -7,7 +7,6 @@ import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuPageReq
 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
 import org.apache.ibatis.annotations.Mapper;
 
-import java.util.Collections;
 import java.util.List;
 
 /**
@@ -34,13 +33,12 @@ public interface ProductSkuMapper extends BaseMapperX<ProductSkuDO> {
 
 
     // TODO @franky:方法名 selectList; 可以直接调用 selectList
-    default List<ProductSkuDO> selectBySpuIds(List<Long> spuIds) {
-        return selectList(new LambdaQueryWrapperX<ProductSkuDO>()
-                .inIfPresent(ProductSkuDO::getSpuId, spuIds));
+    default List<ProductSkuDO> selectListBySpuIds(List<Long> spuIds) {
+        return selectList(ProductSkuDO::getSpuId, spuIds);
     }
 
-    default List<ProductSkuDO> selectBySpuId(Long spuIds) {
-        return selectBySpuIds(Collections.singletonList(spuIds));
+    default List<ProductSkuDO> selectListBySpuId(Long spuId) {
+        return selectList(ProductSkuDO::getSpuId, spuId);
     }
 
     default void deleteBySpuId(Long spuId) {

+ 3 - 2
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/brand/ProductBrandService.java

@@ -55,10 +55,11 @@ public interface ProductBrandService {
 
     /**
      * 获得品牌列表
-     * @param listVo 请求参数
+     *
+     * @param listReqVO 请求参数
      * @return 品牌列表
      */
-    List<ProductBrandDO> getBrandList(ProductBrandListReqVO listVo);
+    List<ProductBrandDO> getBrandList(ProductBrandListReqVO listReqVO);
 
     /**
      * 验证选择的商品分类是否合法

+ 9 - 8
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/brand/ProductBrandServiceImpl.java

@@ -1,11 +1,13 @@
 package cn.iocoder.yudao.module.product.service.brand;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.product.controller.admin.brand.vo.*;
+import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandCreateReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandListReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandPageReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandUpdateReqVO;
 import cn.iocoder.yudao.module.product.convert.brand.ProductBrandConvert;
 import cn.iocoder.yudao.module.product.dal.dataobject.brand.ProductBrandDO;
 import cn.iocoder.yudao.module.product.dal.mysql.brand.ProductBrandMapper;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
@@ -14,8 +16,7 @@ import java.util.Collection;
 import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PRODUCT_BRAND_NOT_EXISTS;
-import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PRODUCT_CATEGORY_LEVEL;
+import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.BRAND_NOT_EXISTS;
 
 /**
  * 品牌 Service 实现类
@@ -57,7 +58,7 @@ public class ProductBrandServiceImpl implements ProductBrandService {
 
     private void validateBrandExists(Long id) {
         if (brandMapper.selectById(id) == null) {
-            throw exception(PRODUCT_BRAND_NOT_EXISTS);
+            throw exception(BRAND_NOT_EXISTS);
         }
     }
 
@@ -72,14 +73,14 @@ public class ProductBrandServiceImpl implements ProductBrandService {
     }
 
     @Override
-    public List<ProductBrandDO> getBrandList(ProductBrandListReqVO listVo) {
-        return brandMapper.selectList(listVo);
+    public List<ProductBrandDO> getBrandList(ProductBrandListReqVO listReqVO) {
+        return brandMapper.selectList(listReqVO);
     }
 
     @Override
     public void validateProductBrand(Long id) {
         if(getBrand(id) == null){
-            throw exception(PRODUCT_BRAND_NOT_EXISTS);
+            throw exception(BRAND_NOT_EXISTS);
         }
     }
 

+ 10 - 9
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryService.java

@@ -22,21 +22,21 @@ public interface ProductCategoryService {
      * @param createReqVO 创建信息
      * @return 编号
      */
-    Long createProductCategory(@Valid ProductCategoryCreateReqVO createReqVO);
+    Long createCategory(@Valid ProductCategoryCreateReqVO createReqVO);
 
     /**
      * 更新商品分类
      *
      * @param updateReqVO 更新信息
      */
-    void updateProductCategory(@Valid ProductCategoryUpdateReqVO updateReqVO);
+    void updateCategory(@Valid ProductCategoryUpdateReqVO updateReqVO);
 
     /**
      * 删除商品分类
      *
      * @param id 编号
      */
-    void deleteProductCategory(Long id);
+    void deleteCategory(Long id);
 
     /**
      * 获得商品分类
@@ -44,7 +44,7 @@ public interface ProductCategoryService {
      * @param id 编号
      * @return 商品分类
      */
-    ProductCategoryDO getProductCategory(Long id);
+    ProductCategoryDO getCategory(Long id);
 
     /**
      * 获得商品分类列表
@@ -52,7 +52,7 @@ public interface ProductCategoryService {
      * @param ids 编号
      * @return 商品分类列表
      */
-    List<ProductCategoryDO> getEnableProductCategoryList(Collection<Long> ids);
+    List<ProductCategoryDO> getEnableCategoryList(Collection<Long> ids);
 
     /**
      * 获得商品分类列表
@@ -60,20 +60,21 @@ public interface ProductCategoryService {
      * @param listReqVO 查询条件
      * @return 商品分类列表
      */
-    List<ProductCategoryDO> getEnableProductCategoryList(ProductCategoryListReqVO listReqVO);
+    List<ProductCategoryDO> getEnableCategoryList(ProductCategoryListReqVO listReqVO);
 
     /**
-     * 验证选择的商品分类是否合法
+     * 验证选择的商品分类的级别是否合法
+     * 例如说,商品发布的时候,必须在第 3 级别
      *
      * @param id 分类编号
      */
-    void validateProductCategory(Long id);
+    void validateCategoryLevel(Long id);
 
     /**
      * 获得开启状态的商品分类列表
      *
      * @return 商品分类列表
      */
-    List<ProductCategoryDO> getEnableProductCategoryList();
+    List<ProductCategoryDO> getEnableCategoryList();
 
 }

+ 28 - 20
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImpl.java

@@ -32,7 +32,7 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
     private ProductCategoryMapper productCategoryMapper;
 
     @Override
-    public Long createProductCategory(ProductCategoryCreateReqVO createReqVO) {
+    public Long createCategory(ProductCategoryCreateReqVO createReqVO) {
         // 校验父分类存在
         validateParentProductCategory(createReqVO.getParentId());
 
@@ -44,7 +44,7 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
     }
 
     @Override
-    public void updateProductCategory(ProductCategoryUpdateReqVO updateReqVO) {
+    public void updateCategory(ProductCategoryUpdateReqVO updateReqVO) {
         // 校验分类是否存在
         validateProductCategoryExists(updateReqVO.getId());
         // 校验父分类存在
@@ -56,12 +56,12 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
     }
 
     @Override
-    public void deleteProductCategory(Long id) {
+    public void deleteCategory(Long id) {
         // 校验分类是否存在
         validateProductCategoryExists(id);
         // 校验是否还有子分类
         if (productCategoryMapper.selectCountByParentId(id) > 0) {
-            throw exception(PRODUCT_CATEGORY_EXISTS_CHILDREN);
+            throw exception(CATEGORY_EXISTS_CHILDREN);
         }
 
         // 删除
@@ -76,61 +76,69 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
         // 父分类不存在
         ProductCategoryDO category = productCategoryMapper.selectById(id);
         if (category == null) {
-            throw exception(PRODUCT_CATEGORY_PARENT_NOT_EXISTS);
+            throw exception(CATEGORY_PARENT_NOT_EXISTS);
         }
         // 父分类不能是二级分类
         if (Objects.equals(id, ProductCategoryDO.PARENT_ID_NULL)) {
-            throw exception(PRODUCT_CATEGORY_PARENT_NOT_FIRST_LEVEL);
+            throw exception(CATEGORY_PARENT_NOT_FIRST_LEVEL);
         }
     }
 
     private void validateProductCategoryExists(Long id) {
         ProductCategoryDO category = productCategoryMapper.selectById(id);
         if (category == null) {
-            throw exception(PRODUCT_CATEGORY_NOT_EXISTS);
+            throw exception(CATEGORY_NOT_EXISTS);
         }
     }
 
     @Override
-    public void validateProductCategory(Long id) {
-        Integer level = categoryLevel(id, 1);
+    public void validateCategoryLevel(Long id) {
+        Integer level = getProductCategoryLevel(id, 1);
         if(level < 3){
-          throw exception(PRODUCT_CATEGORY_LEVEL);
+          throw exception(CATEGORY_LEVEL_ERROR);
         }
     }
 
-    // 校验分类级别
-    private Integer categoryLevel(Long id, int level){
+    // TODO @Luowenfeng:建议使用 for 循环,避免递归
+    /**
+     * 获得商品分类的级别
+     *
+     * @param id 商品分类的编号
+     * @return 级别
+     */
+    private Integer getProductCategoryLevel(Long id, int level){
         ProductCategoryDO category = productCategoryMapper.selectById(id);
         if (category == null) {
-            throw exception(PRODUCT_CATEGORY_NOT_EXISTS);
+            throw exception(CATEGORY_NOT_EXISTS);
         }
+        // TODO Luowenfeng:去掉是否开启,它不影响级别哈
         if (ObjectUtil.notEqual(category.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
-            throw exception(PRODUCT_CATEGORY_DISABLED);
+            throw exception(CATEGORY_DISABLED);
         }
-        if(category.getParentId() == 0) {
+        // TODO Luowenfeng:不使用 0 直接比较哈,使用枚举
+        if (category.getParentId() == 0) {
             return level;
         }
-        return categoryLevel(category.getParentId(), ++level);
+        return getProductCategoryLevel(category.getParentId(), ++level);
     }
 
     @Override
-    public ProductCategoryDO getProductCategory(Long id) {
+    public ProductCategoryDO getCategory(Long id) {
         return productCategoryMapper.selectById(id);
     }
 
     @Override
-    public List<ProductCategoryDO> getEnableProductCategoryList(Collection<Long> ids) {
+    public List<ProductCategoryDO> getEnableCategoryList(Collection<Long> ids) {
         return productCategoryMapper.selectBatchIds(ids);
     }
 
     @Override
-    public List<ProductCategoryDO> getEnableProductCategoryList(ProductCategoryListReqVO listReqVO) {
+    public List<ProductCategoryDO> getEnableCategoryList(ProductCategoryListReqVO listReqVO) {
         return productCategoryMapper.selectList(listReqVO);
     }
 
     @Override
-    public List<ProductCategoryDO> getEnableProductCategoryList() {
+    public List<ProductCategoryDO> getEnableCategoryList() {
         return productCategoryMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
     }
 

+ 13 - 9
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyService.java

@@ -1,10 +1,12 @@
 package cn.iocoder.yudao.module.product.service.property;
 
-import java.util.*;
-import javax.validation.*;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.product.controller.admin.property.vo.*;
 import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
+
+import javax.validation.Valid;
+import java.util.Collection;
+import java.util.List;
 
 /**
  * 规格名称 Service 接口
@@ -72,14 +74,16 @@ public interface ProductPropertyService {
      * @param pageReqVO
      * @return
      */
-    PageResult<ProductPropertyRespVO> getPropertyListPage(ProductPropertyPageReqVO pageReqVO);
+    PageResult<ProductPropertyAndValueRespVO> getPropertyListPage(ProductPropertyPageReqVO pageReqVO);
 
-    ProductPropertyRespVO getPropertyResp(Long id);
+    ProductPropertyAndValueRespVO getPropertyResp(Long id);
 
     /**
-     * 根据数据名id集合查询属性名以及属性值的集合
-     * @param propertyIds 属性名id集合
-     * @return
+     * 根据规格属性编号的集合,获得对应的规格 + 规格值的集合
+     *
+     * @param ids 规格编号的集合
+     * @return 对应的规格 + 规格值的集合
      */
-    List<ProductPropertyRespVO> selectByIds(List<Long> propertyIds);
+    List<ProductPropertyAndValueRespVO> getPropertyAndValueList(Collection<Long> ids);
+
 }

+ 11 - 11
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java

@@ -108,11 +108,11 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
     }
 
     @Override
-    public PageResult<ProductPropertyRespVO> getPropertyListPage(ProductPropertyPageReqVO pageReqVO) {
+    public PageResult<ProductPropertyAndValueRespVO> getPropertyListPage(ProductPropertyPageReqVO pageReqVO) {
         //获取属性列表
         PageResult<ProductPropertyDO> pageResult = productPropertyMapper.selectPage(pageReqVO);
-        PageResult<ProductPropertyRespVO> propertyRespVOPageResult = ProductPropertyConvert.INSTANCE.convertPage(pageResult);
-        List<Long> propertyIds = propertyRespVOPageResult.getList().stream().map(ProductPropertyRespVO::getId).collect(Collectors.toList());
+        PageResult<ProductPropertyAndValueRespVO> propertyRespVOPageResult = ProductPropertyConvert.INSTANCE.convertPage(pageResult);
+        List<Long> propertyIds = propertyRespVOPageResult.getList().stream().map(ProductPropertyAndValueRespVO::getId).collect(Collectors.toList());
 
         //获取属性值列表
         List<ProductPropertyValueDO> productPropertyValueDOList = productPropertyValueMapper.getPropertyValueListByPropertyId(propertyIds);
@@ -121,7 +121,7 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
         propertyRespVOPageResult.getList().forEach(x->{
             Long propertyId = x.getId();
             List<ProductPropertyValueRespVO> valueDOList = propertyValueRespVOList.stream().filter(v -> v.getPropertyId().equals(propertyId)).collect(Collectors.toList());
-            x.setPropertyValueList(valueDOList);
+            x.setValues(valueDOList);
         });
         return propertyRespVOPageResult;
     }
@@ -131,25 +131,25 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
     }
 
     @Override
-    public ProductPropertyRespVO getPropertyResp(Long id) {
+    public ProductPropertyAndValueRespVO getPropertyResp(Long id) {
         //查询规格
         ProductPropertyDO property = getProperty(id);
-        ProductPropertyRespVO propertyRespVO = ProductPropertyConvert.INSTANCE.convert(property);
+        ProductPropertyAndValueRespVO propertyRespVO = ProductPropertyConvert.INSTANCE.convert(property);
         //查询属性值
         List<ProductPropertyValueDO> valueDOList = productPropertyValueMapper.getPropertyValueListByPropertyId(Arrays.asList(id));
         List<ProductPropertyValueRespVO> propertyValueRespVOS = ProductPropertyValueConvert.INSTANCE.convertList(valueDOList);
         //组装
-        propertyRespVO.setPropertyValueList(propertyValueRespVOS);
+        propertyRespVO.setValues(propertyValueRespVOS);
         return propertyRespVO;
     }
 
     @Override
-    public List<ProductPropertyRespVO> selectByIds(List<Long> propertyIds) {
-        List<ProductPropertyRespVO> productPropertyRespVO = ProductPropertyConvert.INSTANCE.convertList(productPropertyMapper.selectBatchIds(propertyIds));
+    public List<ProductPropertyAndValueRespVO> getPropertyAndValueList(Collection<Long> ids) {
+        List<ProductPropertyAndValueRespVO> productPropertyRespVO = ProductPropertyConvert.INSTANCE.convertList(productPropertyMapper.selectBatchIds(ids));
         //查询属性值
-        List<ProductPropertyValueDO> valueDOList = productPropertyValueMapper.getPropertyValueListByPropertyId(propertyIds);
+        List<ProductPropertyValueDO> valueDOList = productPropertyValueMapper.selectBatchIds(ids);
         Map<Long, List<ProductPropertyValueDO>> propertyValuesMap = valueDOList.stream().collect(Collectors.groupingBy(ProductPropertyValueDO::getPropertyId));
-        productPropertyRespVO.forEach(p -> p.setPropertyValueList(ProductPropertyValueConvert.INSTANCE.convertList(propertyValuesMap.get(p.getId()))));
+        productPropertyRespVO.forEach(p -> p.setValues(ProductPropertyValueConvert.INSTANCE.convertList(propertyValuesMap.get(p.getId()))));
         return productPropertyRespVO;
     }
 }

+ 5 - 4
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java

@@ -11,14 +11,14 @@ import java.util.Collection;
 import java.util.List;
 
 /**
- * 商品sku Service 接口
+ * 商品 SKU Service 接口
  *
  * @author 芋道源码
  */
 public interface ProductSkuService {
 
     /**
-     * 创建商品sku
+     * 创建商品 SKU
      *
      * @param createReqVO 创建信息
      * @return 编号
@@ -68,14 +68,15 @@ public interface ProductSkuService {
      *
      * @param list sku组合的集合
      */
-    void validateProductSkus(List<ProductSkuCreateOrUpdateReqVO> list, Integer specType);
+    void validateSkus(List<ProductSkuCreateOrUpdateReqVO> list, Integer specType);
 
     /**
      * 批量创建 SKU
      *
+     * @param spuId 商品 SPU 编号
      * @param list SKU 对象集合
      */
-    void createProductSkus(List<ProductSkuCreateOrUpdateReqVO> list, Long spuId);
+    void createSkus(Long spuId, List<ProductSkuCreateOrUpdateReqVO> list);
 
     /**
      * 根据 SPU 编号,批量更新它的 SKU 信息

+ 46 - 44
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java

@@ -1,9 +1,10 @@
 package cn.iocoder.yudao.module.product.service.sku;
 
 import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
-import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyRespVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyAndValueRespVO;
 import cn.iocoder.yudao.module.product.controller.admin.propertyvalue.vo.ProductPropertyValueRespVO;
 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO;
 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
@@ -24,11 +25,10 @@ import java.util.*;
 import java.util.stream.Collectors;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PROPERTY_NOT_EXISTS;
-import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
+import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*;
 
 /**
- * 商品sku Service 实现类
+ * 商品 SKU Service 实现类
  *
  * @author 芋道源码
  */
@@ -90,48 +90,51 @@ public class ProductSkuServiceImpl implements ProductSkuService {
     }
 
     @Override
-    public void validateProductSkus(List<ProductSkuCreateOrUpdateReqVO> list, Integer specType) {
-        // 多规格才需校验
-        if (specType.equals(ProductSpuSpecTypeEnum.DISABLE.getType())) {
-            List<ProductSkuBaseVO.Property> skuPropertyList = list.stream().flatMap(p -> Optional.of(p.getProperties()).orElse(new ArrayList<>()).stream()).collect(Collectors.toList());
-            // 1、校验规格属性存在
-            List<Long> propertyIds = CollectionUtils.convertList(skuPropertyList, ProductSkuBaseVO.Property::getPropertyId);
-            List<ProductPropertyRespVO> propertyAndValueList = productPropertyService.selectByIds(propertyIds);
-            if (propertyAndValueList.size() == propertyIds.size()) {
-                throw exception(PROPERTY_NOT_EXISTS);
+    public void validateSkus(List<ProductSkuCreateOrUpdateReqVO> skus, Integer specType) {
+        // 非多规格,不需要校验
+        if (ObjectUtil.notEqual(specType, ProductSpuSpecTypeEnum.DISABLE.getType())) {
+            return;
+        }
+
+        // 1、校验规格属性存在
+        // TODO @Luowenfeng:stream 的写法;不用改哈,就是说下可以酱紫写;
+        Set<Long> propertyIds = skus.stream().filter(p -> p.getProperties() != null).flatMap(p -> p.getProperties().stream()) // 遍历多个 Property 属性
+                .map(ProductSkuBaseVO.Property::getPropertyId).collect(Collectors.toSet()); // 将每个 Property 转换成对应的 propertyId,最后形成集合
+        List<ProductPropertyAndValueRespVO> propertyAndValueList = productPropertyService.getPropertyAndValueList(propertyIds);
+        if (propertyAndValueList.size() == propertyIds.size()) {
+            throw exception(PROPERTY_NOT_EXISTS);
+        }
+
+        // 2. 校验,一个 SKU 下,没有重复的规格。校验方式是,遍历每个 SKU ,看看是否有重复的规格 propertyId
+        Map<Long, ProductPropertyValueRespVO> propertyValueMap = propertyAndValueList.stream().filter(p -> p.getValues() != null).flatMap(p -> p.getValues().stream())
+                .collect(Collectors.toMap(ProductPropertyValueRespVO::getId, value -> value)); // KEY:规格属性值的编号
+        skus.forEach(sku -> {
+            Set<Long> skuPropertyIds = CollectionUtils.convertSet(sku.getProperties(), propertyItem -> propertyValueMap.get(propertyItem.getValueId()).getPropertyId());
+            if (skuPropertyIds.size() != sku.getProperties().size()) {
+                throw exception(SKU_PROPERTIES_DUPLICATED);
             }
-            // 2. 校验,一个 Sku 下,没有重复的规格。校验方式是,遍历每个 Sku ,看看是否有重复的规格 attrId
-            List<ProductPropertyValueRespVO> collect = propertyAndValueList.stream()
-                    .flatMap(v -> Optional.of(v.getPropertyValueList())
-                            .orElse(new ArrayList<>()).stream()).collect(Collectors.toList());
-            Map<Long, ProductPropertyValueRespVO> propertyValueRespVOMap = CollectionUtils.convertMap(collect, ProductPropertyValueRespVO::getId);
-            list.forEach(v -> {
-                Set<Long> keys = v.getProperties().stream().map(k -> propertyValueRespVOMap.get(k.getValueId()).getPropertyId()).collect(Collectors.toSet());
-                if (keys.size() != v.getProperties().size()) {
-                    throw exception(ErrorCodeConstants.SKU_PROPERTIES_DUPLICATED);
-                }
-            });
+        });
 
-            // 3. 再校验,每个 Sku 的规格值的数量,是一致的。
-            int attrValueIdsSize = list.get(0).getProperties().size();
-            for (int i = 1; i < list.size(); i++) {
-                if (attrValueIdsSize != list.get(i).getProperties().size()) {
-                    throw exception(ErrorCodeConstants.PRODUCT_SPU_ATTR_NUMBERS_MUST_BE_EQUALS);
-                }
+        // 3. 再校验,每个 Sku 的规格值的数量,是一致的。
+        int attrValueIdsSize = skus.get(0).getProperties().size();
+        for (int i = 1; i < skus.size(); i++) {
+            if (attrValueIdsSize != skus.get(i).getProperties().size()) {
+                throw exception(ErrorCodeConstants.SPU_ATTR_NUMBERS_MUST_BE_EQUALS);
             }
+        }
 
-            // 4. 最后校验,每个 Sku 之间不是重复的
-            Set<Set<Long>> skuAttrValues = new HashSet<>(); // 每个元素,都是一个 Sku 的 attrValueId 集合。这样,通过最外层的 Set ,判断是否有重复的.
-            for (ProductSkuCreateOrUpdateReqVO sku : list) {
-                if (!skuAttrValues.add(sku.getProperties().stream().map(ProductSkuBaseVO.Property::getValueId).collect(Collectors.toSet()))) { // 添加失败,说明重复
-                    throw exception(ErrorCodeConstants.PRODUCT_SPU_SKU_NOT_DUPLICATE);
-                }
+        // 4. 最后校验,每个 Sku 之间不是重复的
+        Set<Set<Long>> skuAttrValues = new HashSet<>(); // 每个元素,都是一个 Sku 的 attrValueId 集合。这样,通过最外层的 Set ,判断是否有重复的.
+        for (ProductSkuCreateOrUpdateReqVO sku : skus) {
+            // TODO @Luowenfeng:可以使用 CollectionUtils.convertSet(),简化下面的 stream 操作
+            if (!skuAttrValues.add(sku.getProperties().stream().map(ProductSkuBaseVO.Property::getValueId).collect(Collectors.toSet()))) { // 添加失败,说明重复
+                throw exception(ErrorCodeConstants.SPU_SKU_NOT_DUPLICATE);
             }
         }
     }
 
     @Override
-    public void createProductSkus(List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList, Long spuId) {
+    public void createSkus(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList) {
         // 批量插入 SKU
         List<ProductSkuDO> skuDOList = ProductSkuConvert.INSTANCE.convertSkuDOList(skuCreateReqList);
         skuDOList.forEach(v -> v.setSpuId(spuId));
@@ -140,13 +143,12 @@ public class ProductSkuServiceImpl implements ProductSkuService {
 
     @Override
     public List<ProductSkuDO> getSkusBySpuId(Long spuId) {
-        List<ProductSkuDO> productSkuDOS = productSkuMapper.selectBySpuIds(Collections.singletonList(spuId));
-        return productSkuDOS;
+        return productSkuMapper.selectListBySpuIds(Collections.singletonList(spuId));
     }
 
     @Override
     public List<ProductSkuDO> getSkusBySpuIds(List<Long> spuIds) {
-        return productSkuMapper.selectBySpuIds(spuIds);
+        return productSkuMapper.selectListBySpuIds(spuIds);
     }
 
     @Override
@@ -157,16 +159,16 @@ public class ProductSkuServiceImpl implements ProductSkuService {
     @Override
     @Transactional
     public void updateProductSkus(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skus) {
-        // 查询 spu 下已经存在的 sku 的集合
-        List<ProductSkuDO> existsSkus = productSkuMapper.selectBySpuId(spuId);
+        // 查询 SPU 下已经存在的 SKU 的集合
+        List<ProductSkuDO> existsSkus = productSkuMapper.selectListBySpuId(spuId);
         Map<Long, ProductSkuDO> existsSkuMap = CollectionUtils.convertMap(existsSkus, ProductSkuDO::getId);
 
         // 拆分三个集合,新插入的、需要更新的、需要删除的
         List<ProductSkuDO> insertSkus = new ArrayList<>();
-        List<ProductSkuDO> updateSkus = new ArrayList<>();
+        List<ProductSkuDO> updateSkus = new ArrayList<>(); // TODO Luowenfeng:使用 Long 即可
         List<ProductSkuDO> deleteSkus = new ArrayList<>();
 
-        // TODO @芋艿:是不是基于规格匹配会比较好。
+        // TODO @Luowenfeng:是不是基于规格匹配会比较好。可以参考下 onemall 的 ProductSpuServiceImpl 的 updateProductSpu 逻辑
         List<ProductSkuDO> allUpdateSkus = ProductSkuConvert.INSTANCE.convertSkuDOList(skus);
         allUpdateSkus.forEach(p -> {
             if (p.getId() != null) {

+ 2 - 2
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java

@@ -26,14 +26,14 @@ public interface ProductSpuService {
      * @param createReqVO 创建信息
      * @return 编号
      */
-    Long createProductSpu(@Valid ProductSpuCreateReqVO createReqVO);
+    Long createSpu(@Valid ProductSpuCreateReqVO createReqVO);
 
     /**
      * 更新商品 SPU
      *
      * @param updateReqVO 更新信息
      */
-    void updateProductSpu(@Valid ProductSpuUpdateReqVO updateReqVO);
+    void updateSpu(@Valid ProductSpuUpdateReqVO updateReqVO);
 
     /**
      * 删除商品spu

+ 15 - 15
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java

@@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.product.service.spu;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
-import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyRespVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyAndValueRespVO;
 import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyViewRespVO;
 import cn.iocoder.yudao.module.product.controller.admin.propertyvalue.vo.ProductPropertyValueRespVO;
 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO;
@@ -16,7 +16,6 @@ import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageReqVO;
 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageRespVO;
 import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert;
 import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
-import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
 import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper;
 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuSpecTypeEnum;
@@ -30,7 +29,6 @@ import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
 import java.util.*;
-import java.util.function.Function;
 import java.util.stream.Collectors;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -62,14 +60,14 @@ public class ProductSpuServiceImpl implements ProductSpuService {
 
     @Override
     @Transactional
-    public Long createProductSpu(ProductSpuCreateReqVO createReqVO) {
+    public Long createSpu(ProductSpuCreateReqVO createReqVO) {
         // 校验分类
-        categoryService.validateProductCategory(createReqVO.getCategoryId());
+        categoryService.validateCategoryLevel(createReqVO.getCategoryId());
         // 校验品牌
         brandService.validateProductBrand(createReqVO.getBrandId());
         // 校验SKU
         List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = createReqVO.getSkus();
-        productSkuService.validateProductSkus(skuCreateReqList, createReqVO.getSpecType());
+        productSkuService.validateSkus(skuCreateReqList, createReqVO.getSpecType());
         // 插入 SPU
         ProductSpuDO spu = ProductSpuConvert.INSTANCE.convert(createReqVO);
         spu.setMarketPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getMarketPrice));
@@ -78,24 +76,25 @@ public class ProductSpuServiceImpl implements ProductSpuService {
         spu.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
         ProductSpuMapper.insert(spu);
         // 插入 SKU
-        productSkuService.createProductSkus(skuCreateReqList, spu.getId());
+        productSkuService.createSkus(spu.getId(), skuCreateReqList);
         // 返回
         return spu.getId();
     }
 
     @Override
     @Transactional
-    public void updateProductSpu(ProductSpuUpdateReqVO updateReqVO) {
+    public void updateSpu(ProductSpuUpdateReqVO updateReqVO) {
         // 校验 SPU 是否存在
         validateSpuExists(updateReqVO.getId());
         // 校验分类
-        categoryService.validateProductCategory(updateReqVO.getCategoryId());
+        categoryService.validateCategoryLevel(updateReqVO.getCategoryId());
         // 校验品牌
         brandService.validateProductBrand(updateReqVO.getBrandId());
         // 校验SKU
         List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = updateReqVO.getSkus();
         // 多规格才需校验
-        productSkuService.validateProductSkus(skuCreateReqList, updateReqVO.getSpecType());
+        productSkuService.validateSkus(skuCreateReqList, updateReqVO.getSpecType());
+
         // 更新 SPU
         ProductSpuDO updateObj = ProductSpuConvert.INSTANCE.convert(updateReqVO);
         updateObj.setMarketPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getMarketPrice));
@@ -103,7 +102,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
         updateObj.setMinPrice(CollectionUtils.getMinValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
         updateObj.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
         ProductSpuMapper.updateById(updateObj);
-        // 更新 SKU
+        // 批量更新 SKU
         productSkuService.updateProductSkus(updateObj.getId(), updateReqVO.getSkus());
     }
 
@@ -111,7 +110,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
     @Transactional
     public void deleteSpu(Long id) {
         // 校验存在
-        this.validateSpuExists(id);
+        validateSpuExists(id);
         // 删除 SPU
         ProductSpuMapper.deleteById(id);
         // 删除关联的 SKU
@@ -125,6 +124,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
     }
 
     @Override
+    // TODO @芋艿:需要再 review 下
     public SpuRespVO getSpu(Long id) {
         ProductSpuDO spu = ProductSpuMapper.selectById(id);
         SpuRespVO spuVO = ProductSpuConvert.INSTANCE.convert(spu);
@@ -138,7 +138,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
                     properties.addAll(productSkuRespVO.getProperties());
                 }
                 Map<Long, List<ProductSkuBaseVO.Property>> propertyMaps = properties.stream().collect(Collectors.groupingBy(ProductSkuBaseVO.Property::getPropertyId));
-                List<ProductPropertyRespVO> propertyAndValueList = productPropertyService.selectByIds(new ArrayList<>(propertyMaps.keySet()));
+                List<ProductPropertyAndValueRespVO> propertyAndValueList = productPropertyService.getPropertyAndValueList(new ArrayList<>(propertyMaps.keySet()));
                 // 装载组装过后的属性
                 List<ProductPropertyViewRespVO> productPropertyViews = new ArrayList<>();
                 propertyAndValueList.forEach(p -> {
@@ -146,7 +146,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
                     productPropertyViewRespVO.setPropertyId(p.getId());
                     productPropertyViewRespVO.setName(p.getName());
                     List<ProductPropertyViewRespVO.Tuple2> propertyValues = new ArrayList<>();
-                    Map<Long, ProductPropertyValueRespVO> propertyValueMaps = p.getPropertyValueList().stream().collect(Collectors.toMap(ProductPropertyValueRespVO::getId, pv -> pv));
+                    Map<Long, ProductPropertyValueRespVO> propertyValueMaps = p.getValues().stream().collect(Collectors.toMap(ProductPropertyValueRespVO::getId, pv -> pv));
                     propertyMaps.get(p.getId()).forEach(pv -> {
                         ProductPropertyViewRespVO.Tuple2 tuple2 = new ProductPropertyViewRespVO.Tuple2(pv.getValueId(), propertyValueMaps.get(pv.getValueId()).getName());
                         propertyValues.add(tuple2);
@@ -162,7 +162,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
                 Long parentId = spuVO.getCategoryId();
                 categoryArray.addFirst(parentId);
                 while (parentId != 0) {
-                    parentId = categoryService.getProductCategory(parentId).getParentId();
+                    parentId = categoryService.getCategory(parentId).getParentId();
                     if (parentId > 0) {
                         categoryArray.addFirst(parentId);
                     }

+ 3 - 3
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/brand/ProductBrandServiceImplTest.java

@@ -20,7 +20,7 @@ import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEq
 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
-import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PRODUCT_BRAND_NOT_EXISTS;
+import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.BRAND_NOT_EXISTS;
 import static org.junit.jupiter.api.Assertions.*;
 
 /**
@@ -74,7 +74,7 @@ public class ProductBrandServiceImplTest extends BaseDbUnitTest {
         ProductBrandUpdateReqVO reqVO = randomPojo(ProductBrandUpdateReqVO.class);
 
         // 调用, 并断言异常
-        assertServiceException(() -> brandService.updateBrand(reqVO), PRODUCT_BRAND_NOT_EXISTS);
+        assertServiceException(() -> brandService.updateBrand(reqVO), BRAND_NOT_EXISTS);
     }
 
     @Test
@@ -97,7 +97,7 @@ public class ProductBrandServiceImplTest extends BaseDbUnitTest {
         Long id = randomLongId();
 
         // 调用, 并断言异常
-        assertServiceException(() -> brandService.deleteBrand(id), PRODUCT_BRAND_NOT_EXISTS);
+        assertServiceException(() -> brandService.deleteBrand(id), BRAND_NOT_EXISTS);
     }
 
     @Test

+ 7 - 7
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImplTest.java

@@ -17,7 +17,7 @@ import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEq
 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
-import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PRODUCT_CATEGORY_NOT_EXISTS;
+import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.CATEGORY_NOT_EXISTS;
 import static org.junit.jupiter.api.Assertions.*;
 
 /**
@@ -43,7 +43,7 @@ public class ProductCategoryServiceImplTest extends BaseDbUnitTest {
         productCategoryMapper.insert(parentProductCategory);
 
         // 调用
-        Long categoryId = productCategoryService.createProductCategory(reqVO);
+        Long categoryId = productCategoryService.createCategory(reqVO);
         // 断言
         assertNotNull(categoryId);
         // 校验记录的属性是否正确
@@ -65,7 +65,7 @@ public class ProductCategoryServiceImplTest extends BaseDbUnitTest {
         productCategoryMapper.insert(parentProductCategory);
 
         // 调用
-        productCategoryService.updateProductCategory(reqVO);
+        productCategoryService.updateCategory(reqVO);
         // 校验是否更新正确
         ProductCategoryDO category = productCategoryMapper.selectById(reqVO.getId()); // 获取最新的
         assertPojoEquals(reqVO, category);
@@ -77,7 +77,7 @@ public class ProductCategoryServiceImplTest extends BaseDbUnitTest {
         ProductCategoryUpdateReqVO reqVO = randomPojo(ProductCategoryUpdateReqVO.class);
 
         // 调用, 并断言异常
-        assertServiceException(() -> productCategoryService.updateProductCategory(reqVO), PRODUCT_CATEGORY_NOT_EXISTS);
+        assertServiceException(() -> productCategoryService.updateCategory(reqVO), CATEGORY_NOT_EXISTS);
     }
 
     @Test
@@ -89,7 +89,7 @@ public class ProductCategoryServiceImplTest extends BaseDbUnitTest {
         Long id = dbCategory.getId();
 
         // 调用
-        productCategoryService.deleteProductCategory(id);
+        productCategoryService.deleteCategory(id);
         // 校验数据不存在了
         assertNull(productCategoryMapper.selectById(id));
     }
@@ -100,7 +100,7 @@ public class ProductCategoryServiceImplTest extends BaseDbUnitTest {
         Long id = randomLongId();
 
         // 调用, 并断言异常
-        assertServiceException(() -> productCategoryService.deleteProductCategory(id), PRODUCT_CATEGORY_NOT_EXISTS);
+        assertServiceException(() -> productCategoryService.deleteCategory(id), CATEGORY_NOT_EXISTS);
     }
 
     @Test
@@ -117,7 +117,7 @@ public class ProductCategoryServiceImplTest extends BaseDbUnitTest {
         reqVO.setName("特曼");
 
         // 调用
-        List<ProductCategoryDO> list = productCategoryService.getEnableProductCategoryList(reqVO);
+        List<ProductCategoryDO> list = productCategoryService.getEnableCategoryList(reqVO);
         // 断言
         assertEquals(1, list.size());
         assertPojoEquals(dbCategory, list.get(0));

+ 3 - 3
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java

@@ -41,7 +41,7 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
         ProductSpuCreateReqVO reqVO = randomPojo(ProductSpuCreateReqVO.class);
 
         // 调用
-        Long spuId = spuService.createProductSpu(reqVO);
+        Long spuId = spuService.createSpu(reqVO);
         // 断言
         assertNotNull(spuId);
         // 校验记录的属性是否正确
@@ -60,7 +60,7 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
         });
 
         // 调用
-        spuService.updateProductSpu(reqVO);
+        spuService.updateSpu(reqVO);
         // 校验是否更新正确
         ProductSpuDO spu = ProductSpuMapper.selectById(reqVO.getId()); // 获取最新的
         assertPojoEquals(reqVO, spu);
@@ -72,7 +72,7 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
         ProductSpuUpdateReqVO reqVO = randomPojo(ProductSpuUpdateReqVO.class);
 
         // 调用, 并断言异常
-        assertServiceException(() -> spuService.updateProductSpu(reqVO), SPU_NOT_EXISTS);
+        assertServiceException(() -> spuService.updateSpu(reqVO), SPU_NOT_EXISTS);
     }
 
     @Test