From e107b42f537ee1036c9b7a6ec90a002c78017eab Mon Sep 17 00:00:00 2001 From: YunaiV <> Date: Mon, 27 Jul 2020 20:07:23 +0800 Subject: [PATCH] =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E5=95=86=E5=93=81=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E7=9A=84=E8=BF=81=E7=A7=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/ProductSpuController.http | 18 ++- .../product/ProductSpuController.java | 3 + .../product/vo/spu/ProductSpuCreateReqVO.java | 50 ++++++-- .../product/vo/spu/ProductSpuPageReqVO.java | 22 +--- .../convert/product/ProductSpuConvert.java | 4 +- .../enums/ProductErrorCodeConstants.java | 14 +- .../productservice/rpc/spu/ProductSpuRpc.java | 4 +- .../spu/dto/ProductSpuAndSkuCreateReqDTO.java | 90 +++++++++++++ .../rpc/spu/dto/ProductSpuCreateReqDTO.java | 64 ---------- .../rpc/spu/dto/ProductSpuPageReqDTO.java | 8 ++ .../convert/sku/ProductSkuConvert.java | 33 +++++ .../convert/spu/ProductSpuConvert.java | 11 +- .../dataobject/attr/ProductAttrKeyDO.java | 34 +++++ .../dataobject/attr/ProductAttrValueDO.java | 12 +- .../mysql/dataobject/spu/ProductSkuDO.java | 7 +- .../mapper/attr/ProductAttrKeyMapper.java | 10 ++ .../mapper}/attr/ProductAttrValueMapper.java | 6 +- .../mysql/mapper/sku/ProductSkuMapper.java | 21 +++ .../mysql/mapper/spu/ProductSpuMapper.java | 3 +- .../manager/spu/ProductSpuManager.java | 61 ++++++++- .../rpc/spu/ProductSpuRpcImpl.java | 4 +- .../service/attr/ProductAttrService.java | 64 ++++++++++ .../attr/bo/ProductAttrKeyValueBO.java | 32 +++++ .../service/sku/ProductSkuService.java | 74 +++++++++++ .../sku/bo/ProductSkuCreateOrUpdateBO.java | 10 +- .../service/spu/bo/ProductSpuPageBO.java | 8 ++ .../resources/mapper/ProductSkuMapper.xml | 17 +++ .../bo/product/ProductAttrAndValuePairBO.java | 32 ----- .../biz/dao/attr/ProductAttrMapper.java | 10 -- .../product/biz/dao/sku/ProductSpuMapper.java | 11 -- .../biz/dataobject/attr/ProductAttrDO.java | 30 ----- .../dto/product/ProductSkuAddOrUpdateDTO.java | 35 ----- .../biz/dto/product/ProductSpuAddDTO.java | 62 --------- .../biz/dto/sku/ProductSkuAddOrUpdateDTO.java | 35 ----- .../product/biz/dto/sku/ProductSpuAddDTO.java | 63 --------- .../biz/dto/sku/ProductSpuUpdateDTO.java | 69 ---------- .../resources/mapper/ProductSpuMapper.xml | 6 - .../mall/product/api/ProductSpuService.java | 2 - .../api/bo/ProductAttrAndValuePairBO.java | 32 ----- .../mall/product/api/bo/ProductSpuBO.java | 74 ----------- .../mall/product/api/bo/ProductSpuPageBO.java | 25 ---- .../product/api/dto/ProductSpuAddDTO.java | 62 --------- .../product/api/dto/ProductSpuPageDTO.java | 41 ------ .../mall/product/dao/ProductSpuMapper.java | 21 --- .../service/ProductAttrServiceImpl.java | 33 ----- .../service/ProductSpuServiceImpl.java | 88 ------------- .../resources/mapper/ProductSpuMapper.xml | 120 ------------------ .../UserProductSpuCollectionsMapper.xml | 41 ------ .../src/main/resources/mybatis-config.xml | 19 --- 49 files changed, 553 insertions(+), 1042 deletions(-) create mode 100644 product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/rpc/spu/dto/ProductSpuAndSkuCreateReqDTO.java delete mode 100644 product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/rpc/spu/dto/ProductSpuCreateReqDTO.java create mode 100644 product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/convert/sku/ProductSkuConvert.java create mode 100644 product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/dataobject/attr/ProductAttrKeyDO.java rename {product/product-biz/src/main/java/cn/iocoder/mall/product/biz => product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql}/dataobject/attr/ProductAttrValueDO.java (65%) create mode 100644 product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/mapper/attr/ProductAttrKeyMapper.java rename {product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dao => product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/mapper}/attr/ProductAttrValueMapper.java (57%) create mode 100644 product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/mapper/sku/ProductSkuMapper.java create mode 100644 product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/service/attr/ProductAttrService.java create mode 100644 product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/service/attr/bo/ProductAttrKeyValueBO.java create mode 100644 product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/service/sku/ProductSkuService.java rename product/product-service-api/src/main/java/cn/iocoder/mall/product/api/dto/ProductSkuAddOrUpdateDTO.java => product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/service/sku/bo/ProductSkuCreateOrUpdateBO.java (75%) create mode 100644 product-service-project/product-service-app/src/main/resources/mapper/ProductSkuMapper.xml delete mode 100644 product/product-biz/src/main/java/cn/iocoder/mall/product/biz/bo/product/ProductAttrAndValuePairBO.java delete mode 100644 product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dao/attr/ProductAttrMapper.java delete mode 100644 product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dao/sku/ProductSpuMapper.java delete mode 100644 product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dataobject/attr/ProductAttrDO.java delete mode 100644 product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/product/ProductSkuAddOrUpdateDTO.java delete mode 100644 product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/product/ProductSpuAddDTO.java delete mode 100644 product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/sku/ProductSkuAddOrUpdateDTO.java delete mode 100644 product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/sku/ProductSpuAddDTO.java delete mode 100644 product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/sku/ProductSpuUpdateDTO.java delete mode 100644 product/product-biz/src/main/resources/mapper/ProductSpuMapper.xml delete mode 100644 product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductAttrAndValuePairBO.java delete mode 100644 product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductSpuBO.java delete mode 100644 product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductSpuPageBO.java delete mode 100644 product/product-service-api/src/main/java/cn/iocoder/mall/product/api/dto/ProductSpuAddDTO.java delete mode 100644 product/product-service-api/src/main/java/cn/iocoder/mall/product/api/dto/ProductSpuPageDTO.java delete mode 100644 product/product-service-impl/src/main/resources/mapper/UserProductSpuCollectionsMapper.xml delete mode 100644 product/product-service-impl/src/main/resources/mybatis-config.xml diff --git a/management-web-app/src/main/java/cn/iocoder/mall/managementweb/controller/product/ProductSpuController.http b/management-web-app/src/main/java/cn/iocoder/mall/managementweb/controller/product/ProductSpuController.http index 6069ed666..28683ca7e 100644 --- a/management-web-app/src/main/java/cn/iocoder/mall/managementweb/controller/product/ProductSpuController.http +++ b/management-web-app/src/main/java/cn/iocoder/mall/managementweb/controller/product/ProductSpuController.http @@ -3,5 +3,21 @@ GET {{baseUrl}}/product-spu/page?pageNo=1&pageSize=10 Content-Type: application/x-www-form-urlencoded Authorization: Bearer {{accessToken}} -### +### /product-spu/page 成功(有库存 + 上架) +GET {{baseUrl}}/product-spu/page?pageNo=1&pageSize=10&hasQuantity=true&visible=true +Content-Type: application/x-www-form-urlencoded +Authorization: Bearer {{accessToken}} +### /product-spu/page 成功(无库存 + 下架) +GET {{baseUrl}}/product-spu/page?pageNo=1&pageSize=10&hasQuantity=false&visible=false +Content-Type: application/x-www-form-urlencoded +Authorization: Bearer {{accessToken}} + +### /product-spu/create 成功 +POST {{baseUrl}}/product-spu/create +Content-Type: application/x-www-form-urlencoded +Authorization: Bearer {{accessToken}} + +name=测试商品标题&description=测试商品描述&cid=637&sellPoint=丑&picUrls=1,2,3&visible=true&skus[0].price=1&skus[0].quantity=100&skus[0].attrValueIds=1,3 + +### diff --git a/management-web-app/src/main/java/cn/iocoder/mall/managementweb/controller/product/ProductSpuController.java b/management-web-app/src/main/java/cn/iocoder/mall/managementweb/controller/product/ProductSpuController.java index dabc28651..63846171a 100644 --- a/management-web-app/src/main/java/cn/iocoder/mall/managementweb/controller/product/ProductSpuController.java +++ b/management-web-app/src/main/java/cn/iocoder/mall/managementweb/controller/product/ProductSpuController.java @@ -61,6 +61,9 @@ public class ProductSpuController { @GetMapping("/page") @ApiOperation("获得商品 SPU 分页") public CommonResult> pageProductSpu(ProductSpuPageReqVO pageVO) { + // + // + // return success(productSpuManager.pageProductSpu(pageVO)); } diff --git a/management-web-app/src/main/java/cn/iocoder/mall/managementweb/controller/product/vo/spu/ProductSpuCreateReqVO.java b/management-web-app/src/main/java/cn/iocoder/mall/managementweb/controller/product/vo/spu/ProductSpuCreateReqVO.java index 0bbcfbed0..9f0b506f1 100644 --- a/management-web-app/src/main/java/cn/iocoder/mall/managementweb/controller/product/vo/spu/ProductSpuCreateReqVO.java +++ b/management-web-app/src/main/java/cn/iocoder/mall/managementweb/controller/product/vo/spu/ProductSpuCreateReqVO.java @@ -3,15 +3,45 @@ package cn.iocoder.mall.managementweb.controller.product.vo.spu; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; +import lombok.experimental.Accessors; +import javax.validation.Valid; +import javax.validation.constraints.Min; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; import java.util.List; -@ApiModel("商品 SPU创建 Request VO") +@ApiModel("商品 SPU 创建 Request VO") @Data public class ProductSpuCreateReqVO { + /** + * SKU 信息 + */ + @Data + @Accessors(chain = true) + public static class Sku { + + /** + * 规格值数组 + */ + @NotNull(message = "规格值数组不能为空") + private List attrValueIds; + /** + * 价格,单位:分 + */ + @NotNull(message = "价格不能为空") + @Min(value = 1L, message = "最小价格为 1") + private Integer price; + /** + * 库存数量 + */ + @NotNull(message = "库存数量不能为空") + @Min(value = 1L, message = "最小库存为 1") + private Integer quantity; + + } + @ApiModelProperty(value = "SPU 名字", required = true) @NotEmpty(message = "SPU 名字不能为空") private String name; @@ -30,14 +60,14 @@ public class ProductSpuCreateReqVO { @ApiModelProperty(value = "是否上架商品", required = true) @NotNull(message = "是否上架商品不能为空") private Boolean visible; - @ApiModelProperty(value = "排序字段", required = true) - @NotNull(message = "排序字段不能为空") - private Integer sort; - @ApiModelProperty(value = "价格", required = true) - @NotNull(message = "价格不能为空") - private Integer price; - @ApiModelProperty(value = "库存数量", required = true) - @NotNull(message = "库存数量不能为空") - private Integer quantity; + + // ========== SKU ========= + + /** + * SKU 数组 + */ + @NotNull(message = "SKU 不能为空") + @Valid + private List skus; } diff --git a/management-web-app/src/main/java/cn/iocoder/mall/managementweb/controller/product/vo/spu/ProductSpuPageReqVO.java b/management-web-app/src/main/java/cn/iocoder/mall/managementweb/controller/product/vo/spu/ProductSpuPageReqVO.java index cadfcea8c..9911a8d46 100644 --- a/management-web-app/src/main/java/cn/iocoder/mall/managementweb/controller/product/vo/spu/ProductSpuPageReqVO.java +++ b/management-web-app/src/main/java/cn/iocoder/mall/managementweb/controller/product/vo/spu/ProductSpuPageReqVO.java @@ -11,23 +11,13 @@ import lombok.EqualsAndHashCode; @EqualsAndHashCode(callSuper = true) public class ProductSpuPageReqVO extends PageParam { - @ApiModelProperty(value = "SPU 名字", required = true) + @ApiModelProperty(value = "SPU 名字", notes = "模糊匹配", example = "艿艿") private String name; - @ApiModelProperty(value = "卖点", required = true) - private String sellPoint; - @ApiModelProperty(value = "描述", required = true) - private String description; - @ApiModelProperty(value = "分类编号", required = true) + @ApiModelProperty(value = "分类编号", example = "1024") private Integer cid; - @ApiModelProperty(value = "商品主图地址", required = true) - private String picUrls; - @ApiModelProperty(value = "是否上架商品", required = true) - private Integer visible; - @ApiModelProperty(value = "排序字段", required = true) - private Integer sort; - @ApiModelProperty(value = "价格", required = true) - private Integer price; - @ApiModelProperty(value = "库存数量", required = true) - private Integer quantity; + @ApiModelProperty(value = "是否上架商品", example = "true") + private Boolean visible; + @ApiModelProperty(value = "是否有库存", example = "true") + private Boolean hasQuantity; } diff --git a/management-web-app/src/main/java/cn/iocoder/mall/managementweb/convert/product/ProductSpuConvert.java b/management-web-app/src/main/java/cn/iocoder/mall/managementweb/convert/product/ProductSpuConvert.java index 19cc7c6bf..4b731c399 100644 --- a/management-web-app/src/main/java/cn/iocoder/mall/managementweb/convert/product/ProductSpuConvert.java +++ b/management-web-app/src/main/java/cn/iocoder/mall/managementweb/convert/product/ProductSpuConvert.java @@ -5,7 +5,7 @@ import cn.iocoder.mall.managementweb.controller.product.vo.spu.ProductSpuCreateR import cn.iocoder.mall.managementweb.controller.product.vo.spu.ProductSpuPageReqVO; import cn.iocoder.mall.managementweb.controller.product.vo.spu.ProductSpuRespVO; import cn.iocoder.mall.managementweb.controller.product.vo.spu.ProductSpuUpdateReqVO; -import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuCreateReqDTO; +import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuAndSkuCreateReqDTO; import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuPageReqDTO; import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuRespDTO; import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuUpdateReqDTO; @@ -19,7 +19,7 @@ public interface ProductSpuConvert { ProductSpuConvert INSTANCE = Mappers.getMapper(ProductSpuConvert.class); - ProductSpuCreateReqDTO convert(ProductSpuCreateReqVO bean); + ProductSpuAndSkuCreateReqDTO convert(ProductSpuCreateReqVO bean); ProductSpuUpdateReqDTO convert(ProductSpuUpdateReqVO bean); diff --git a/product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/enums/ProductErrorCodeConstants.java b/product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/enums/ProductErrorCodeConstants.java index 5aaa28b20..509f5dd59 100644 --- a/product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/enums/ProductErrorCodeConstants.java +++ b/product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/enums/ProductErrorCodeConstants.java @@ -18,15 +18,15 @@ public interface ProductErrorCodeConstants { ErrorCode PRODUCT_CATEGORY_PARENT_CAN_NOT_BE_LEVEL2 = new ErrorCode(1002001005, "父分类必须是一级分类"); // ========== PRODUCT SPU + SKU 模块 ========== - ErrorCode PRODUCT_SKU_ATTR_CANT_NOT_DUPLICATE = new ErrorCode(1003002000, "一个 Sku 下,不能有重复的规格"); - ErrorCode PRODUCT_SPU_ATTR_NUMBERS_MUST_BE_EQUALS = new ErrorCode(1003002001, "一个 Spu 下的每个 Sku ,其规格数必须一致"); - ErrorCode PRODUCT_SPU_SKU__NOT_DUPLICATE = new ErrorCode(1003002002, "一个 Spu 下的每个 Sku ,必须不重复"); - ErrorCode PRODUCT_SPU_NOT_EXISTS = new ErrorCode(1003002003, "Spu 不存在"); - ErrorCode PRODUCT_SPU_CATEGORY_MUST_BE_LEVEL2 = new ErrorCode(1003002003, "Spu 只能添加在二级分类下"); + ErrorCode PRODUCT_SKU_ATTR_CANT_NOT_DUPLICATE = new ErrorCode(1003002000, "一个 SKU 下,不能有重复的规格"); + ErrorCode PRODUCT_SPU_ATTR_NUMBERS_MUST_BE_EQUALS = new ErrorCode(1003002001, "一个 Spu 下的每个 SKU ,其规格数必须一致"); + ErrorCode PRODUCT_SPU_SKU_NOT_DUPLICATE = new ErrorCode(1003002002, "一个 SPU 下的每个 SKU ,必须不重复"); + ErrorCode PRODUCT_SPU_NOT_EXISTS = new ErrorCode(1003002003, "SPU 不存在"); + ErrorCode PRODUCT_SPU_CATEGORY_MUST_BE_LEVEL2 = new ErrorCode(1003002003, "SPU 只能添加在二级分类下"); // ========== PRODUCT ATTR + ATTR_VALUE 模块 ========== - ErrorCode PRODUCT_ATTR_VALUE_NOT_EXIST = new ErrorCode(1003003000, "商品属性值不存在"); - ErrorCode PRODUCT_ATTR_NOT_EXIST = new ErrorCode(1003003001, "商品属性值不存在"); + ErrorCode PRODUCT_ATTR_VALUE_NOT_EXIST = new ErrorCode(1003003000, "商品属性值不存在"); + ErrorCode PRODUCT_ATTR_KEY_NOT_EXIST = new ErrorCode(1003003001, "商品属性值不存在"); ErrorCode PRODUCT_ATTR_EXISTS = new ErrorCode(1003003002, "商品规格已经存在"); ErrorCode PRODUCT_ATTR_STATUS_EQUALS = new ErrorCode(1003003003, "商品规格已经是该状态"); ErrorCode PRODUCT_ATTR_VALUE_EXISTS = new ErrorCode(1003003004, "商品规格值已经存在"); diff --git a/product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/rpc/spu/ProductSpuRpc.java b/product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/rpc/spu/ProductSpuRpc.java index 14c58e230..0e33c9e6f 100644 --- a/product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/rpc/spu/ProductSpuRpc.java +++ b/product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/rpc/spu/ProductSpuRpc.java @@ -2,7 +2,7 @@ package cn.iocoder.mall.productservice.rpc.spu; import cn.iocoder.common.framework.vo.CommonResult; import cn.iocoder.common.framework.vo.PageResult; -import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuCreateReqDTO; +import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuAndSkuCreateReqDTO; import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuPageReqDTO; import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuRespDTO; import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuUpdateReqDTO; @@ -20,7 +20,7 @@ public interface ProductSpuRpc { * @param createDTO 创建商品 SPU DTO * @return 商品 SPU编号 */ - CommonResult createProductSpu(ProductSpuCreateReqDTO createDTO); + CommonResult createProductSpu(ProductSpuAndSkuCreateReqDTO createDTO); /** * 更新商品 SPU diff --git a/product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/rpc/spu/dto/ProductSpuAndSkuCreateReqDTO.java b/product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/rpc/spu/dto/ProductSpuAndSkuCreateReqDTO.java new file mode 100644 index 000000000..625a449e3 --- /dev/null +++ b/product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/rpc/spu/dto/ProductSpuAndSkuCreateReqDTO.java @@ -0,0 +1,90 @@ +package cn.iocoder.mall.productservice.rpc.spu.dto; + +import lombok.Data; +import lombok.experimental.Accessors; + +import javax.validation.Valid; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.List; + +/** +* 商品 SPU 和 SKU 创建 Request DTO +*/ +@Data +@Accessors(chain = true) +public class ProductSpuAndSkuCreateReqDTO implements Serializable { + + /** + * SKU 信息 + */ + @Data + @Accessors(chain = true) + public static class Sku implements Serializable { + + /** + * 规格值数组 + */ + @NotNull(message = "规格值数组不能为空") + private List attrValueIds; + /** + * 价格,单位:分 + */ + @NotNull(message = "价格不能为空") + @Min(value = 1L, message = "最小价格为 1") + private Integer price; + /** + * 库存数量 + */ + @NotNull(message = "库存数量不能为空") + @Min(value = 1L, message = "最小库存为 1") + private Integer quantity; + + } + + // ========== 基本信息 ========= + /** + * SPU 名字 + */ + @NotEmpty(message = "SPU 名字不能为空") + private String name; + /** + * 卖点 + */ + @NotEmpty(message = "卖点不能为空") + private String sellPoint; + /** + * 描述 + */ + @NotEmpty(message = "描述不能为空") + private String description; + /** + * 分类编号 + */ + @NotNull(message = "分类编号不能为空") + private Integer cid; + /** + * 商品主图地址 + */ + @NotEmpty(message = "商品主图地址不能为空") + private List picUrls; + + // ========== 其他信息 ========= + /** + * 是否上架商品 + */ + @NotNull(message = "是否上架商品不能为空") + private Boolean visible; + + // ========== SKU ========= + + /** + * SKU 数组 + */ + @NotNull(message = "SKU 不能为空") + @Valid + private List skus; + +} diff --git a/product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/rpc/spu/dto/ProductSpuCreateReqDTO.java b/product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/rpc/spu/dto/ProductSpuCreateReqDTO.java deleted file mode 100644 index b3289f576..000000000 --- a/product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/rpc/spu/dto/ProductSpuCreateReqDTO.java +++ /dev/null @@ -1,64 +0,0 @@ -package cn.iocoder.mall.productservice.rpc.spu.dto; - -import lombok.Data; -import lombok.experimental.Accessors; - -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import java.io.Serializable; -import java.util.List; - -/** -* 商品 SPU 创建 Request DTO -*/ -@Data -@Accessors(chain = true) -public class ProductSpuCreateReqDTO implements Serializable { - - /** - * SPU 名字 - */ - @NotEmpty(message = "SPU 名字不能为空") - private String name; - /** - * 卖点 - */ - @NotEmpty(message = "卖点不能为空") - private String sellPoint; - /** - * 描述 - */ - @NotEmpty(message = "描述不能为空") - private String description; - /** - * 分类编号 - */ - @NotNull(message = "分类编号不能为空") - private Integer cid; - /** - * 商品主图地址 - */ - @NotEmpty(message = "商品主图地址不能为空") - private List picUrls; - /** - * 是否上架商品 - */ - @NotNull(message = "是否上架商品不能为空") - private Boolean visible; - /** - * 排序字段 - */ - @NotNull(message = "排序字段不能为空") - private Integer sort; - /** - * 价格 - */ - @NotNull(message = "价格不能为空") - private Integer price; - /** - * 库存数量 - */ - @NotNull(message = "库存数量不能为空") - private Integer quantity; - -} diff --git a/product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/rpc/spu/dto/ProductSpuPageReqDTO.java b/product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/rpc/spu/dto/ProductSpuPageReqDTO.java index d0d6600be..ead77560f 100644 --- a/product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/rpc/spu/dto/ProductSpuPageReqDTO.java +++ b/product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/rpc/spu/dto/ProductSpuPageReqDTO.java @@ -17,6 +17,14 @@ public class ProductSpuPageReqDTO extends PageParam { * SPU 名字 */ private String name; + /** + * 分类编号 + */ + private Integer cid; + /** + * 是否可见 + */ + private Boolean visible; /** * 是否有库存 */ diff --git a/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/convert/sku/ProductSkuConvert.java b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/convert/sku/ProductSkuConvert.java new file mode 100644 index 000000000..51ab84f7c --- /dev/null +++ b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/convert/sku/ProductSkuConvert.java @@ -0,0 +1,33 @@ +package cn.iocoder.mall.productservice.convert.sku; + +import cn.iocoder.common.framework.util.StringUtils; +import cn.iocoder.mall.productservice.dal.mysql.dataobject.spu.ProductSkuDO; +import cn.iocoder.mall.productservice.service.sku.bo.ProductSkuCreateOrUpdateBO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface ProductSkuConvert { + + ProductSkuConvert INSTANCE = Mappers.getMapper(ProductSkuConvert.class); + + List convertList(List list); + + @Mapping(source = "attrValueIds", target = "attrs", qualifiedByName = "translatePicUrlsFromStringList") + ProductSkuDO convertList(ProductSkuCreateOrUpdateBO bean); + + @Named("translateAttrValueIdsFromString") + default List translateAttrValueIdsFromString(String attrValueIdsStar) { + return StringUtils.split(attrValueIdsStar, ","); + } + + @Named("translateAttrValueIdsFromList") + default String translateAttrValueIdsFromList(List attrValueIds) { + return StringUtils.join(attrValueIds, ","); + } + +} diff --git a/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/convert/spu/ProductSpuConvert.java b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/convert/spu/ProductSpuConvert.java index 3a5619d4b..ced5694b4 100644 --- a/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/convert/spu/ProductSpuConvert.java +++ b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/convert/spu/ProductSpuConvert.java @@ -3,7 +3,8 @@ package cn.iocoder.mall.productservice.convert.spu; import cn.iocoder.common.framework.util.StringUtils; import cn.iocoder.common.framework.vo.PageResult; import cn.iocoder.mall.productservice.dal.mysql.dataobject.spu.ProductSpuDO; -import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuCreateReqDTO; +import cn.iocoder.mall.productservice.service.sku.bo.ProductSkuCreateOrUpdateBO; +import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuAndSkuCreateReqDTO; import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuPageReqDTO; import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuRespDTO; import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuUpdateReqDTO; @@ -38,7 +39,7 @@ public interface ProductSpuConvert { @Mapping(source = "records", target = "list") PageResult convertPage(IPage page); - ProductSpuCreateBO convert(ProductSpuCreateReqDTO bean); + ProductSpuCreateBO convert(ProductSpuAndSkuCreateReqDTO bean); ProductSpuUpdateBO convert(ProductSpuUpdateReqDTO bean); @@ -51,13 +52,15 @@ public interface ProductSpuConvert { PageResult convertPage(PageResult page); @Named("translatePicUrlsFromString") - default List translatePicUrlsFromString(String picUrls) { + default List translatePicUrlsFromList(String picUrls) { return StringUtils.split(picUrls, ","); } @Named("translatePicUrlsFromStringList") - default String translatePicUrlsFromString(List picUrls) { + default String translatePicUrlsFromList(List picUrls) { return StringUtils.join(picUrls, ","); } + List convert(List list); + } diff --git a/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/dataobject/attr/ProductAttrKeyDO.java b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/dataobject/attr/ProductAttrKeyDO.java new file mode 100644 index 000000000..528c6e0fa --- /dev/null +++ b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/dataobject/attr/ProductAttrKeyDO.java @@ -0,0 +1,34 @@ +package cn.iocoder.mall.productservice.dal.mysql.dataobject.attr; + +import cn.iocoder.common.framework.enums.CommonStatusEnum; +import cn.iocoder.mall.mybatis.core.dataobject.DeletableDO; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + * Product 规格键 DO + */ +@TableName("product_attr_key") +@Data +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = true) +public class ProductAttrKeyDO extends DeletableDO { + + /** + * 规格编号 + */ + private Integer id; + /** + * 名称 + */ + private String name; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + +} diff --git a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dataobject/attr/ProductAttrValueDO.java b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/dataobject/attr/ProductAttrValueDO.java similarity index 65% rename from product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dataobject/attr/ProductAttrValueDO.java rename to product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/dataobject/attr/ProductAttrValueDO.java index 15e75e36a..277c57e09 100644 --- a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dataobject/attr/ProductAttrValueDO.java +++ b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/dataobject/attr/ProductAttrValueDO.java @@ -1,13 +1,16 @@ -package cn.iocoder.mall.product.biz.dataobject.attr; +package cn.iocoder.mall.productservice.dal.mysql.dataobject.attr; +import cn.iocoder.common.framework.enums.CommonStatusEnum; import cn.iocoder.mall.mybatis.core.dataobject.DeletableDO; +import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; /** - * Product 规格值 + * 商品规格值 DO */ +@TableName("product_attr_value") @Data @EqualsAndHashCode(callSuper = true) @Accessors(chain = true) @@ -27,9 +30,8 @@ public class ProductAttrValueDO extends DeletableDO { private String name; /** * 状态 - *

- * 1-正常 - * 2-禁用 + * + * 枚举 {@link CommonStatusEnum} */ private Integer status; diff --git a/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/dataobject/spu/ProductSkuDO.java b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/dataobject/spu/ProductSkuDO.java index 6a84db151..b7c61e3c2 100644 --- a/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/dataobject/spu/ProductSkuDO.java +++ b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/dataobject/spu/ProductSkuDO.java @@ -1,6 +1,8 @@ package cn.iocoder.mall.productservice.dal.mysql.dataobject.spu; +import cn.iocoder.common.framework.enums.CommonStatusEnum; import cn.iocoder.mall.mybatis.core.dataobject.DeletableDO; +import cn.iocoder.mall.productservice.dal.mysql.dataobject.attr.ProductAttrValueDO; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import lombok.EqualsAndHashCode; @@ -29,8 +31,7 @@ public class ProductSkuDO extends DeletableDO { /** * 状态 * - * 1-正常 - * 2-禁用 + * 枚举 {@link CommonStatusEnum} */ private Integer status; /** @@ -38,7 +39,7 @@ public class ProductSkuDO extends DeletableDO { */ private String picUrl; /** - * 规格值({@link ProductAttrDO})数组 + * 规格值({@link ProductAttrValueDO#getId()})数组 * * 数组,以逗号分隔 */ diff --git a/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/mapper/attr/ProductAttrKeyMapper.java b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/mapper/attr/ProductAttrKeyMapper.java new file mode 100644 index 000000000..fba7c685e --- /dev/null +++ b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/mapper/attr/ProductAttrKeyMapper.java @@ -0,0 +1,10 @@ +package cn.iocoder.mall.productservice.dal.mysql.mapper.attr; + +import cn.iocoder.mall.productservice.dal.mysql.dataobject.attr.ProductAttrKeyDO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.springframework.stereotype.Repository; + +@Repository +public interface ProductAttrKeyMapper extends BaseMapper { + +} diff --git a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dao/attr/ProductAttrValueMapper.java b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/mapper/attr/ProductAttrValueMapper.java similarity index 57% rename from product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dao/attr/ProductAttrValueMapper.java rename to product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/mapper/attr/ProductAttrValueMapper.java index 466b73972..dd64788de 100644 --- a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dao/attr/ProductAttrValueMapper.java +++ b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/mapper/attr/ProductAttrValueMapper.java @@ -1,6 +1,6 @@ -package cn.iocoder.mall.product.biz.dao.attr; +package cn.iocoder.mall.productservice.dal.mysql.mapper.attr; -import cn.iocoder.mall.product.biz.dataobject.attr.ProductAttrValueDO; +import cn.iocoder.mall.productservice.dal.mysql.dataobject.attr.ProductAttrValueDO; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.springframework.stereotype.Repository; @@ -8,4 +8,4 @@ import org.springframework.stereotype.Repository; public interface ProductAttrValueMapper extends BaseMapper { -} \ No newline at end of file +} diff --git a/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/mapper/sku/ProductSkuMapper.java b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/mapper/sku/ProductSkuMapper.java new file mode 100644 index 000000000..fe3edbc7d --- /dev/null +++ b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/mapper/sku/ProductSkuMapper.java @@ -0,0 +1,21 @@ +package cn.iocoder.mall.productservice.dal.mysql.mapper.sku; + +import cn.iocoder.mall.mybatis.core.query.QueryWrapperX; +import cn.iocoder.mall.productservice.dal.mysql.dataobject.spu.ProductSkuDO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface ProductSkuMapper extends BaseMapper { + + default List selectListBySpuIdAndStatus(Integer spuId, Integer status) { + return selectList(new QueryWrapperX().eq("spu_id", spuId) + .eq("status", status)); + } + + void insertList(@Param("productSkuDOs") List productSkuDOs); + +} diff --git a/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/mapper/spu/ProductSpuMapper.java b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/mapper/spu/ProductSpuMapper.java index dadd89d0c..86e08cd4b 100644 --- a/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/mapper/spu/ProductSpuMapper.java +++ b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/dal/mysql/mapper/spu/ProductSpuMapper.java @@ -12,7 +12,8 @@ import org.springframework.stereotype.Repository; public interface ProductSpuMapper extends BaseMapper { default IPage selectPage(ProductSpuPageBO pageBO) { - QueryWrapperX query = new QueryWrapperX().likeIfPresent("name", pageBO.getName()); + QueryWrapperX query = new QueryWrapperX().likeIfPresent("name", pageBO.getName()) + .eqIfPresent("cid", pageBO.getCid()).eqIfPresent("visible", pageBO.getVisible()); // 库存过滤 if (pageBO.getHasQuantity() != null) { if (pageBO.getHasQuantity()) { diff --git a/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/manager/spu/ProductSpuManager.java b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/manager/spu/ProductSpuManager.java index 7cd5f8228..f6cb021e4 100644 --- a/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/manager/spu/ProductSpuManager.java +++ b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/manager/spu/ProductSpuManager.java @@ -1,17 +1,33 @@ package cn.iocoder.mall.productservice.manager.spu; +import cn.iocoder.common.framework.exception.util.ServiceExceptionUtil; import cn.iocoder.common.framework.vo.PageResult; import cn.iocoder.mall.productservice.convert.spu.ProductSpuConvert; -import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuCreateReqDTO; +import cn.iocoder.mall.productservice.enums.category.ProductCategoryIdEnum; +import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuAndSkuCreateReqDTO; import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuPageReqDTO; import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuRespDTO; import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuUpdateReqDTO; +import cn.iocoder.mall.productservice.service.attr.ProductAttrService; +import cn.iocoder.mall.productservice.service.attr.bo.ProductAttrKeyValueBO; +import cn.iocoder.mall.productservice.service.category.ProductCategoryService; +import cn.iocoder.mall.productservice.service.category.bo.ProductCategoryBO; +import cn.iocoder.mall.productservice.service.sku.ProductSkuService; +import cn.iocoder.mall.productservice.service.sku.bo.ProductSkuCreateOrUpdateBO; import cn.iocoder.mall.productservice.service.spu.ProductSpuService; import cn.iocoder.mall.productservice.service.spu.bo.ProductSpuBO; +import cn.iocoder.mall.productservice.service.spu.bo.ProductSpuCreateBO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import java.util.Comparator; +import java.util.HashSet; import java.util.List; +import java.util.Set; + +import static cn.iocoder.mall.productservice.enums.ProductErrorCodeConstants.PRODUCT_CATEGORY_NOT_EXISTS; +import static cn.iocoder.mall.productservice.enums.ProductErrorCodeConstants.PRODUCT_SPU_CATEGORY_MUST_BE_LEVEL2; /** * 商品 SPU Manager @@ -21,16 +37,46 @@ public class ProductSpuManager { @Autowired private ProductSpuService productSpuService; + @Autowired + private ProductSkuService productSkuService; + @Autowired + private ProductCategoryService productCategoryService; + @Autowired + private ProductAttrService productAttrService; /** - * 创建商品 SPU + * 创建商品 SPU 和 SKU * - * @param createDTO 创建商品 SPU DTO + * @param createDTO 创建商品 SPU 和 SKU DTO * @return 商品 SPU */ - public Integer createProductSpu(ProductSpuCreateReqDTO createDTO) { - ProductSpuBO productSpuBO = productSpuService.createProductSpu(ProductSpuConvert.INSTANCE.convert(createDTO)); - return productSpuBO.getId(); + @Transactional + public Integer createProductSpu(ProductSpuAndSkuCreateReqDTO createDTO) { + // 校验商品分类分类存在 + ProductCategoryBO categoryBO = productCategoryService.getProductCategory(createDTO.getCid()); + if (categoryBO == null) { + // 不存在 + throw ServiceExceptionUtil.exception(PRODUCT_CATEGORY_NOT_EXISTS); + } + if (ProductCategoryIdEnum.ROOT.getId().equals(categoryBO.getPid())) { + // 商品只能添加到二级分类下 + throw ServiceExceptionUtil.exception(PRODUCT_SPU_CATEGORY_MUST_BE_LEVEL2); + } + // 校验规格是否存在 + Set attrValueIds = new HashSet<>(); + createDTO.getSkus().forEach(productSkuAddDTO -> attrValueIds.addAll(productSkuAddDTO.getAttrValueIds())); + List attrKeyValueBOs = productAttrService.validProductAttr(attrValueIds, true); + // 创建商品 SKU 对象,并进行校验 + List skus = ProductSpuConvert.INSTANCE.convert(createDTO.getSkus()); + productSkuService.validProductSku(skus, attrKeyValueBOs); + // 插入商品 SPU 记录 + ProductSpuCreateBO spuCreateBO = ProductSpuConvert.INSTANCE.convert(createDTO).setSort(0); + spuCreateBO.setPrice(skus.stream().min(Comparator.comparing(ProductSkuCreateOrUpdateBO::getPrice)).get().getPrice()); // 求最小价格 + spuCreateBO.setQuantity(skus.stream().mapToInt(ProductSkuCreateOrUpdateBO::getQuantity).sum()); // 求库存之和 + ProductSpuBO spuBO = productSpuService.createProductSpu(spuCreateBO); + // 从插入商品 SKU 记录 + productSkuService.createProductSkus(spuBO.getId(), skus); + return spuBO.getId(); } /** @@ -71,7 +117,8 @@ public class ProductSpuManager { * @return 商品 SPU分页结果 */ public PageResult pageProductSpu(ProductSpuPageReqDTO pageDTO) { - PageResult pageResultBO = productSpuService.pageProductSpu(ProductSpuConvert.INSTANCE.convert(pageDTO)); + PageResult pageResultBO = productSpuService.pageProductSpu(ProductSpuConvert.INSTANCE.convert(pageDTO)); return ProductSpuConvert.INSTANCE.convertPage(pageResultBO); } + } diff --git a/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/rpc/spu/ProductSpuRpcImpl.java b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/rpc/spu/ProductSpuRpcImpl.java index cb289c1fd..983087723 100644 --- a/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/rpc/spu/ProductSpuRpcImpl.java +++ b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/rpc/spu/ProductSpuRpcImpl.java @@ -3,7 +3,7 @@ package cn.iocoder.mall.productservice.rpc.spu; import cn.iocoder.common.framework.vo.CommonResult; import cn.iocoder.common.framework.vo.PageResult; import cn.iocoder.mall.productservice.manager.spu.ProductSpuManager; -import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuCreateReqDTO; +import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuAndSkuCreateReqDTO; import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuPageReqDTO; import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuRespDTO; import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuUpdateReqDTO; @@ -24,7 +24,7 @@ public class ProductSpuRpcImpl implements ProductSpuRpc { private ProductSpuManager productSpuManager; @Override - public CommonResult createProductSpu(ProductSpuCreateReqDTO createDTO) { + public CommonResult createProductSpu(ProductSpuAndSkuCreateReqDTO createDTO) { return success(productSpuManager.createProductSpu(createDTO)); } diff --git a/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/service/attr/ProductAttrService.java b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/service/attr/ProductAttrService.java new file mode 100644 index 000000000..7bc877d96 --- /dev/null +++ b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/service/attr/ProductAttrService.java @@ -0,0 +1,64 @@ +package cn.iocoder.mall.productservice.service.attr; + +import cn.iocoder.common.framework.enums.CommonStatusEnum; +import cn.iocoder.common.framework.exception.util.ServiceExceptionUtil; +import cn.iocoder.common.framework.util.CollectionUtils; +import cn.iocoder.mall.productservice.dal.mysql.dataobject.attr.ProductAttrKeyDO; +import cn.iocoder.mall.productservice.dal.mysql.dataobject.attr.ProductAttrValueDO; +import cn.iocoder.mall.productservice.dal.mysql.mapper.attr.ProductAttrKeyMapper; +import cn.iocoder.mall.productservice.dal.mysql.mapper.attr.ProductAttrValueMapper; +import cn.iocoder.mall.productservice.service.attr.bo.ProductAttrKeyValueBO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import static cn.iocoder.mall.productservice.enums.ProductErrorCodeConstants.PRODUCT_ATTR_KEY_NOT_EXIST; +import static cn.iocoder.mall.productservice.enums.ProductErrorCodeConstants.PRODUCT_ATTR_VALUE_NOT_EXIST; + +@Service +public class ProductAttrService { + + @Autowired + private ProductAttrKeyMapper productAttrKeyMapper; + @Autowired + private ProductAttrValueMapper productAttrValueMapper; + + public List validProductAttr(Set productAttrValueIds, boolean validStatus) { + // 首先,校验规格 Value + List attrValues = productAttrValueMapper.selectBatchIds(productAttrValueIds); + if (attrValues.size() != productAttrValueIds.size()) { + throw ServiceExceptionUtil.exception(PRODUCT_ATTR_VALUE_NOT_EXIST); + } + if (validStatus) { + for (ProductAttrValueDO attrValue : attrValues) { // 同时,校验下状态 + if (CommonStatusEnum.DISABLE.getValue().equals(attrValue.getStatus())) { + throw ServiceExceptionUtil.exception(PRODUCT_ATTR_VALUE_NOT_EXIST); + } + } + } + // 然后,校验规 Key + Set attrKeyIds = CollectionUtils.convertSet(attrValues, ProductAttrValueDO::getAttrId); + List attrKeys = productAttrKeyMapper.selectBatchIds(attrKeyIds); + if (attrKeys.size() != attrKeyIds.size()) { + throw ServiceExceptionUtil.exception(PRODUCT_ATTR_KEY_NOT_EXIST); + } + if (validStatus) { + for (ProductAttrKeyDO attrKey : attrKeys) { // 同时,校验下状态 + if (CommonStatusEnum.DISABLE.getValue().equals(attrKey.getStatus())) { + throw ServiceExceptionUtil.exception(PRODUCT_ATTR_KEY_NOT_EXIST); + } + } + } + // 返回成功 + Map attrKeyMap = CollectionUtils.convertMap(attrKeys, ProductAttrKeyDO::getId, attrKeyDO -> attrKeyDO); // ProductAttrDO 的映射,方便查找。 + return attrValues.stream().map(attrValueDO -> new ProductAttrKeyValueBO() + .setAttrKeyId(attrValueDO.getAttrId()).setAttrKeyName(attrKeyMap.get(attrValueDO.getAttrId()).getName()) + .setAttrValueId(attrValueDO.getId()).setAttrValueName(attrValueDO.getName())) + .collect(Collectors.toList()); + } + +} diff --git a/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/service/attr/bo/ProductAttrKeyValueBO.java b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/service/attr/bo/ProductAttrKeyValueBO.java new file mode 100644 index 000000000..12c8b88c0 --- /dev/null +++ b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/service/attr/bo/ProductAttrKeyValueBO.java @@ -0,0 +1,32 @@ +package cn.iocoder.mall.productservice.service.attr.bo; + +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + * 商品规格键值对 BO + */ +@Data +@Accessors(chain = true) +public class ProductAttrKeyValueBO implements Serializable { + + /** + * 规格 Key 编号 + */ + private Integer attrKeyId; + /** + * 规格 Key 名字 + */ + private String attrKeyName; + /** + * 规格 Value 编号 + */ + private Integer attrValueId; + /** + * 规格 Value 名字 + */ + private String attrValueName; + +} diff --git a/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/service/sku/ProductSkuService.java b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/service/sku/ProductSkuService.java new file mode 100644 index 000000000..4eaebb8f9 --- /dev/null +++ b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/service/sku/ProductSkuService.java @@ -0,0 +1,74 @@ +package cn.iocoder.mall.productservice.service.sku; + +import cn.iocoder.common.framework.enums.CommonStatusEnum; +import cn.iocoder.common.framework.exception.util.ServiceExceptionUtil; +import cn.iocoder.mall.productservice.convert.sku.ProductSkuConvert; +import cn.iocoder.mall.productservice.dal.mysql.dataobject.spu.ProductSkuDO; +import cn.iocoder.mall.productservice.dal.mysql.mapper.sku.ProductSkuMapper; +import cn.iocoder.mall.productservice.service.attr.bo.ProductAttrKeyValueBO; +import cn.iocoder.mall.productservice.service.sku.bo.ProductSkuCreateOrUpdateBO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import static cn.iocoder.mall.productservice.enums.ProductErrorCodeConstants.*; + +@Service +public class ProductSkuService { + + @Autowired + private ProductSkuMapper productSkuMapper; + + public void createProductSkus(Integer spuId, List createBOs) { + List skus = ProductSkuConvert.INSTANCE.convertList(createBOs); + skus.forEach(sku -> { + sku.setStatus(CommonStatusEnum.ENABLE.getValue()); + sku.setSpuId(spuId); + }); + productSkuMapper.insertList(skus); + } + + public void updateProductSkus(Integer spuId, List createBOs) { + + } + + /** + * 校验 sku 是否合法 + * + * @param skuBOs 商品 SKU 添加信息 + * @param attrKeyValueBOs 商品规格明细数组 + */ + public void validProductSku(List skuBOs, List attrKeyValueBOs) { + // 创建 ProductAttrDetailBO 的映射。其中,KEY 为 ProductAttrDetailBO.attrValueId ,即规格值的编号 + Map productAttrDetailBOMap = attrKeyValueBOs.stream().collect( + Collectors.toMap(ProductAttrKeyValueBO::getAttrValueId, productAttrDetailBO -> productAttrDetailBO)); + // 1. 先校验,一个 Sku 下,没有重复的规格。校验方式是,遍历每个 Sku ,看看是否有重复的规格 attrId + for (ProductSkuCreateOrUpdateBO sku : skuBOs) { + Set attrIds = sku.getAttrValueIds().stream().map(attrValueId -> productAttrDetailBOMap.get(attrValueId).getAttrKeyId()) + .collect(Collectors.toSet()); + if (attrIds.size() != sku.getAttrValueIds().size()) { + throw ServiceExceptionUtil.exception(PRODUCT_SKU_ATTR_CANT_NOT_DUPLICATE); + } + } + // 2. 再校验,每个 Sku 的规格值的数量,是一致的。 + int attrValueIdsSize = skuBOs.get(0).getAttrValueIds().size(); + for (int i = 1; i < skuBOs.size(); i++) { + if (attrValueIdsSize != skuBOs.get(i).getAttrValueIds().size()) { + throw ServiceExceptionUtil.exception(PRODUCT_SPU_ATTR_NUMBERS_MUST_BE_EQUALS); + } + } + // 3. 最后校验,每个 Sku 之间不是重复的 + Set> skuAttrValues = new HashSet<>(); // 每个元素,都是一个 Sku 的 attrValueId 集合。这样,通过最外层的 Set ,判断是否有重复的. + for (ProductSkuCreateOrUpdateBO sku : skuBOs) { + if (!skuAttrValues.add(new HashSet<>(sku.getAttrValueIds()))) { // 添加失败,说明重复 + throw ServiceExceptionUtil.exception(PRODUCT_SPU_SKU_NOT_DUPLICATE); + } + } + } + +} diff --git a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/dto/ProductSkuAddOrUpdateDTO.java b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/service/sku/bo/ProductSkuCreateOrUpdateBO.java similarity index 75% rename from product/product-service-api/src/main/java/cn/iocoder/mall/product/api/dto/ProductSkuAddOrUpdateDTO.java rename to product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/service/sku/bo/ProductSkuCreateOrUpdateBO.java index a39a1f9b6..c6b3097fc 100644 --- a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/dto/ProductSkuAddOrUpdateDTO.java +++ b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/service/sku/bo/ProductSkuCreateOrUpdateBO.java @@ -1,4 +1,4 @@ -package cn.iocoder.mall.product.api.dto; +package cn.iocoder.mall.productservice.service.sku.bo; import lombok.Data; import lombok.experimental.Accessors; @@ -8,17 +8,19 @@ import javax.validation.constraints.NotNull; import java.util.List; /** - * 商品 Sku 添加 DTO + * 商品 SKU 创建或者修改 BO + * + * 注意,目前该对象是 */ @Data @Accessors(chain = true) -public class ProductSkuAddOrUpdateDTO { +public class ProductSkuCreateOrUpdateBO { /** * 规格值数组 */ @NotNull(message = "规格值数组不能为空") - private List attrs; + private List attrValueIds; /** * 价格,单位:分 */ diff --git a/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/service/spu/bo/ProductSpuPageBO.java b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/service/spu/bo/ProductSpuPageBO.java index 46444b261..0a0bf23a3 100644 --- a/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/service/spu/bo/ProductSpuPageBO.java +++ b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/service/spu/bo/ProductSpuPageBO.java @@ -17,6 +17,14 @@ public class ProductSpuPageBO extends PageParam { * SPU 名字 */ private String name; + /** + * 分类编号 + */ + private Integer cid; + /** + * 是否可见 + */ + private Boolean visible; /** * 是否有库存 */ diff --git a/product-service-project/product-service-app/src/main/resources/mapper/ProductSkuMapper.xml b/product-service-project/product-service-app/src/main/resources/mapper/ProductSkuMapper.xml new file mode 100644 index 000000000..884f67c8c --- /dev/null +++ b/product-service-project/product-service-app/src/main/resources/mapper/ProductSkuMapper.xml @@ -0,0 +1,17 @@ + + + + + + INSERT INTO product_sku ( + spu_id, status, pic_url, attrs, price, + quantity + ) VALUES + + (#{productSkuDO.spuId}, #{productSkuDO.status}, #{productSkuDO.picUrl}, #{productSkuDO.attrs}, #{productSkuDO.price}, + #{productSkuDO.quantity} + ) + + + + diff --git a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/bo/product/ProductAttrAndValuePairBO.java b/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/bo/product/ProductAttrAndValuePairBO.java deleted file mode 100644 index 2d0ec610b..000000000 --- a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/bo/product/ProductAttrAndValuePairBO.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.iocoder.mall.product.biz.bo.product; - -import lombok.Data; -import lombok.experimental.Accessors; - -import java.io.Serializable; - -/** - * 商品规格明细 BO - */ -@Data -@Accessors(chain = true) -public class ProductAttrAndValuePairBO implements Serializable { - - /** - * 规格编号 - */ - private Integer attrId; - /** - * 规格名 - */ - private String attrName; - /** - * 规格值 - */ - private Integer attrValueId; - /** - * 规格值名 - */ - private String attrValueName; - -} diff --git a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dao/attr/ProductAttrMapper.java b/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dao/attr/ProductAttrMapper.java deleted file mode 100644 index 0903da75b..000000000 --- a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dao/attr/ProductAttrMapper.java +++ /dev/null @@ -1,10 +0,0 @@ -package cn.iocoder.mall.product.biz.dao.attr; - -import cn.iocoder.mall.product.biz.dataobject.attr.ProductAttrDO; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import org.springframework.stereotype.Repository; - -@Repository -public interface ProductAttrMapper extends BaseMapper { - -} \ No newline at end of file diff --git a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dao/sku/ProductSpuMapper.java b/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dao/sku/ProductSpuMapper.java deleted file mode 100644 index 4b001141c..000000000 --- a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dao/sku/ProductSpuMapper.java +++ /dev/null @@ -1,11 +0,0 @@ -package cn.iocoder.mall.product.biz.dao.sku; - -import cn.iocoder.mall.product.biz.dataobject.spu.ProductSpuDO; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import org.springframework.stereotype.Repository; - -@Repository -public interface ProductSpuMapper extends BaseMapper { - - -} diff --git a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dataobject/attr/ProductAttrDO.java b/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dataobject/attr/ProductAttrDO.java deleted file mode 100644 index c9e8469b6..000000000 --- a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dataobject/attr/ProductAttrDO.java +++ /dev/null @@ -1,30 +0,0 @@ -package cn.iocoder.mall.product.biz.dataobject.attr; - -import cn.iocoder.mall.mybatis.core.dataobject.DeletableDO; -import lombok.Data; -import lombok.experimental.Accessors; - -/** - * Product 规格 - */ -@Data -@Accessors(chain = true) -public class ProductAttrDO extends DeletableDO { - - /** - * 规格编号 - */ - private Integer id; - /** - * 名称 - */ - private String name; - /** - * 状态 - * - * 1-开启 - * 2-禁用 - */ - private Integer status; - -} diff --git a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/product/ProductSkuAddOrUpdateDTO.java b/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/product/ProductSkuAddOrUpdateDTO.java deleted file mode 100644 index b497b3c58..000000000 --- a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/product/ProductSkuAddOrUpdateDTO.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.mall.product.biz.dto.product; - -import lombok.Data; -import lombok.experimental.Accessors; - -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import java.util.List; - -/** - * 商品 Sku 添加 DTO - */ -@Data -@Accessors(chain = true) -public class ProductSkuAddOrUpdateDTO { - - /** - * 规格值数组 - */ - @NotNull(message = "规格值数组不能为空") - private List attrs; - /** - * 价格,单位:分 - */ - @NotNull(message = "价格不能为空") - @Min(value = 1L, message = "最小价格为 1") - private Integer price; - /** - * 库存数量 - */ - @NotNull(message = "库存数量不能为空") - @Min(value = 1L, message = "最小库存为 1") - private Integer quantity; - -} diff --git a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/product/ProductSpuAddDTO.java b/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/product/ProductSpuAddDTO.java deleted file mode 100644 index f03aa9c8c..000000000 --- a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/product/ProductSpuAddDTO.java +++ /dev/null @@ -1,62 +0,0 @@ -package cn.iocoder.mall.product.biz.dto.product; - -import lombok.Data; -import lombok.experimental.Accessors; - -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import java.util.List; - -/** - * 商品 SPU + SKU 添加 DTO - */ -@Data -@Accessors(chain = true) -public class ProductSpuAddDTO { - - // ========== 基本信息 ========= - /** - * SPU 名字 - */ - @NotEmpty(message = "SPU 名字不能为空") - private String name; - /** - * 卖点 - */ - @NotEmpty(message = "卖点不能为空") - private String sellPoint; - /** - * 描述 - */ - @NotEmpty(message = "描述不能为空") - private String description; - /** - * 分类编号 - */ - @NotNull(message = "分类不能为空") - private Integer cid; - /** - * 商品主图地址 - */ - @NotNull(message = "商品主图不能为空") - private List picUrls; - - // ========== 其他信息 ========= - /** - * 是否上架商品(是否可见)。 - * - * true 为已上架 - * false 为已下架 - */ - @NotNull(message = "是否上架不能为空") - private Boolean visible; - - // ========== SKU ========= - - /** - * SKU 数组 - */ - @NotNull(message = "SKU 不能为空") - private List skus; - -} diff --git a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/sku/ProductSkuAddOrUpdateDTO.java b/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/sku/ProductSkuAddOrUpdateDTO.java deleted file mode 100644 index 42a88e8b3..000000000 --- a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/sku/ProductSkuAddOrUpdateDTO.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.mall.product.biz.dto.sku; - -import lombok.Data; -import lombok.experimental.Accessors; - -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import java.util.List; - -/** - * 商品 Sku 添加 DTO - */ -@Data -@Accessors(chain = true) -public class ProductSkuAddOrUpdateDTO { - - /** - * 规格值数组 - */ - @NotNull(message = "规格值数组不能为空") - private List attrs; - /** - * 价格,单位:分 - */ - @NotNull(message = "价格不能为空") - @Min(value = 1L, message = "最小价格为 1") - private Integer price; - /** - * 库存数量 - */ - @NotNull(message = "库存数量不能为空") - @Min(value = 1L, message = "最小库存为 1") - private Integer quantity; - -} diff --git a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/sku/ProductSpuAddDTO.java b/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/sku/ProductSpuAddDTO.java deleted file mode 100644 index 7543dcf6b..000000000 --- a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/sku/ProductSpuAddDTO.java +++ /dev/null @@ -1,63 +0,0 @@ -package cn.iocoder.mall.product.biz.dto.sku; - -import lombok.Data; -import lombok.experimental.Accessors; - -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import java.util.List; - -/** - * 商品 SPU + SKU 添加 DTO - */ -@Data -@Accessors(chain = true) -// TODO FROM 芋艿 to sunderui && q2118cs:貌似重复了,只要保留一个哈 -public class ProductSpuAddDTO { - - // ========== 基本信息 ========= - /** - * SPU 名字 - */ - @NotEmpty(message = "SPU 名字不能为空") - private String name; - /** - * 卖点 - */ - @NotEmpty(message = "卖点不能为空") - private String sellPoint; - /** - * 描述 - */ - @NotEmpty(message = "描述不能为空") - private String description; - /** - * 分类编号 - */ - @NotNull(message = "分类不能为空") - private Integer cid; - /** - * 商品主图地址 - */ - @NotNull(message = "商品主图不能为空") - private List picUrls; - - // ========== 其他信息 ========= - /** - * 是否上架商品(是否可见)。 - * - * true 为已上架 - * false 为已下架 - */ - @NotNull(message = "是否上架不能为空") - private Boolean visible; - - // ========== SKU ========= - - /** - * SKU 数组 - */ - @NotNull(message = "SKU 不能为空") - private List skus; - -} diff --git a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/sku/ProductSpuUpdateDTO.java b/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/sku/ProductSpuUpdateDTO.java deleted file mode 100644 index 1bf191478..000000000 --- a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/sku/ProductSpuUpdateDTO.java +++ /dev/null @@ -1,69 +0,0 @@ -package cn.iocoder.mall.product.biz.dto.sku; - -import cn.iocoder.mall.product.biz.dto.product.ProductSkuAddOrUpdateDTO; -import lombok.Data; -import lombok.experimental.Accessors; - -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import java.util.List; - -/** - * 商品 SPU + SKU 更新 DTO - */ -@Data -@Accessors(chain = true) -public class ProductSpuUpdateDTO { - - /** - * Spu 编号 - */ - @NotNull(message = "SPU 编号不能为空") - private Integer id; - - // ========== 基本信息 ========= - /** - * SPU 名字 - */ - @NotEmpty(message = "SPU 名字不能为空") - private String name; - /** - * 卖点 - */ - @NotEmpty(message = "卖点不能为空") - private String sellPoint; - /** - * 描述 - */ - @NotEmpty(message = "描述不能为空") - private String description; - /** - * 分类编号 - */ - @NotNull(message = "分类不能为空") - private Integer cid; - /** - * 商品主图地址 - */ - @NotNull(message = "商品主图不能为空") - private List picUrls; - - // ========== 其他信息 ========= - /** - * 是否上架商品(是否可见)。 - * - * true 为已上架 - * false 为已下架 - */ - @NotNull(message = "是否上架不能为空") - private Boolean visible; - - // ========== SKU ========= - - /** - * SKU 数组 - */ - @NotNull(message = "SKU 不能为空") - private List skus; - -} diff --git a/product/product-biz/src/main/resources/mapper/ProductSpuMapper.xml b/product/product-biz/src/main/resources/mapper/ProductSpuMapper.xml deleted file mode 100644 index c6f19b77c..000000000 --- a/product/product-biz/src/main/resources/mapper/ProductSpuMapper.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/ProductSpuService.java b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/ProductSpuService.java index 68f3ae6c2..2082b1f27 100644 --- a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/ProductSpuService.java +++ b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/ProductSpuService.java @@ -22,8 +22,6 @@ public interface ProductSpuService { */ List getProductSpuDetailListForSync(Integer lastId, Integer limit); - ProductSpuPageBO getProductSpuPage(ProductSpuPageDTO productSpuPageDTO); - List getProductSpuSearchList(ProductSpuSearchListDTO productSpuSearchListDTO); List getProductSpuList(Collection ids); diff --git a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductAttrAndValuePairBO.java b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductAttrAndValuePairBO.java deleted file mode 100644 index 3faa888aa..000000000 --- a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductAttrAndValuePairBO.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.iocoder.mall.product.api.bo; - -import lombok.Data; -import lombok.experimental.Accessors; - -import java.io.Serializable; - -/** - * 商品规格明细 BO - */ -@Data -@Accessors(chain = true) -public class ProductAttrAndValuePairBO implements Serializable { - - /** - * 规格编号 - */ - private Integer attrId; - /** - * 规格名 - */ - private String attrName; - /** - * 规格值 - */ - private Integer attrValueId; - /** - * 规格值名 - */ - private String attrValueName; - -} diff --git a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductSpuBO.java b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductSpuBO.java deleted file mode 100644 index 8f442e4d0..000000000 --- a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductSpuBO.java +++ /dev/null @@ -1,74 +0,0 @@ -package cn.iocoder.mall.product.api.bo; - -import lombok.Data; -import lombok.experimental.Accessors; - -import java.io.Serializable; -import java.util.List; - -/** - * 商品 SPU BO - */ -@Data -@Accessors(chain = true) -public class ProductSpuBO implements Serializable { - - /** - * SPU 编号 - */ - private Integer id; - - // ========== 基本信息 ========= - /** - * SPU 名字 - */ - private String name; - /** - * 卖点 - */ - private String sellPoint; - /** - * 描述 - */ - private String description; - /** - * 分类编号 - */ - private Integer cid; - /** - * 商品主图地址 - * - * 数组,以逗号分隔 - * - * 建议尺寸:800*800像素,你可以拖拽图片调整顺序,最多上传15张 - */ - private List picUrls; - - // ========== 其他信息 ========= - /** - * 是否上架商品(是否可见)。 - * - * true 为已上架 - * false 为已下架 - */ - private Boolean visible; - /** - * 排序字段 - */ - private Integer sort; - - // ========== Sku 相关字段 ========= - /** - * 价格 - * - * 目前的计算方式是,以 Sku 最小价格为准 - */ - private Integer price; - /** - * 库存数量 - * - * 目前的计算方式是,以 Sku 库存累加为准 - */ - private Integer quantity; - -} diff --git a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductSpuPageBO.java b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductSpuPageBO.java deleted file mode 100644 index c969b94fd..000000000 --- a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductSpuPageBO.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.iocoder.mall.product.api.bo; - -import lombok.Data; -import lombok.experimental.Accessors; - -import java.io.Serializable; -import java.util.List; - -/** - * 商品 SPU 分页 BO - */ -@Data -@Accessors(chain = true) -public class ProductSpuPageBO implements Serializable { - - /** - * Spu 数组 - */ - private List list; - /** - * 总量 - */ - private Integer total; - -} diff --git a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/dto/ProductSpuAddDTO.java b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/dto/ProductSpuAddDTO.java deleted file mode 100644 index b2150b25e..000000000 --- a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/dto/ProductSpuAddDTO.java +++ /dev/null @@ -1,62 +0,0 @@ -package cn.iocoder.mall.product.api.dto; - -import lombok.Data; -import lombok.experimental.Accessors; - -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import java.util.List; - -/** - * 商品 SPU + SKU 添加 DTO - */ -@Data -@Accessors(chain = true) -public class ProductSpuAddDTO { - - // ========== 基本信息 ========= - /** - * SPU 名字 - */ - @NotEmpty(message = "SPU 名字不能为空") - private String name; - /** - * 卖点 - */ - @NotEmpty(message = "卖点不能为空") - private String sellPoint; - /** - * 描述 - */ - @NotEmpty(message = "描述不能为空") - private String description; - /** - * 分类编号 - */ - @NotNull(message = "分类不能为空") - private Integer cid; - /** - * 商品主图地址 - */ - @NotNull(message = "商品主图不能为空") - private List picUrls; - - // ========== 其他信息 ========= - /** - * 是否上架商品(是否可见)。 - * - * true 为已上架 - * false 为已下架 - */ - @NotNull(message = "是否上架不能为空") - private Boolean visible; - - // ========== SKU ========= - - /** - * SKU 数组 - */ - @NotNull(message = "SKU 不能为空") - private List skus; - -} diff --git a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/dto/ProductSpuPageDTO.java b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/dto/ProductSpuPageDTO.java deleted file mode 100644 index 0893adb9e..000000000 --- a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/dto/ProductSpuPageDTO.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.iocoder.mall.product.api.dto; - -import lombok.Data; -import lombok.experimental.Accessors; - -import javax.validation.constraints.NotNull; - -/** - * 商品 Spu 分页 DTO - */ -@Data -@Accessors(chain = true) -public class ProductSpuPageDTO { - - /** - * 商品名 - * - * 模糊匹配 - */ - private String name; - /** - * 分类编号 - */ - private Integer cid; - /** - * 是否可见 - */ - private Boolean visible; - /** - * 是否有库存 - * - * 允许为空。空时,不进行筛选 - */ - private Boolean hasQuantity; - - @NotNull(message = "页码不能为空") - private Integer pageNo; - @NotNull(message = "每页条数不能为空") - private Integer pageSize; - -} diff --git a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dao/ProductSpuMapper.java b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dao/ProductSpuMapper.java index 07867572c..9341be8a3 100644 --- a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dao/ProductSpuMapper.java +++ b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dao/ProductSpuMapper.java @@ -10,10 +10,6 @@ import java.util.List; @Repository public interface ProductSpuMapper { - ProductSpuDO selectById(Integer id); - - List selectByIds(@Param("ids") Collection ids); - /** * 获得大于 id 的商品编号数组 * @@ -24,21 +20,4 @@ public interface ProductSpuMapper { List selectIdListByIdGt(@Param("id") Integer id, @Param("limit") Integer limit); - void insert(ProductSpuDO productSpuDO); - - void update(ProductSpuDO productSpuDO); - - // TODO 芋艿,需要捉摸下,怎么优化下。参数有点多 - List selectListByNameLikeOrderBySortAsc(@Param("name") String name, - @Param("cid") Integer cid, - @Param("visible") Boolean visible, - @Param("hasQuantity") Boolean hasQuantity, - @Param("offset") Integer offset, - @Param("limit") Integer limit); - - Integer selectCountByNameLike(@Param("name") String name, - @Param("cid") Integer cid, - @Param("hasQuantity") Boolean hasQuantity, - @Param("visible") Boolean visible); - } diff --git a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductAttrServiceImpl.java b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductAttrServiceImpl.java index 504b783a6..8e7870f1b 100644 --- a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductAttrServiceImpl.java +++ b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductAttrServiceImpl.java @@ -35,39 +35,6 @@ public class ProductAttrServiceImpl implements ProductAttrService { @Autowired private ProductAttrValueMapper productAttrValueMapper; - public List validProductAttrAndValue(Set productAttrValueIds, boolean validStatus) { - // 首先,校验规格值 - List attrValues = productAttrValueMapper.selectListByIds(productAttrValueIds); - if (attrValues.size() != productAttrValueIds.size()) { - throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_ATTR_VALUE_NOT_EXIST.getCode()); - } - if (validStatus) { - for (ProductAttrValueDO attrValue : attrValues) { // 同时,校验下状态 - if (ProductAttrConstants.ATTR_STATUS_DISABLE.equals(attrValue.getStatus())) { - throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_ATTR_VALUE_NOT_EXIST.getCode()); - } - } - } - // 然后,校验规格 - Set attrIds = attrValues.stream().map(ProductAttrValueDO::getAttrId).collect(Collectors.toSet()); - List attrs = productAttrMapper.selectListByIds(attrIds); - if (attrs.size() != attrIds.size()) { - throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_ATTR_NOT_EXIST.getCode()); - } - if (validStatus) { - for (ProductAttrDO attr : attrs) { // 同时,校验下状态 - if (ProductAttrConstants.ATTR_VALUE_STATUS_DISABLE.equals(attr.getStatus())) { - throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_ATTR_NOT_EXIST.getCode()); - } - } - } - // 返回成功 - Map attrMap = attrs.stream().collect(Collectors.toMap(ProductAttrDO::getId, productAttrDO -> productAttrDO)); // ProductAttrDO 的映射,方便查找。 - return attrValues.stream().map(productAttrValueDO -> new ProductAttrAndValuePairBO() - .setAttrId(productAttrValueDO.getAttrId()).setAttrName(attrMap.get(productAttrValueDO.getAttrId()).getName()) - .setAttrValueId(productAttrValueDO.getId()).setAttrValueName(productAttrValueDO.getName())).collect(Collectors.toList()); - } - @Override public ProductAttrPageBO getProductAttrPage(ProductAttrPageDTO productAttrPageDTO) { ProductAttrPageBO productAttrPageBO = new ProductAttrPageBO(); diff --git a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductSpuServiceImpl.java b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductSpuServiceImpl.java index 72e251b74..f5a021890 100644 --- a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductSpuServiceImpl.java +++ b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductSpuServiceImpl.java @@ -96,45 +96,6 @@ public class ProductSpuServiceImpl implements ProductSpuService { return productSpuDetailBO; } - @SuppressWarnings("Duplicates") - @Transactional - public ProductSpuDetailBO addProductSpu0(Integer adminId, ProductSpuAddDTO productSpuAddDTO) { - // 校验商品分类分类存在 - ProductCategoryDO category = productCategoryService.validProductCategory(productSpuAddDTO.getCid()); - if (ProductCategoryConstants.PID_ROOT.equals(category.getPid())) { // 商品只能添加到二级分类下 - throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_SPU_CATEGORY_MUST_BE_LEVEL2.getCode()); - } - // 校验规格是否存在 - Set productAttrValueIds = new HashSet<>(); - productSpuAddDTO.getSkus().forEach(productSkuAddDTO -> productAttrValueIds.addAll(productSkuAddDTO.getAttrs())); - List attrAndValuePairList = productAttrService.validProductAttrAndValue(productAttrValueIds - , true); // 读取规格时,需要考虑规格是否被禁用 - // 保存 Spu - ProductSpuDO spu = ProductSpuConvert.INSTANCE.convert(productSpuAddDTO) - .setPicUrls(StringUtil.join(productSpuAddDTO.getPicUrls(), ",")) - .setSort(0); // 排序为 0 - spu.setCreateTime(new Date()); - spu.setDeleted(DeletedStatusEnum.DELETED_NO.getValue()); - initSpuFromSkus(spu, productSpuAddDTO.getSkus()); // 初始化 sku 相关信息到 spu 中 - productSpuMapper.insert(spu); - // 保存 Sku - List skus = productSpuAddDTO.getSkus().stream().map(productSkuAddDTO -> { - ProductSkuDO sku = ProductSpuConvert.INSTANCE.convert(productSkuAddDTO) - .setSpuId(spu.getId()) - .setStatus(ProductSpuConstants.SKU_STATUS_ENABLE) - .setAttrs(StringUtil.join(productSkuAddDTO.getAttrs(), ",")); - sku.setCreateTime(new Date()); - sku.setDeleted(DeletedStatusEnum.DELETED_NO.getValue()); - return sku; - }).collect(Collectors.toList()); - // 校验 Sku 规格 - validProductSku(productSpuAddDTO.getSkus(), attrAndValuePairList); - // 插入 SKU 到数据库 - productSkuMapper.insertList(skus); - // 返回成功 - return ProductSpuConvert.INSTANCE.convert2(spu, skus, attrAndValuePairList, category); - } - @Override public void updateProductSpu(Integer adminId, ProductSpuUpdateDTO productSpuUpdateDTO) { // 更新商品 @@ -276,43 +237,6 @@ public class ProductSpuServiceImpl implements ProductSpuService { return ProductSpuConvert.INSTANCE.convert3(skus, spus, attrAndValuePairList); } - /** - * 校验 sku 是否合法 - * - * @param productSkuAddDTOs sku 添加或修改信息 - * @param productAttrDetailBOs 商品规格明细数组 - * @return 是否校验通过 - */ - private Boolean validProductSku(List productSkuAddDTOs, List productAttrDetailBOs) { - // 创建 ProductAttrDetailBO 的映射。其中,KEY 为 ProductAttrDetailBO.attrValueId ,即规格值的编号 - Map productAttrDetailBOMap = productAttrDetailBOs.stream().collect( - Collectors.toMap(ProductAttrAndValuePairBO::getAttrValueId, productAttrDetailBO -> productAttrDetailBO)); - // 1. 先校验,一个 Sku 下,没有重复的规格。校验方式是,遍历每个 Sku ,看看是否有重复的规格 attrId - for (ProductSkuAddOrUpdateDTO sku : productSkuAddDTOs) { - Set attrIds = sku.getAttrs().stream().map(attrValueId -> productAttrDetailBOMap.get(attrValueId).getAttrId()) - .collect(Collectors.toSet()); - if (attrIds.size() != sku.getAttrs().size()) { - throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_SKU_ATTR_CANT_NOT_DUPLICATE.getCode()); - } - } - // 2. 再校验,每个 Sku 的规格值的数量,是一致的。 - int attrSize = productSkuAddDTOs.get(0).getAttrs().size(); - for (int i = 1; i < productSkuAddDTOs.size(); i++) { - if (attrSize != productSkuAddDTOs.get(i).getAttrs().size()) { - throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_SPU_ATTR_NUMBERS_MUST_BE_EQUALS.getCode()); - } - } - // 3. 最后校验,每个 Sku 之间不是重复的 - Set> skuAttrValues = new HashSet<>(); // 每个元素,都是一个 Sku 的 attrValueId 集合。这样,通过最外层的 Set ,判断是否有重复的. - for (ProductSkuAddOrUpdateDTO sku : productSkuAddDTOs) { - if (!skuAttrValues.add(new HashSet<>(sku.getAttrs()))) { // 添加失败,说明重复 - throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_SPU_SKU__NOT_DUPLICATE.getCode()); - } - } - // 校验通过 - return true; - } - /** * 获得 sku 数组中,指定规格的 sku * @@ -335,18 +259,6 @@ public class ProductSpuServiceImpl implements ProductSpuService { return null; } - /** - * 根据 sku 数组,计算相关的字段到 spu 中。 - * - * @param spu spu - * @param skus sku 数组 - */ - private void initSpuFromSkus(ProductSpuDO spu, List skus) { - assert skus.size() > 0; // 写个断言,避免下面警告 - spu.setPrice(skus.stream().min(Comparator.comparing(ProductSkuAddOrUpdateDTO::getPrice)).get().getPrice()); // 求最小价格 - spu.setQuantity(skus.stream().mapToInt(ProductSkuAddOrUpdateDTO::getQuantity).sum()); // 求库存之和 - } - private boolean sendProductUpdateMessage(Integer id) { // 创建 Message 对象 ProductUpdateMessage message = new ProductUpdateMessage().setId(id); diff --git a/product/product-service-impl/src/main/resources/mapper/ProductSpuMapper.xml b/product/product-service-impl/src/main/resources/mapper/ProductSpuMapper.xml index 2cc42f204..16ea54419 100644 --- a/product/product-service-impl/src/main/resources/mapper/ProductSpuMapper.xml +++ b/product/product-service-impl/src/main/resources/mapper/ProductSpuMapper.xml @@ -8,25 +8,6 @@ create_time - - - - - - INSERT INTO product_spu ( - name, sell_point, description, cid, pic_urls, - visible, sort, price, quantity, - deleted, create_time - ) VALUES ( - #{name}, #{sellPoint}, #{description}, #{cid}, #{picUrls}, - #{visible}, #{sort}, #{price}, #{quantity}, - #{deleted}, #{createTime} - ) - - - - UPDATE product_spu - - - name = #{name}, - - - sell_point = #{sellPoint}, - - - description = #{description}, - - - cid = #{cid}, - - - pic_urls = #{picUrls}, - - - visible = #{visible}, - - - price = #{price}, - - - quantity = #{quantity}, - - - sort = #{sort}, - - - deleted = #{deleted} - - - WHERE id = #{id} - - - - - - diff --git a/product/product-service-impl/src/main/resources/mapper/UserProductSpuCollectionsMapper.xml b/product/product-service-impl/src/main/resources/mapper/UserProductSpuCollectionsMapper.xml deleted file mode 100644 index 695710fa2..000000000 --- a/product/product-service-impl/src/main/resources/mapper/UserProductSpuCollectionsMapper.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - id, user_id, nickname, spu_id, spu_name, - spu_image,sell_point,price, create_time, update_time, - deleted - - - - - - - - - - diff --git a/product/product-service-impl/src/main/resources/mybatis-config.xml b/product/product-service-impl/src/main/resources/mybatis-config.xml deleted file mode 100644 index 7f604cc7e..000000000 --- a/product/product-service-impl/src/main/resources/mybatis-config.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file