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 28683ca7e..00d3c8f3c 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 @@ -18,6 +18,34 @@ 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 +name=测试商品标题&description=测试商品描述&cid=637&sellPoint=丑&picUrls=1,2,3&visible=true +&skus[0].price=1&skus[0].quantity=100&skus[0].attrValueIds=1,3 +&skus[1].price=2&skus[1].quantity=50&skus[1].attrValueIds=2,4 + +### /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,0 + +### /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 +&skus[1].price=2&skus[1].quantity=50&skus[1].attrValueIds=1,2,4 + +### /product-spu/update 成功 +POST {{baseUrl}}/product-spu/update +Content-Type: application/x-www-form-urlencoded +Authorization: Bearer {{accessToken}} + +id=59&name=测试商品标题&description=测试商品描述&cid=637&sellPoint=丑&picUrls=1,2,3&visible=true +&skus[0].price=1&skus[0].quantity=100&skus[0].attrValueIds=1,3 +&skus[1].price=2&skus[1].quantity=50&skus[1].attrValueIds=2,4 ### 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 63846171a..dc9f34d2c 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 @@ -46,14 +46,14 @@ public class ProductSpuController { @GetMapping("/get") @ApiOperation("获得商品 SPU") - @ApiImplicitParam(name = "productSpuId", value = "商品 SPU编号", required = true) + @ApiImplicitParam(name = "productSpuId", value = "商品 SPU 编号", required = true) public CommonResult getProductSpu(@RequestParam("productSpuId") Integer productSpuId) { return success(productSpuManager.getProductSpu(productSpuId)); } @GetMapping("/list") @ApiOperation("获得商品 SPU 列表") - @ApiImplicitParam(name = "productSpuIds", value = "商品 SPU编号列表", required = true) + @ApiImplicitParam(name = "productSpuIds", value = "商品 SPU 编号列表", required = true) public CommonResult> listProductSpus(@RequestParam("productSpuIds") List productSpuIds) { return success(productSpuManager.listProductSpus(productSpuIds)); } 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 9f0b506f1..a194eb3ef 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 @@ -42,22 +42,22 @@ public class ProductSpuCreateReqVO { } - @ApiModelProperty(value = "SPU 名字", required = true) + @ApiModelProperty(value = "SPU 名字", required = true, example = "芋艿") @NotEmpty(message = "SPU 名字不能为空") private String name; - @ApiModelProperty(value = "卖点", required = true) + @ApiModelProperty(value = "卖点", required = true, example = "好吃好玩") @NotEmpty(message = "卖点不能为空") private String sellPoint; - @ApiModelProperty(value = "描述", required = true) + @ApiModelProperty(value = "描述", required = true, example = "我是哈哈哈") @NotEmpty(message = "描述不能为空") private String description; - @ApiModelProperty(value = "分类编号", required = true) + @ApiModelProperty(value = "分类编号", required = true, example = "1") @NotNull(message = "分类编号不能为空") private Integer cid; - @ApiModelProperty(value = "商品主图地址", required = true) + @ApiModelProperty(value = "商品主图地址", required = true, example = "http://www.iocoder.cn/xxx.jpg", notes = "多个之间,使用逗号分隔") @NotEmpty(message = "商品主图地址不能为空") private List picUrls; - @ApiModelProperty(value = "是否上架商品", required = true) + @ApiModelProperty(value = "是否上架商品", required = true, example = "true") @NotNull(message = "是否上架商品不能为空") private Boolean visible; diff --git a/management-web-app/src/main/java/cn/iocoder/mall/managementweb/controller/product/vo/spu/ProductSpuRespVO.java b/management-web-app/src/main/java/cn/iocoder/mall/managementweb/controller/product/vo/spu/ProductSpuRespVO.java index 5e4e94d13..a7e1a0e28 100644 --- a/management-web-app/src/main/java/cn/iocoder/mall/managementweb/controller/product/vo/spu/ProductSpuRespVO.java +++ b/management-web-app/src/main/java/cn/iocoder/mall/managementweb/controller/product/vo/spu/ProductSpuRespVO.java @@ -10,27 +10,25 @@ public class ProductSpuRespVO { @ApiModelProperty(value = "SPU 编号", required = true) private Integer id; - @ApiModelProperty(value = "SPU 名字", required = true) + @ApiModelProperty(value = "SPU 名字", required = true, example = "芋艿") private String name; - @ApiModelProperty(value = "卖点", required = true) + @ApiModelProperty(value = "卖点", required = true, example = "好吃好玩") private String sellPoint; - @ApiModelProperty(value = "描述", required = true) + @ApiModelProperty(value = "描述", required = true, example = "我是哈哈哈") private String description; - @ApiModelProperty(value = "分类编号", required = true) + @ApiModelProperty(value = "分类编号", required = true, example = "1") private Integer cid; - @ApiModelProperty(value = "商品主图地址", required = true) + @ApiModelProperty(value = "商品主图地址", required = true, example = "http://www.iocoder.cn/xxx.jpg", notes = "多个之间,使用逗号分隔") private List picUrls; - @ApiModelProperty(value = "是否上架商品", required = true) + @ApiModelProperty(value = "是否上架商品", required = true, example = "true") private Boolean visible; - @ApiModelProperty(value = "排序字段", required = true) + @ApiModelProperty(value = "排序字段", required = true, example = "1024") private Integer sort; - @ApiModelProperty(value = "价格", required = true) + @ApiModelProperty(value = "价格", required = true, example = "233", notes = "单位:分") private Integer price; - @ApiModelProperty(value = "库存数量", required = true) + @ApiModelProperty(value = "库存数量", required = true, example = "1024") private Integer quantity; @ApiModelProperty(value = "创建时间", required = true) private Date createTime; - @ApiModelProperty(value = "最后更新时间", required = true) - private Date updateTime; } diff --git a/management-web-app/src/main/java/cn/iocoder/mall/managementweb/controller/product/vo/spu/ProductSpuUpdateReqVO.java b/management-web-app/src/main/java/cn/iocoder/mall/managementweb/controller/product/vo/spu/ProductSpuUpdateReqVO.java index 985b4bae1..7f3f8be48 100644 --- a/management-web-app/src/main/java/cn/iocoder/mall/managementweb/controller/product/vo/spu/ProductSpuUpdateReqVO.java +++ b/management-web-app/src/main/java/cn/iocoder/mall/managementweb/controller/product/vo/spu/ProductSpuUpdateReqVO.java @@ -3,44 +3,75 @@ 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 ProductSpuUpdateReqVO { + /** + * 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) @NotNull(message = "SPU 编号不能为空") private Integer id; - @ApiModelProperty(value = "SPU 名字", required = true) + + @ApiModelProperty(value = "SPU 名字", required = true, example = "芋艿") @NotEmpty(message = "SPU 名字不能为空") private String name; - @ApiModelProperty(value = "卖点", required = true) + @ApiModelProperty(value = "卖点", required = true, example = "好吃好玩") @NotEmpty(message = "卖点不能为空") private String sellPoint; - @ApiModelProperty(value = "描述", required = true) + @ApiModelProperty(value = "描述", required = true, example = "我是哈哈哈") @NotEmpty(message = "描述不能为空") private String description; - @ApiModelProperty(value = "分类编号", required = true) + @ApiModelProperty(value = "分类编号", required = true, example = "1") @NotNull(message = "分类编号不能为空") private Integer cid; - @ApiModelProperty(value = "商品主图地址", required = true) + @ApiModelProperty(value = "商品主图地址", required = true, example = "http://www.iocoder.cn/xxx.jpg", notes = "多个之间,使用逗号分隔") @NotEmpty(message = "商品主图地址不能为空") private List picUrls; - @ApiModelProperty(value = "是否上架商品", required = true) + @ApiModelProperty(value = "是否上架商品", required = true, example = "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/convert/product/ProductSpuConvert.java b/management-web-app/src/main/java/cn/iocoder/mall/managementweb/convert/product/ProductSpuConvert.java index 4b731c399..ec943e223 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 @@ -6,9 +6,9 @@ import cn.iocoder.mall.managementweb.controller.product.vo.spu.ProductSpuPageReq 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.ProductSpuAndSkuCreateReqDTO; +import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuAndSkuUpdateReqDTO; 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 org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @@ -21,7 +21,7 @@ public interface ProductSpuConvert { ProductSpuAndSkuCreateReqDTO convert(ProductSpuCreateReqVO bean); - ProductSpuUpdateReqDTO convert(ProductSpuUpdateReqVO bean); + ProductSpuAndSkuUpdateReqDTO convert(ProductSpuUpdateReqVO bean); ProductSpuRespVO convert(ProductSpuRespDTO bean); diff --git a/order/order-application/pom.xml b/order/order-application/pom.xml deleted file mode 100644 index 2f80d4ffb..000000000 --- a/order/order-application/pom.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - order - cn.iocoder.mall - 1.0-SNAPSHOT - - 4.0.0 - - order-application - - - - - cn.iocoder.mall - order-rest - 1.0-SNAPSHOT - - - cn.iocoder.mall - order-rpc - 1.0-SNAPSHOT - - - - - - diff --git a/order/order-application/src/main/java/cn/iocoder/mall/order/application/OrderApplication.java b/order/order-application/src/main/java/cn/iocoder/mall/order/application/OrderApplication.java deleted file mode 100644 index 5187d889e..000000000 --- a/order/order-application/src/main/java/cn/iocoder/mall/order/application/OrderApplication.java +++ /dev/null @@ -1,51 +0,0 @@ -package cn.iocoder.mall.order.application; - -import org.apache.catalina.connector.Connector; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.config.ConfigFileApplicationListener; -import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer; -import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; -import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; -import org.springframework.context.annotation.Bean; - -/** - * @author xiaofeng - */ -@SpringBootApplication(scanBasePackages = {"cn.iocoder.mall.order"}) -public class OrderApplication { - - /** - * 设置需要读取的配置文件的名字。 基于 {@link org.springframework.boot.context.config.ConfigFileApplicationListener#CONFIG_NAME_PROPERTY} - * 实现。 - */ - private static final String CONFIG_NAME_VALUE = "biz,rest,rpc,application"; - - public static void main(String[] args) { - // 设置环境变量 - System.setProperty(ConfigFileApplicationListener.CONFIG_NAME_PROPERTY, CONFIG_NAME_VALUE); - SpringApplication.run(OrderApplication.class, args); - } - - - /** - * 解决异常信息: java.lang.IllegalArgumentException: Invalid character found in the request target. - * The valid characters are defined in RFC 7230 and RFC 3986 - * - * @return - */ - @Bean - // TODO FROM 芋艿 to 芋艿:这个不太了解,可能后续要放到 starter 里,统一处理。 - public ConfigurableServletWebServerFactory webServerFactory() { - TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); - factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { - @Override - public void customize(Connector connector) { - connector.setProperty("relaxedQueryChars", "|{}[]"); - } - }); - return factory; - } - - -} diff --git a/order/order-application/src/main/resources/application.yaml b/order/order-application/src/main/resources/application.yaml deleted file mode 100644 index 17a49c062..000000000 --- a/order/order-application/src/main/resources/application.yaml +++ /dev/null @@ -1,7 +0,0 @@ -spring: - # Application 的配置项 - application: - name: order-application - # Profile 的配置项 - profiles: - active: local 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 0e33c9e6f..7543658b4 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 @@ -3,9 +3,9 @@ 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.ProductSpuAndSkuCreateReqDTO; +import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuAndSkuUpdateReqDTO; 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 java.util.List; @@ -27,7 +27,7 @@ public interface ProductSpuRpc { * * @param updateDTO 更新商品 SPU DTO */ - CommonResult updateProductSpu(ProductSpuUpdateReqDTO updateDTO); + CommonResult updateProductSpu(ProductSpuAndSkuUpdateReqDTO updateDTO); /** * 获得商品 SPU diff --git a/product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/rpc/spu/dto/ProductSpuAndSkuUpdateReqDTO.java b/product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/rpc/spu/dto/ProductSpuAndSkuUpdateReqDTO.java new file mode 100644 index 000000000..32b547b1a --- /dev/null +++ b/product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/rpc/spu/dto/ProductSpuAndSkuUpdateReqDTO.java @@ -0,0 +1,96 @@ +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 ProductSpuAndSkuUpdateReqDTO 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 编号 + */ + @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; + /** + * 商品主图地址 + */ + @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/ProductSpuUpdateReqDTO.java b/product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/rpc/spu/dto/ProductSpuUpdateReqDTO.java deleted file mode 100644 index 8ce7d5a3e..000000000 --- a/product-service-project/product-service-api/src/main/java/cn/iocoder/mall/productservice/rpc/spu/dto/ProductSpuUpdateReqDTO.java +++ /dev/null @@ -1,69 +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 ProductSpuUpdateReqDTO implements Serializable { - - /** - * 商品 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; - /** - * 商品主图地址 - */ - @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-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 index 51ab84f7c..94f2225fc 100644 --- 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 @@ -18,7 +18,7 @@ public interface ProductSkuConvert { List convertList(List list); @Mapping(source = "attrValueIds", target = "attrs", qualifiedByName = "translatePicUrlsFromStringList") - ProductSkuDO convertList(ProductSkuCreateOrUpdateBO bean); + ProductSkuDO convert(ProductSkuCreateOrUpdateBO skuUpdateDTO); @Named("translateAttrValueIdsFromString") default List translateAttrValueIdsFromString(String attrValueIdsStar) { 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 ced5694b4..fff78d08b 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,11 +3,11 @@ 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.service.sku.bo.ProductSkuCreateOrUpdateBO; import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuAndSkuCreateReqDTO; +import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuAndSkuUpdateReqDTO; 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.sku.bo.ProductSkuCreateOrUpdateBO; import cn.iocoder.mall.productservice.service.spu.bo.ProductSpuBO; import cn.iocoder.mall.productservice.service.spu.bo.ProductSpuCreateBO; import cn.iocoder.mall.productservice.service.spu.bo.ProductSpuPageBO; @@ -41,7 +41,7 @@ public interface ProductSpuConvert { ProductSpuCreateBO convert(ProductSpuAndSkuCreateReqDTO bean); - ProductSpuUpdateBO convert(ProductSpuUpdateReqDTO bean); + ProductSpuUpdateBO convert(ProductSpuAndSkuUpdateReqDTO bean); ProductSpuRespDTO convert(ProductSpuBO bean); @@ -51,6 +51,9 @@ public interface ProductSpuConvert { PageResult convertPage(PageResult page); + List convert(List list); + List convert02(List list); + @Named("translatePicUrlsFromString") default List translatePicUrlsFromList(String picUrls) { return StringUtils.split(picUrls, ","); @@ -61,6 +64,5 @@ public interface ProductSpuConvert { return StringUtils.join(picUrls, ","); } - List convert(List list); } 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 f6cb021e4..dec14d2b2 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 @@ -5,9 +5,9 @@ import cn.iocoder.common.framework.vo.PageResult; import cn.iocoder.mall.productservice.convert.spu.ProductSpuConvert; 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.ProductSpuAndSkuUpdateReqDTO; 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; @@ -17,17 +17,15 @@ 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 cn.iocoder.mall.productservice.service.spu.bo.ProductSpuUpdateBO; 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 java.util.*; +import java.util.stream.Collectors; -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; +import static cn.iocoder.mall.productservice.enums.ProductErrorCodeConstants.*; /** * 商品 SPU Manager @@ -52,30 +50,18 @@ public class ProductSpuManager { */ @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); + // 校验商品分类是否合法 + this.checkProductCategory(createDTO.getCid()); // 创建商品 SKU 对象,并进行校验 - List skus = ProductSpuConvert.INSTANCE.convert(createDTO.getSkus()); - productSkuService.validProductSku(skus, attrKeyValueBOs); + List skuBOs = ProductSpuConvert.INSTANCE.convert(createDTO.getSkus()); + this.checkProductAttr(skuBOs); // 插入商品 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()); // 求库存之和 + spuCreateBO.setPrice(skuBOs.stream().min(Comparator.comparing(ProductSkuCreateOrUpdateBO::getPrice)).get().getPrice()); // 求最小价格 + spuCreateBO.setQuantity(skuBOs.stream().mapToInt(ProductSkuCreateOrUpdateBO::getQuantity).sum()); // 求库存之和 ProductSpuBO spuBO = productSpuService.createProductSpu(spuCreateBO); - // 从插入商品 SKU 记录 - productSkuService.createProductSkus(spuBO.getId(), skus); + // 插入商品 SKU 记录 + productSkuService.createProductSkus(spuBO.getId(), skuBOs); return spuBO.getId(); } @@ -84,8 +70,19 @@ public class ProductSpuManager { * * @param updateDTO 更新商品 SPU DTO */ - public void updateProductSpu(ProductSpuUpdateReqDTO updateDTO) { - productSpuService.updateProductSpu(ProductSpuConvert.INSTANCE.convert(updateDTO)); + public void updateProductSpu(ProductSpuAndSkuUpdateReqDTO updateDTO) { + // 校验商品分类是否合法 + this.checkProductCategory(updateDTO.getCid()); + // 创建商品 SKU 对象,并进行校验 + List skuBOs = ProductSpuConvert.INSTANCE.convert02(updateDTO.getSkus()); + this.checkProductAttr(skuBOs); + // 更新商品 SPU 记录 + ProductSpuUpdateBO spuUpdateBO = ProductSpuConvert.INSTANCE.convert(updateDTO); + spuUpdateBO.setPrice(skuBOs.stream().min(Comparator.comparing(ProductSkuCreateOrUpdateBO::getPrice)).get().getPrice()); // 求最小价格 + spuUpdateBO.setQuantity(skuBOs.stream().mapToInt(ProductSkuCreateOrUpdateBO::getQuantity).sum()); // 求库存之和 + productSpuService.updateProductSpu(spuUpdateBO); + // 更新商品 SKU 记录 + productSkuService.updateProductSkus(updateDTO.getId(), skuBOs); } /** @@ -121,4 +118,57 @@ public class ProductSpuManager { return ProductSpuConvert.INSTANCE.convertPage(pageResultBO); } + /** + * 添加或修改商品 SPU 时,校验商品分类是否合法 + * + * @param cid 商品分类编号 + * @return 商品分类 + */ + private ProductCategoryBO checkProductCategory(Integer cid) { + ProductCategoryBO categoryBO = productCategoryService.getProductCategory(cid); + 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); + } + return categoryBO; + } + + private List checkProductAttr(List skuBOs) { + // 第一步,校验 SKU 使用到的规格是否存在 + Set attrValueIds = new HashSet<>(); + skuBOs.forEach(sku -> attrValueIds.addAll(sku.getAttrValueIds())); + List attrKeyValueBOs = productAttrService.validProductAttr(attrValueIds, true); + // 第二步,校验 SKU 设置的规格是否合法,例如说数量是否一致,是否重复等等 + // 创建 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); + } + } + return attrKeyValueBOs; + } + } 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 983087723..a1b568cbc 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 @@ -4,9 +4,9 @@ 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.ProductSpuAndSkuCreateReqDTO; +import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuAndSkuUpdateReqDTO; 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 org.apache.dubbo.config.annotation.Service; import org.springframework.beans.factory.annotation.Autowired; @@ -29,7 +29,7 @@ public class ProductSpuRpcImpl implements ProductSpuRpc { } @Override - public CommonResult updateProductSpu(ProductSpuUpdateReqDTO updateDTO) { + public CommonResult updateProductSpu(ProductSpuAndSkuUpdateReqDTO updateDTO) { productSpuManager.updateProductSpu(updateDTO); return success(true); } 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 index 4eaebb8f9..5040fc414 100644 --- 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 @@ -1,31 +1,26 @@ 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.common.framework.util.CollectionUtils; +import cn.iocoder.common.framework.util.StringUtils; 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.*; 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); + public void createProductSkus(Integer spuId, List createSkuBOs) { + List skus = ProductSkuConvert.INSTANCE.convertList(createSkuBOs); skus.forEach(sku -> { sku.setStatus(CommonStatusEnum.ENABLE.getValue()); sku.setSpuId(spuId); @@ -33,42 +28,64 @@ public class ProductSkuService { productSkuMapper.insertList(skus); } - public void updateProductSkus(Integer spuId, List createBOs) { - + public void updateProductSkus(Integer spuId, List skuUpdateBOs) { + List existsSkus = productSkuMapper.selectListBySpuIdAndStatus(spuId, + CommonStatusEnum.ENABLE.getValue()); + List insertSkus = new ArrayList<>(); // 1、找不到,进行插入 + List deleteSkus = new ArrayList<>(); // 2、多余的,删除 + List updateSkus = new ArrayList<>(); // 3、找的到,进行更新。 + for (ProductSkuCreateOrUpdateBO skuUpdateDTO : skuUpdateBOs) { + ProductSkuDO existsSku = findProductSku(skuUpdateDTO.getAttrValueIds(), existsSkus); + // 3、找的到,进行更新。 + if (existsSku != null) { + // 移除 + existsSkus.remove(existsSku); + // 创建 ProductSkuDO + updateSkus.add(ProductSkuConvert.INSTANCE.convert(skuUpdateDTO).setId(existsSku.getId())); + continue; + } + // 1、找不到,进行插入 + ProductSkuDO insertSku = ProductSkuConvert.INSTANCE.convert(skuUpdateDTO) + .setSpuId(spuId).setStatus(CommonStatusEnum.ENABLE.getValue()); + insertSkus.add(insertSku); + } + // 2、多余的,删除 + if (!existsSkus.isEmpty()) { + deleteSkus.addAll(existsSkus.stream().map(ProductSkuDO::getId).collect(Collectors.toList())); + } + // 执行修改 Sku + if (!insertSkus.isEmpty()) { + productSkuMapper.insertList(insertSkus); + } + if (!updateSkus.isEmpty()) { + updateSkus.forEach(productSkuDO -> productSkuMapper.updateById(productSkuDO)); + } + if (!deleteSkus.isEmpty()) { + productSkuMapper.deleteBatchIds(deleteSkus); + } } /** - * 校验 sku 是否合法 + * 获得 sku 数组中,指定规格的 sku * - * @param skuBOs 商品 SKU 添加信息 - * @param attrKeyValueBOs 商品规格明细数组 + * @param attrValueIds 指定规格 Value 的编号数组 + * @param skus sku 数组 + * @return 符合条件的 sku */ - 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); + private ProductSkuDO findProductSku(Collection attrValueIds, List skus) { + if (CollectionUtils.isEmpty(skus)) { + return null; + } + // 创建成 Set ,方便后面比较 + attrValueIds = new HashSet<>(attrValueIds); + for (ProductSkuDO sku : skus) { + Set skuAttrValueIds = StringUtils.split(sku.getAttrs(), ",") + .stream().map(Integer::parseInt).collect(Collectors.toSet()); + if (attrValueIds.equals(skuAttrValueIds)) { + return sku; } } + return null; } } diff --git a/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/service/spu/bo/ProductSpuUpdateBO.java b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/service/spu/bo/ProductSpuUpdateBO.java index f7f93cafe..5e88acfa4 100644 --- a/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/service/spu/bo/ProductSpuUpdateBO.java +++ b/product-service-project/product-service-app/src/main/java/cn/iocoder/mall/productservice/service/spu/bo/ProductSpuUpdateBO.java @@ -52,7 +52,6 @@ public class ProductSpuUpdateBO { /** * 排序字段 */ - @NotNull(message = "排序字段不能为空") private Integer sort; /** * 价格 diff --git a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/bo/brand/ProductBrandBO.java b/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/bo/brand/ProductBrandBO.java deleted file mode 100644 index 6dcdcc99b..000000000 --- a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/bo/brand/ProductBrandBO.java +++ /dev/null @@ -1,42 +0,0 @@ -package cn.iocoder.mall.product.biz.bo.brand; - -import lombok.Data; -import lombok.experimental.Accessors; - -import java.io.Serializable; - -/** - * 商品品牌 VO - */ -@Data -@Accessors(chain = true) -public class ProductBrandBO implements Serializable { - - /** - * 规格编号 - */ - private Integer id; - /** - * 名称 - */ - private String name; - - /** - * 描述 - */ - private String description; - - /** - * 图片地址 - */ - private String picUrl; - - /** - * 状态 - * - * 1-开启 - * 2-禁用 - */ - private Integer status; - -} diff --git a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dao/sku/ProductSkuMapper.java b/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dao/sku/ProductSkuMapper.java deleted file mode 100644 index 9a2179205..000000000 --- a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dao/sku/ProductSkuMapper.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.iocoder.mall.product.biz.dao.sku; - -import cn.iocoder.mall.product.biz.dataobject.spu.ProductSkuDO; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.toolkit.Wrappers; -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(Wrappers.query().lambda() - .eq(ProductSkuDO::getSpuId, spuId) - .eq(ProductSkuDO::getStatus, status) - .eq(ProductSkuDO::getDeleted, false)); - } - - void insertList(@Param("productSkuDOs") List productSkuDOs); -} diff --git a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/package-info.java b/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/package-info.java deleted file mode 100644 index 0b03eaaf8..000000000 --- a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -/** - * author: sin - * time: 2020/5/3 8:29 下午 - */ -package cn.iocoder.mall.product.biz.dto; \ No newline at end of file diff --git a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/product/ProductSpuPageDTO.java b/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/product/ProductSpuPageDTO.java deleted file mode 100644 index 9f6dfe5a9..000000000 --- a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/product/ProductSpuPageDTO.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.iocoder.mall.product.biz.dto.product; - -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-biz/src/main/java/cn/iocoder/mall/product/biz/dto/product/ProductSpuUpdateDTO.java b/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/product/ProductSpuUpdateDTO.java deleted file mode 100644 index 58372f0d7..000000000 --- a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/product/ProductSpuUpdateDTO.java +++ /dev/null @@ -1,68 +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 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/java/cn/iocoder/mall/product/biz/dto/product/UserProductSpuCollectionsUpdateDTO.java b/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/product/UserProductSpuCollectionsUpdateDTO.java deleted file mode 100644 index e47596ee7..000000000 --- a/product/product-biz/src/main/java/cn/iocoder/mall/product/biz/dto/product/UserProductSpuCollectionsUpdateDTO.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.mall.product.biz.dto.product; - -import lombok.Data; -import lombok.experimental.Accessors; - -import java.io.Serializable; -import java.util.Date; - -/** - * 更新商品收藏参数 - * @author xiaofeng - * @date 2019/07/01 20:38 - * @version 1.0 - */ -@Data -@Accessors(chain = true) -public class UserProductSpuCollectionsUpdateDTO implements Serializable { - - /** - * id自增长 - */ - private Integer id; - - /** - * 更新时间 - */ - private Date updateTime; - - /** - * 删除状态 - */ - private Integer deleted; - - -} diff --git a/product/product-rest/src/main/java/cn/iocoder/mall/product/rest/controller/brand/AdminsProductBrandController.java b/product/product-rest/src/main/java/cn/iocoder/mall/product/rest/controller/brand/AdminsProductBrandController.java deleted file mode 100644 index 79814d9f3..000000000 --- a/product/product-rest/src/main/java/cn/iocoder/mall/product/rest/controller/brand/AdminsProductBrandController.java +++ /dev/null @@ -1,93 +0,0 @@ -package cn.iocoder.mall.product.rest.controller.brand; - -import cn.iocoder.common.framework.vo.CommonResult; -import cn.iocoder.common.framework.vo.PageResult; -import cn.iocoder.mall.product.biz.bo.brand.ProductBrandBO; -import cn.iocoder.mall.product.biz.dto.brand.ProductBrandAddDTO; -import cn.iocoder.mall.product.biz.dto.brand.ProductBrandPageDTO; -import cn.iocoder.mall.product.biz.dto.brand.ProductBrandUpdateDTO; -import cn.iocoder.mall.product.biz.service.brand.ProductBrandService; -import cn.iocoder.mall.product.rest.convert.brand.ProductBrandConvert; -import cn.iocoder.mall.product.rest.request.brand.ProductBrandAddRequest; -import cn.iocoder.mall.product.rest.request.brand.ProductBrandPageRequest; -import cn.iocoder.mall.product.rest.request.brand.ProductBrandUpdateRequest; -import cn.iocoder.mall.product.rest.response.brand.AdminsProductBrandResponse; -import cn.iocoder.mall.security.core.context.AdminSecurityContextHolder; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; -import lombok.AllArgsConstructor; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import static cn.iocoder.common.framework.vo.CommonResult.success; - -@RestController -@RequestMapping("admins/brand") -@Api("管理员 - 商品品牌 API") -@AllArgsConstructor -public class AdminsProductBrandController { - - private final ProductBrandService productBrandService; - - @PostMapping("/add") - @ApiOperation("创建品牌") - public CommonResult add(@Validated ProductBrandAddRequest addRequest) { - // 创建 ProductBrandAddDTO 对象 - ProductBrandAddDTO productBrandAddDTO = ProductBrandConvert.INSTANCE.convertAdd(addRequest); - // 保存品牌 - ProductBrandBO result = productBrandService.addProductBrand(AdminSecurityContextHolder.getContext().getAdminId(), productBrandAddDTO); - // 返回结果 - return success(ProductBrandConvert.INSTANCE.convert(result)); - } - - @PostMapping("/update") - @ApiOperation("更新商品") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "品牌主键", required = true, example = "1"), - @ApiImplicitParam(name = "name", value = "品牌名称", required = true, example = "安踏"), - @ApiImplicitParam(name = "description", value = "品牌描述", required = true, example = "安踏拖鞋"), - @ApiImplicitParam(name = "picUrl", value = "品牌图片", required = true, example = "http://www.iocoder.cn"), - @ApiImplicitParam(name = "status", value = "状态 1开启 2禁用", required = true, example = "1") - }) - // TODO FROM 芋艿 to q2118cs:只要改成了 bean 接收,就不用在写 @ApiImplicitParam 注解啦,直接在 bean 里写就 ok 啦 - public CommonResult update(@Validated ProductBrandUpdateRequest updateRequest) { - // 创建 productBrandUpdateDTO 对象 - ProductBrandUpdateDTO productBrandUpdateDTO = ProductBrandConvert.INSTANCE.convertUpdate(updateRequest); - // 更新商品 - return success(productBrandService.updateProductBrand(AdminSecurityContextHolder.getContext().getAdminId(), productBrandUpdateDTO)); - } - - @GetMapping("/get") - @ApiOperation("获取品牌") - @ApiImplicitParams({ - @ApiImplicitParam(name = "id", value = "品牌主键", required = true, example = "1") - }) - public CommonResult add(@RequestParam("id") Integer id) { - // 保存商品 - ProductBrandBO result = productBrandService.getProductBrand(id); - // 返回结果 - return success(ProductBrandConvert.INSTANCE.convert(result)); - } - - @GetMapping("/page") - @ApiOperation("获得品牌分页") - @ApiImplicitParams({ - @ApiImplicitParam(name = "name", value = "品牌名称", required = true, example = "安踏"), - @ApiImplicitParam(name = "description", value = "品牌描述", required = true, example = "安踏拖鞋"), - @ApiImplicitParam(name = "status", value = "状态 1开启 2禁用", required = true, example = "1"), - @ApiImplicitParam(name = "pageNo", value = "页码", required = true, example = "1"), - @ApiImplicitParam(name = "pageSize", value = "页面大小", required = true, example = "10") - }) - public CommonResult> attrPage(ProductBrandPageRequest pageRequest) { - // 创建 ProductBrandPageDTO 对象 - ProductBrandPageDTO productBrandPageDTO = ProductBrandConvert.INSTANCE.convertPageRequest(pageRequest); - // 查询分页 - PageResult productBrandPage = productBrandService.getProductBrandPage(productBrandPageDTO); - PageResult adminPageResponse = ProductBrandConvert.INSTANCE.convertPage(productBrandPage); - return CommonResult.success(adminPageResponse); - } - - -} 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 2082b1f27..f1b4c2d71 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 @@ -30,10 +30,6 @@ public interface ProductSpuService { List getProductSkuDetailList(Collection ids); - ProductSpuDetailBO addProductSpu(Integer adminId, ProductSpuAddDTO productSpuAddDTO); - - void updateProductSpu(Integer adminId, ProductSpuUpdateDTO productSpuUpdateDTO); - Boolean updateProductSpuSort(Integer adminId, Integer spuId, Integer sort); } diff --git a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/dto/ProductSpuUpdateDTO.java b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/dto/ProductSpuUpdateDTO.java deleted file mode 100644 index 5b4753491..000000000 --- a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/dto/ProductSpuUpdateDTO.java +++ /dev/null @@ -1,68 +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 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-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 f5a021890..a89767c46 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 @@ -88,7 +88,6 @@ public class ProductSpuServiceImpl implements ProductSpuService { @Override public ProductSpuDetailBO addProductSpu(Integer adminId, ProductSpuAddDTO productSpuAddDTO) { - ProductSpuDetailBO productSpuDetailBO = addProductSpu0(adminId, productSpuAddDTO); // 如果新增生成,发送创建商品 Topic 消息 // TODO 芋艿,先不考虑事务的问题。等后面的 fescar 一起搞 sendProductUpdateMessage(productSpuDetailBO.getId()); @@ -96,76 +95,6 @@ public class ProductSpuServiceImpl implements ProductSpuService { return productSpuDetailBO; } - @Override - public void updateProductSpu(Integer adminId, ProductSpuUpdateDTO productSpuUpdateDTO) { - // 更新商品 - updateProductSpu0(adminId, productSpuUpdateDTO); - // TODO 芋艿,先不考虑事务的问题。等后面的 fescar 一起搞 - sendProductUpdateMessage(productSpuUpdateDTO.getId()); - } - - @SuppressWarnings("Duplicates") - @Transactional - public void updateProductSpu0(Integer adminId, ProductSpuUpdateDTO productSpuUpdateDTO) { - // 校验 Spu 是否存在 - if (productSpuMapper.selectById(productSpuUpdateDTO.getId()) == null) { - throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_SPU_NOT_EXISTS.getCode()); - } - // 校验商品分类分类存在 - ProductCategoryDO category = productCategoryService.validProductCategory(productSpuUpdateDTO.getCid()); - if (ProductCategoryConstants.PID_ROOT.equals(category.getPid())) { // 商品只能添加到二级分类下 - throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_SPU_CATEGORY_MUST_BE_LEVEL2.getCode()); - } - // 校验规格是否存在 - Set productAttrValueIds = new HashSet<>(); - productSpuUpdateDTO.getSkus().forEach(productSkuAddDTO -> productAttrValueIds.addAll(productSkuAddDTO.getAttrs())); - List attrAndValuePairList = productAttrService.validProductAttrAndValue(productAttrValueIds, - true); // 读取规格时,需要考虑规格是否被禁用 - // 校验 Sku 规格 - validProductSku(productSpuUpdateDTO.getSkus(), attrAndValuePairList); - // 更新 Spu - ProductSpuDO updateSpu = ProductSpuConvert.INSTANCE.convert(productSpuUpdateDTO) - .setPicUrls(StringUtil.join(productSpuUpdateDTO.getPicUrls(), ",")); - initSpuFromSkus(updateSpu, productSpuUpdateDTO.getSkus()); // 初始化 sku 相关信息到 spu 中 - productSpuMapper.update(updateSpu); - // 修改 Sku - List existsSkus = productSkuMapper.selectListBySpuIdAndStatus(productSpuUpdateDTO.getId(), ProductSpuConstants.SKU_STATUS_ENABLE); - List insertSkus = new ArrayList<>(0); // 1、找不到,进行插入 - List deleteSkus = new ArrayList<>(0); // 2、多余的,删除 - List updateSkus = new ArrayList<>(0); // 3、找的到,进行更新。 - for (ProductSkuAddOrUpdateDTO skuUpdateDTO : productSpuUpdateDTO.getSkus()) { - ProductSkuDO existsSku = findProductSku(skuUpdateDTO.getAttrs(), existsSkus); - // 3、找的到,进行更新。 - if (existsSku != null) { - // 移除 - existsSkus.remove(existsSku); - // 创建 ProductSkuDO - updateSkus.add(ProductSpuConvert.INSTANCE.convert(skuUpdateDTO).setId(existsSku.getId())); - continue; - } - // 1、找不到,进行插入 - ProductSkuDO insertSku = ProductSpuConvert.INSTANCE.convert(skuUpdateDTO) - .setSpuId(productSpuUpdateDTO.getId()).setStatus(ProductSpuConstants.SKU_STATUS_ENABLE).setAttrs(StringUtil.join(skuUpdateDTO.getAttrs(), ",")); - insertSku.setCreateTime(new Date()); - insertSku.setDeleted(DeletedStatusEnum.DELETED_NO.getValue()); - insertSkus.add(insertSku); - } - // 2、多余的,删除 - if (!existsSkus.isEmpty()) { - deleteSkus.addAll(existsSkus.stream().map(ProductSkuDO::getId).collect(Collectors.toList())); - } - // 执行修改 Sku - if (!insertSkus.isEmpty()) { - productSkuMapper.insertList(insertSkus); - } - if (!updateSkus.isEmpty()) { - updateSkus.forEach(productSkuDO -> productSkuMapper.update(productSkuDO)); - } - if (!deleteSkus.isEmpty()) { - productSkuMapper.updateToDeleted(deleteSkus); - } - } - @Override public Boolean updateProductSpuSort(Integer adminId, Integer spuId, Integer sort) { // 校验 Spu 是否存在 @@ -181,21 +110,6 @@ public class ProductSpuServiceImpl implements ProductSpuService { return true; } - @Override - public ProductSpuPageBO getProductSpuPage(ProductSpuPageDTO productSpuPageDTO) { - ProductSpuPageBO productSpuPage = new ProductSpuPageBO(); - // 查询分页数据 - int offset = (productSpuPageDTO.getPageNo() - 1) * productSpuPageDTO.getPageSize(); - productSpuPage.setList(ProductSpuConvert.INSTANCE.convert(productSpuMapper.selectListByNameLikeOrderBySortAsc( - productSpuPageDTO.getName(), productSpuPageDTO.getCid(), productSpuPageDTO.getHasQuantity(), productSpuPageDTO.getVisible(), - offset, productSpuPageDTO.getPageSize()))); - // 查询分页总数 - productSpuPage.setTotal(productSpuMapper.selectCountByNameLike(productSpuPageDTO.getName(), productSpuPageDTO.getCid(), productSpuPageDTO.getHasQuantity(), - productSpuPageDTO.getVisible())); - // 返回结果 - return productSpuPage; - } - @Override public List getProductSpuSearchList(ProductSpuSearchListDTO productSpuSearchListDTO) { return ProductSpuConvert.INSTANCE.convert( @@ -237,28 +151,6 @@ public class ProductSpuServiceImpl implements ProductSpuService { return ProductSpuConvert.INSTANCE.convert3(skus, spus, attrAndValuePairList); } - /** - * 获得 sku 数组中,指定规格的 sku - * - * @param attrs 指定规格 - * @param skus sku 数组 - * @return 符合条件的 sku - */ - private ProductSkuDO findProductSku(Collection attrs, List skus) { - if (CollectionUtil.isEmpty(skus)) { - return null; - } - // 创建成 Set ,方便后面比较 - attrs = new HashSet<>(attrs); - for (ProductSkuDO sku : skus) { - Set skuAttrs = StringUtil.split(sku.getAttrs(), ",").stream().map(Integer::parseInt).collect(Collectors.toSet()); - if (attrs.equals(skuAttrs)) { - return sku; - } - } - return null; - } - private boolean sendProductUpdateMessage(Integer id) { // 创建 Message 对象 ProductUpdateMessage message = new ProductUpdateMessage().setId(id);