Commit c2fd24f597003ea04ff8e726c85c169735f8e0c3

Authored by YunaiV
1 parent edfe3798

mall:code review 商品 spu 的后端代码

yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java
... ... @@ -21,7 +21,9 @@ public class ProductSkuBaseVO {
21 21 @NotEmpty(message = "商品 SKU 名字不能为空")
22 22 private String name;
23 23  
24   - @ApiModelProperty(value = "规格值数组-json格式 单规格中无此列表, [{propertyId: , valueId: }, {propertyId: , valueId: }]")
  24 + /**
  25 + * 规格值数组
  26 + */
25 27 private List<Property> properties;
26 28  
27 29 @ApiModelProperty(value = "销售价格,单位:分", required = true, example = "1024", notes = "单位:分")
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java
... ... @@ -35,15 +35,15 @@ public class ProductSpuController {
35 35 @PostMapping("/create")
36 36 @ApiOperation("创建商品 SPU")
37 37 @PreAuthorize("@ss.hasPermission('product:spu:create')")
38   - public CommonResult<Long> createSpu(@Valid @RequestBody ProductSpuCreateReqVO createReqVO) {
39   - return success(spuService.createSpu(createReqVO));
  38 + public CommonResult<Long> createProductSpu(@Valid @RequestBody ProductSpuCreateReqVO createReqVO) {
  39 + return success(spuService.createProductSpu(createReqVO));
40 40 }
41 41  
42 42 @PutMapping("/update")
43 43 @ApiOperation("更新商品 SPU")
44 44 @PreAuthorize("@ss.hasPermission('product:spu:update')")
45 45 public CommonResult<Boolean> updateSpu(@Valid @RequestBody ProductSpuUpdateReqVO updateReqVO) {
46   - spuService.updateSpu(updateReqVO);
  46 + spuService.updateProductSpu(updateReqVO);
47 47 return success(true);
48 48 }
49 49  
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java
... ... @@ -44,4 +44,5 @@ public interface ProductSkuMapper extends BaseMapperX&lt;ProductSkuDO&gt; {
44 44 .eqIfPresent(ProductSkuDO::getSpuId, spuId);
45 45 delete(lambdaQueryWrapperX);
46 46 }
  47 +
47 48 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java
... ... @@ -68,14 +68,22 @@ public interface ProductSkuService {
68 68 *
69 69 * @param list sku组合的集合
70 70 */
71   - void validateSkus(List<ProductSkuCreateOrUpdateReqVO> list);
  71 + void validateProductSkus(List<ProductSkuCreateOrUpdateReqVO> list);
72 72  
73 73 /**
74   - * 批量保存 sku
  74 + * 批量创建 SKU
75 75 *
76   - * @param list sku对象集合
  76 + * @param list SKU 对象集合
77 77 */
78   - void createSkus(List<ProductSkuDO> list);
  78 + void createProductSkus(List<ProductSkuDO> list);
  79 +
  80 + /**
  81 + * 根据 SPU 编号,批量更新它的 SKU 信息
  82 + *
  83 + * @param spuId SPU 编码
  84 + * @param skus SKU 的集合
  85 + */
  86 + void updateProductSkus(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skus);
79 87  
80 88 /**
81 89 * 获得商品 sku 集合
... ... @@ -100,11 +108,4 @@ public interface ProductSkuService {
100 108 */
101 109 void deleteSkuBySpuId(Long spuId);
102 110  
103   - /**
104   - * 根据 spuId 更新 spu 下的 sku 信息
105   - *
106   - * @param spuId spu 编码
107   - * @param skus sku 的集合
108   - */
109   - void updateSkus(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skus);
110 111 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java
1 1 package cn.iocoder.yudao.module.product.service.sku;
2 2  
3   -import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
4 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 4 import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyRespVO;
6 5 import cn.iocoder.yudao.module.product.controller.admin.propertyvalue.vo.ProductPropertyValueRespVO;
... ... @@ -87,25 +86,30 @@ public class ProductSkuServiceImpl implements ProductSkuService {
87 86 return productSkuMapper.selectPage(pageReqVO);
88 87 }
89 88  
  89 + // TODO luowenfeng:参考下 yudao-cloud 的 checkProductAttr 方法,重构下
90 90 @Override
91   - public void validateSkus(List<ProductSkuCreateOrUpdateReqVO> list) {
  91 + public void validateProductSkus(List<ProductSkuCreateOrUpdateReqVO> list) {
92 92 List<ProductSkuBaseVO.Property> skuPropertyList = list.stream().flatMap(p -> Optional.of(p.getProperties()).orElse(new ArrayList<>()).stream()).collect(Collectors.toList());
93   - // 校验规格属性以及规格值是否存在
  93 + // 校验规格属性存在
  94 + // TODO @luowenfeng:使用 CollectionUtils.convert
94 95 List<Long> propertyIds = skuPropertyList.stream().map(ProductSkuBaseVO.Property::getPropertyId).collect(Collectors.toList());
95 96 List<ProductPropertyRespVO> propertyAndValueList = productPropertyService.selectByIds(propertyIds);
  97 + // TODO @luowenfeng:校验数量一致;
96 98 if (propertyAndValueList.isEmpty()) {
97   - throw ServiceExceptionUtil.exception(PROPERTY_NOT_EXISTS);
  99 + throw exception(PROPERTY_NOT_EXISTS);
98 100 }
  101 + // 校验规格属性值存在
  102 + // TODO @luowenfeng:使用 CollectionUtils.convert
99 103 Map<Long, ProductPropertyRespVO> propertyMap = propertyAndValueList.stream().collect(Collectors.toMap(ProductPropertyRespVO::getId, p -> p));
100 104 skuPropertyList.forEach(p -> {
101 105 ProductPropertyRespVO productPropertyRespVO = propertyMap.get(p.getPropertyId());
102 106 // 如果对应的属性名不存在或属性名下的属性值集合为空,给出提示
103 107 if (null == productPropertyRespVO || productPropertyRespVO.getPropertyValueList().isEmpty()) {
104   - throw ServiceExceptionUtil.exception(PROPERTY_NOT_EXISTS);
  108 + throw exception(PROPERTY_NOT_EXISTS);
105 109 }
106 110 // 判断改属性名对应的属性值是否存在,不存在,给出提示
107 111 if (!productPropertyRespVO.getPropertyValueList().stream().map(ProductPropertyValueRespVO::getId).collect(Collectors.toSet()).contains(p.getValueId())) {
108   - throw ServiceExceptionUtil.exception(ErrorCodeConstants.PROPERTY_VALUE_NOT_EXISTS);
  112 + throw exception(ErrorCodeConstants.PROPERTY_VALUE_NOT_EXISTS);
109 113 }
110 114 });
111 115 // 校验是否有重复的sku组合
... ... @@ -114,13 +118,13 @@ public class ProductSkuServiceImpl implements ProductSkuService {
114 118 skuProperties.forEach(p -> {
115 119 // 组合属性值id为 1~2~3.... 形式的字符串,通过set的特性判断是否有重复的组合
116 120 if (!skuPropertiesConvertSet.add(p.stream().map(pr -> String.valueOf(pr.getValueId())).sorted().collect(Collectors.joining("~")))) {
117   - throw ServiceExceptionUtil.exception(ErrorCodeConstants.SKU_PROPERTIES_DUPLICATED);
  121 + throw exception(ErrorCodeConstants.SKU_PROPERTIES_DUPLICATED);
118 122 }
119 123 });
120 124 }
121 125  
122 126 @Override
123   - public void createSkus(List<ProductSkuDO> skuDOList) {
  127 + public void createProductSkus(List<ProductSkuDO> skuDOList) {
124 128 productSkuMapper.insertBatch(skuDOList);
125 129 }
126 130  
... ... @@ -141,21 +145,23 @@ public class ProductSkuServiceImpl implements ProductSkuService {
141 145  
142 146 @Override
143 147 @Transactional
144   - public void updateSkus(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skus) {
145   - List<ProductSkuDO> allUpdateSkus = ProductSkuConvert.INSTANCE.convertSkuDOList(skus);
  148 + public void updateProductSkus(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skus) {
146 149 // 查询 spu 下已经存在的 sku 的集合
  150 + // TODO @luowenfeng:selectListBySpuId 搞个
147 151 List<ProductSkuDO> existsSkus = productSkuMapper.selectBySpuIds(Collections.singletonList(spuId));
148 152 // TODO @franky:使用 CollUtils 即可
149 153 Map<Long, ProductSkuDO> existsSkuMap = existsSkus.stream().collect(Collectors.toMap(ProductSkuDO::getId, p -> p));
150 154  
151   - // 拆分三个集合, 新插入的, 需要更新的,需要删除的
  155 + // 拆分三个集合,新插入的、需要更新的、需要删除的
152 156 List<ProductSkuDO> insertSkus = new ArrayList<>();
153 157 List<ProductSkuDO> updateSkus = new ArrayList<>();
154 158 List<ProductSkuDO> deleteSkus = new ArrayList<>();
155 159  
156 160 // TODO @芋艿:是不是基于规格匹配会比较好。
  161 + List<ProductSkuDO> allUpdateSkus = ProductSkuConvert.INSTANCE.convertSkuDOList(skus);
157 162 allUpdateSkus.forEach(p -> {
158   - if (null != p.getId()) {
  163 + if (p.getId() != null) {
  164 + // TODO @luowenfeng:contains
159 165 if (existsSkuMap.get(p.getId()) != null) {
160 166 updateSkus.add(p);
161 167 return;
... ... @@ -167,14 +173,13 @@ public class ProductSkuServiceImpl implements ProductSkuService {
167 173 insertSkus.add(p);
168 174 });
169 175  
  176 + // TODO @luowenfeng:使用 CollUtil.isNotEmpty 判断
170 177 if (insertSkus.size() > 0) {
171 178 productSkuMapper.insertBatch(insertSkus);
172 179 }
173   -
174 180 if (updateSkus.size() > 0) {
175 181 updateSkus.forEach(p -> productSkuMapper.updateById(p));
176 182 }
177   -
178 183 if (deleteSkus.size() > 0) {
179 184 productSkuMapper.deleteBatchIds(deleteSkus.stream().map(ProductSkuDO::getId).collect(Collectors.toList()));
180 185 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java
... ... @@ -21,19 +21,19 @@ import java.util.List;
21 21 public interface ProductSpuService {
22 22  
23 23 /**
24   - * 创建商品spu
  24 + * 创建商品 SPU
25 25 *
26 26 * @param createReqVO 创建信息
27 27 * @return 编号
28 28 */
29   - Long createSpu(@Valid ProductSpuCreateReqVO createReqVO);
  29 + Long createProductSpu(@Valid ProductSpuCreateReqVO createReqVO);
30 30  
31 31 /**
32   - * 更新商品spu
  32 + * 更新商品 SPU
33 33 *
34 34 * @param updateReqVO 更新信息
35 35 */
36   - void updateSpu(@Valid ProductSpuUpdateReqVO updateReqVO);
  36 + void updateProductSpu(@Valid ProductSpuUpdateReqVO updateReqVO);
37 37  
38 38 /**
39 39 * 删除商品spu
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java
... ... @@ -7,7 +7,10 @@ import cn.iocoder.yudao.module.product.controller.admin.propertyvalue.vo.Product
7 7 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO;
8 8 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
9 9 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO;
10   -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
  10 +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuCreateReqVO;
  11 +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateReqVO;
  12 +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.SpuPageReqVO;
  13 +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.SpuRespVO;
11 14 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageReqVO;
12 15 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageRespVO;
13 16 import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert;
... ... @@ -53,47 +56,60 @@ public class ProductSpuServiceImpl implements ProductSpuService {
53 56  
54 57 @Override
55 58 @Transactional
56   - public Long createSpu(ProductSpuCreateReqVO createReqVO) {
  59 + public Long createProductSpu(ProductSpuCreateReqVO createReqVO) {
57 60 // 校验分类
  61 + // TODO @luowenfeng:可以在这个类里加个方法,校验分类;商品必须挂在三级分类下;
58 62 categoryService.validateProductCategory(createReqVO.getCategoryId());
  63 + // TODO @luowenfeng:校验品牌
59 64 // 校验SKU
60 65 List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = createReqVO.getSkus();
61 66 // 多规格才需校验
  67 + // TODO @luowenfeng:可以把 type 传递到 productSkuService 里,通过它统一判断处理
62 68 if(Objects.equals(createReqVO.getSpecType(), ProductSpuSpecTypeEnum.DISABLE.getType())) {
63   - productSkuService.validateSkus(skuCreateReqList);
  69 + productSkuService.validateProductSkus(skuCreateReqList);
64 70 }
65   - // 插入SPU
  71 +
  72 + // 插入 SPU
66 73 ProductSpuDO spu = ProductSpuConvert.INSTANCE.convert(createReqVO);
  74 + // TODO @luowenfeng:可以在 CollectionUtils 增加 getMaxValue 方法,增加一个 defaultValue 方法,如果为空,则返回 defaultValue
67 75 spu.setMarketPrice(skuCreateReqList.stream().map(ProductSkuCreateOrUpdateReqVO::getMarketPrice).max(Integer::compare).orElse(0));
68 76 spu.setMaxPrice(skuCreateReqList.stream().map(ProductSkuCreateOrUpdateReqVO::getPrice).max(Integer::compare).orElse(0));
69 77 spu.setMinPrice(skuCreateReqList.stream().map(ProductSkuCreateOrUpdateReqVO::getPrice).min(Integer::compare).orElse(0));
  78 + // TODO @luowenfeng:库存求和
70 79 ProductSpuMapper.insert(spu);
  80 +
  81 + // 批量插入 SKU
  82 + // TODO @luowenfeng:convert 逻辑,交给 createProductSkus 一起处理
71 83 List<ProductSkuDO> skuDOList = ProductSkuConvert.INSTANCE.convertSkuDOList(skuCreateReqList);
72 84 skuDOList.forEach(v->v.setSpuId(spu.getId()));
73   - // 批量插入sku
74   - productSkuService.createSkus(skuDOList);
  85 + productSkuService.createProductSkus(skuDOList);
75 86 // 返回
76 87 return spu.getId();
77 88 }
78 89  
79 90 @Override
80 91 @Transactional
81   - public void updateSpu(ProductSpuUpdateReqVO updateReqVO) {
82   - // 校验 spu 是否存在
83   - this.validateSpuExists(updateReqVO.getId());
  92 + public void updateProductSpu(ProductSpuUpdateReqVO updateReqVO) {
  93 + // 校验 SPU 是否存在
  94 + validateSpuExists(updateReqVO.getId());
84 95 // 校验分类
85 96 categoryService.validateProductCategory(updateReqVO.getCategoryId());
  97 + // TODO @luowenfeng:校验品牌
86 98 // 校验SKU
87 99 List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = updateReqVO.getSkus();
88 100 // 多规格才需校验
  101 + // TODO @luowenfeng:可以把 type 传递到 productSkuService 里,通过它统一判断处理
89 102 if(updateReqVO.getSpecType().equals(ProductSpuSpecTypeEnum.DISABLE.getType())) {
90   - productSkuService.validateSkus(skuCreateReqList);
  103 + productSkuService.validateProductSkus(skuCreateReqList);
91 104 }
92   - // 更新
  105 +
  106 + // 更新 SPU
93 107 ProductSpuDO updateObj = ProductSpuConvert.INSTANCE.convert(updateReqVO);
  108 + // TODO @计算各种字段
94 109 ProductSpuMapper.updateById(updateObj);
95   - // 更新 sku
96   - productSkuService.updateSkus(updateObj.getId(), updateReqVO.getSkus());
  110 +
  111 + // 更新 SKU
  112 + productSkuService.updateProductSkus(updateObj.getId(), updateReqVO.getSkus());
97 113 }
98 114  
99 115 @Override
... ...
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java
... ... @@ -41,7 +41,7 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
41 41 ProductSpuCreateReqVO reqVO = randomPojo(ProductSpuCreateReqVO.class);
42 42  
43 43 // 调用
44   - Long spuId = spuService.createSpu(reqVO);
  44 + Long spuId = spuService.createProductSpu(reqVO);
45 45 // 断言
46 46 assertNotNull(spuId);
47 47 // 校验记录的属性是否正确
... ... @@ -60,7 +60,7 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
60 60 });
61 61  
62 62 // 调用
63   - spuService.updateSpu(reqVO);
  63 + spuService.updateProductSpu(reqVO);
64 64 // 校验是否更新正确
65 65 ProductSpuDO spu = ProductSpuMapper.selectById(reqVO.getId()); // 获取最新的
66 66 assertPojoEquals(reqVO, spu);
... ... @@ -72,7 +72,7 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
72 72 ProductSpuUpdateReqVO reqVO = randomPojo(ProductSpuUpdateReqVO.class);
73 73  
74 74 // 调用, 并断言异常
75   - assertServiceException(() -> spuService.updateSpu(reqVO), SPU_NOT_EXISTS);
  75 + assertServiceException(() -> spuService.updateProductSpu(reqVO), SPU_NOT_EXISTS);
76 76 }
77 77  
78 78 @Test
... ...