一、发布商品

发布商品填写的信息是SPU,不是SKU,不要弄错了
image.png

1.1 获取所有会员等级

配置gateway的路由转发规则,这里我设置了gateway直接从nacos中动态获取配置,以免每次加个路由规则,每次都要重启网关。(路由规则也同步加在了本地application.yml中,nacos中配置文件为route.yaml)

  1. - id: member_route
  2. uri: lb://gulimall-member
  3. predicates:
  4. - Path=/api/gulimallmember/**
  5. filters:
  6. - RewritePath=/api/(?<segment>.*), /$\{segment}

在用户系统-会员等级菜单下添加如下几个会员等级:
image.png

*解决点击发布商品—不发送请求问题

点击发布商品菜单时,前端应该向后台发送如下请求:
image.png
但我这里没有。
解决方法:
npm install --save pubsub-js
然后在src下的main.js中导入

  1. import PubSub from 'pubsub-js'
  2. Vue.prototype.PubSub = PubSub

1.2 获取分类关联的品牌

在添加SPU信息时,选择分类后会发送请求,查询当前分类下的品牌信息。
http://localhost:88/api/gulimallproduct/categorybrandrelation/brands/list?t=1646998496895&catId=225
image.png
Controller只用于处理请求、接收和校验数据
Service接收Controller传来的数据,进行业务处理
Controller接收Service处理完的数据,封装成页面指定VO

  1. package com.atguigu.gulimall.gulimallproduct.vo;
  2. import lombok.Data;
  3. @Data
  4. public class BrandVo {
  5. private Long brandId;
  6. private String brandName;
  7. }
  1. /**
  2. * 获取当前分类对应的所有品牌
  3. */
  4. // /product/categorybrandrelation/brands/list
  5. @GetMapping("/brands/list")
  6. public R relationBrandsList(@RequestParam(value = "catId") Long catId) {
  7. List<BrandEntity> brands = categoryBrandRelationService.getBrands(catId);
  8. List<BrandVo> collect = brands.stream().map((brandEntity -> {
  9. BrandVo brandVo = new BrandVo();
  10. brandVo.setBrandId(brandEntity.getBrandId());
  11. brandVo.setBrandName(brandEntity.getName());
  12. return brandVo;
  13. })).collect(Collectors.toList());
  14. return R.ok().put("data", collect);
  15. }

声明&实现

  1. @Autowired
  2. CategoryBrandRelationDao categoryBrandRelationDao;
  3. @Autowired
  4. BrandService brandService;
  5. /**
  6. * 获取指定分类对应的所有品牌
  7. * @param catId
  8. */
  9. @Override
  10. public List<BrandEntity> getBrands(Long catId) {
  11. // 1 通过分类id取出当前分类与品牌关联的所有记录 查`pms_category_brand_relation`表
  12. List<CategoryBrandRelationEntity> categoryBrandRelationEntities = categoryBrandRelationDao.selectList(new QueryWrapper<CategoryBrandRelationEntity>().eq("catelog_id", catId));
  13. // 2 通过查出来的关联记录,获取每条记录的品牌id,再通过品牌id查询品牌
  14. List<BrandEntity> brandEntityList = categoryBrandRelationEntities.stream().map((item) -> {
  15. Long brandId = item.getBrandId();
  16. BrandEntity brand = brandService.getById(brandId);
  17. return brand;
  18. }).collect(Collectors.toList());
  19. return brandEntityList;
  20. }

1.3 获取分类下所有属性分组&关联属性

image.png
发布商品在设置规格参数的时候,会向后台发送请求,查询当前分类下对应的所有属性分组以及关联属性。
https://easydoc.net/s/78237135/ZUqEdvA4/6JM6txHf
1、查出当前catelogId对应分类下的所有属性分组
2、查出每个分组的所有关联属性
新建一个vo类,存放需要返回的数据

  1. package com.atguigu.gulimall.gulimallproduct.vo;
  2. import com.atguigu.gulimall.gulimallproduct.entity.AttrEntity;
  3. import lombok.Data;
  4. import java.util.List;
  5. @Data
  6. public class AttrGroupWithAttrsVo {
  7. /**
  8. * 分组id
  9. */
  10. private Long attrGroupId;
  11. /**
  12. * 组名
  13. */
  14. private String attrGroupName;
  15. /**
  16. * 排序
  17. */
  18. private Integer sort;
  19. /**
  20. * 描述
  21. */
  22. private String descript;
  23. /**
  24. * 组图标
  25. */
  26. private String icon;
  27. /**
  28. * 所属分类id
  29. */
  30. private Long catelogId;
  31. /**
  32. * 所关联的所有属性
  33. */
  34. private List<AttrEntity> attrs;
  35. }
  1. /**
  2. * 获取当前分类下所有的属性分组&关联属性
  3. */
  4. // /product/attrgroup/{catelogId}/withattr
  5. @GetMapping("/{catelogId}/withattr")
  6. public R getAttrGroupWithAttr(@PathVariable("catelogId") Long catelogId) {
  7. // 1、查出当前catelogId对应分类下的所有属性分组
  8. // 2、查出每个分组的所有关联属性
  9. List<AttrGroupWithAttrsVo> vos = attrGroupService.getAttrGroupWithAttrByCatelogId(catelogId);
  10. return R.ok().put("data", vos);
  11. }

声明&实现

  1. /**
  2. * 根据分类id(catelogId)查询当前分类下所有的属性分组&关联属性
  3. * @param catelogId
  4. * @return
  5. */
  6. @Override
  7. public List<AttrGroupWithAttrsVo> getAttrGroupWithAttrByCatelogId(Long catelogId) {
  8. // 1、查询分组信息
  9. // 根据catelogId在`pms_attr_group`中查到分组信息
  10. List<AttrGroupEntity> attrGroupEntities = this.list(new QueryWrapper<AttrGroupEntity>().eq("catelog_id", catelogId));
  11. // 将查到的分组基本信息放到AttrGroupWithAttrsVo对象中
  12. List<AttrGroupWithAttrsVo> groupWithAttrsVos = attrGroupEntities.stream().map((item) -> {
  13. AttrGroupWithAttrsVo attrGroupWithAttrsVo = new AttrGroupWithAttrsVo();
  14. BeanUtils.copyProperties(item, attrGroupWithAttrsVo);
  15. // 2、查询分组关联所有属性
  16. // 之前在AttrService中写过通过attrGroupId查询关联的全部属性,直接调用
  17. List<AttrEntity> relationAttr = attrService.getRelationAttr(item.getAttrGroupId());
  18. attrGroupWithAttrsVo.setAttrs(relationAttr);
  19. return attrGroupWithAttrsVo;
  20. }).collect(Collectors.toList());
  21. return groupWithAttrsVos;
  22. }

image.png

1.4 新增商品

设置销售属性
image.png
在设置好规格销售属性和SKU信息后,点击下一步。
image.png
可以发现浏览器控制台打印了一长串JSON数据,这个就是我们提交给后台需要保存的数据。
image.png

1.4.1 JSON生成JAVA实体类

浏览器控制台打印了一长串json数据,复制,使用在线JSON生成JAVA实体类。在线JSON生成JAVA实体类
image.png
image.png
修改实体类,将id有关属性设置为Long类型,价格有关属性设置为BigDecimal类型;删除get/set方法使用@Data注解。

1.4.2 实现业务逻辑

这里的逻辑比较复杂,涉及到gulimall_pms(product)和gulimall_sms(coupon)中多张表的保存。获取到的SpuSaveVo包含了许多信息,通过以下6步将其信息保存到数据库中(这里强烈建议好好看看每张表里面到底有什么属性)

  1. 保存spu基本信息 pms_spu_info
  2. 保存spu的描述图片 pms_spu_info_desc
  3. 保存spu的图片集 pms_spu_images
  4. 保存spu的规格参数 pms_product_attr_value
  5. 保存spu的积分信息 gulimall_sms->sms_spu_bounds 与需要远程调用gulimall-coupon服务
  6. 保存当前spu对应的所有sku信息
    1. 保存sku的基本信息 pms_sku_info
    2. 保存sku的图片信息 pms_sku_images
    3. 保存sku的销售属性信息 pms_sku_sale_attr_value
    4. 保存sku的优惠、满减等信息 gulimall_sms(sms_sku_ladder/sms_sku_full_reduction/sms_member_price)

其中保存积分信息和优惠满减信息都需要远程调用coupon服务。

  1. /**
  2. * 保存
  3. */
  4. @RequestMapping("/save")
  5. //@RequiresPermissions("gulimallproduct:spuinfo:save")
  6. public R save(@RequestBody SpuSaveVo vo){
  7. // spuInfoService.save(spuInfo);
  8. spuInfoService.saveSpuInfo(vo);
  9. return R.ok();
  10. }

service声明&实现(没有实现远程调用)。

  1. @Autowired
  2. SpuInfoDescService infoDescService;
  3. @Autowired
  4. SpuImagesService spuImagesService;
  5. @Autowired
  6. ProductAttrValueService attrValueService;
  7. @Autowired
  8. AttrService attrService;
  9. @Autowired
  10. SkuInfoService skuInfoService;
  11. @Autowired
  12. SkuImagesService skuImagesService;
  13. @Autowired
  14. SkuSaleAttrValueService skuSaleAttrValueService;
  15. @Autowired
  16. CouponFeignService couponFeignService;
  17. @Transactional
  18. @Override
  19. public void saveSpuInfo(SpuSaveVo vo) {
  20. @Transactional
  21. @Override
  22. public void saveSpuInfo(SpuSaveVo vo) {
  23. //1、保存spu基本信息 pms_spu_info
  24. SpuInfoEntity spuInfo = new SpuInfoEntity();
  25. BeanUtils.copyProperties(vo, spuInfo);
  26. spuInfo.setCreateTime(new Date()); // mybatis-plus设置自动填充注解 @TableField(fill = FieldFill.INSERT)
  27. spuInfo.setUpdateTime(new Date()); // mybatis-plus设置自动填充注解 @TableField(fill = FieldFill.INSERT_UPDATE)
  28. //this.save(spuInfo); // 为啥不直接使用自带的save方法?
  29. this.saveBaseInfo(spuInfo);
  30. //2、保存spu的描述图片 pms_spu_info_desc
  31. List<String> decript = vo.getDecript();
  32. SpuInfoDescEntity descEntity = new SpuInfoDescEntity();
  33. descEntity.setSpuId(spuInfo.getId()); // 保存后,id会自动封装到实体类中
  34. descEntity.setDecript(String.join(",", decript));
  35. // infoDescService.save(descEntity); //为啥不直接用infoDescService的save方法。。。
  36. infoDescService.saveSpuInfoDesc(descEntity);
  37. //3、保存spu的图片集 pms_spu_images
  38. List<String> images = vo.getImages(); // 获取SpuSaveVo里的图片集
  39. spuImagesService.saveImages(spuInfo.getId(), images); // 保存图片集
  40. //4、保存spu的规格参数 pms_product_attr_value
  41. List<BaseAttrs> baseAttrs = vo.getBaseAttrs(); // 获取spu的规格参数
  42. List<ProductAttrValueEntity> attrValueEntityList = baseAttrs.stream().map((item) -> {
  43. ProductAttrValueEntity productAttrValueEntity = new ProductAttrValueEntity();
  44. productAttrValueEntity.setAttrId(item.getAttrId());
  45. AttrEntity attrEntity = attrService.getById(item.getAttrId());
  46. productAttrValueEntity.setAttrName(attrEntity.getAttrName());
  47. productAttrValueEntity.setAttrValue(item.getAttrValues());
  48. productAttrValueEntity.setQuickShow(item.getShowDesc());
  49. productAttrValueEntity.setSpuId(spuInfo.getId());
  50. return productAttrValueEntity;
  51. }).collect(Collectors.toList());
  52. // attrValueService.saveBatch(attrValueEntityList); // 这里直接saveBatch就行
  53. attrValueService.saveProductAttr(attrValueEntityList); // 创建新方法也是在新方法中调用saveBatch。。
  54. //5、保存spu的积分信息 gulimall_sms->sms_spu_bounds 与需要远程调用gulimall-coupon服务
  55. // coupon有一个SpuBoundsController
  56. // 查看数据库 我们需要传 spu_id grow_bounds buy_bounds过去
  57. //6、保存当前spu对应的所有sku信息
  58. // 从vo中获取提交的所有sku
  59. List<Skus> skus = vo.getSkus();
  60. if (!CollectionUtils.isEmpty(skus)) { // 一定要判断不为空
  61. skus.forEach(item -> { // 遍历每个skuVo对象,将其中的信息保存
  62. //6.1 保存sku的基本信息 pms_sku_info
  63. SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
  64. // 只有skuName、skuTitle、skuSubtitle、price可以直接拷贝
  65. BeanUtils.copyProperties(item, skuInfoEntity);
  66. skuInfoEntity.setBrandId(spuInfo.getBrandId()); // brandId
  67. skuInfoEntity.setCatalogId(spuInfo.getCatalogId()); //catelogId
  68. skuInfoEntity.setSaleCount(0L); // saleCount
  69. skuInfoEntity.setSpuId(spuInfo.getId()); // spuId
  70. // 寻找每个sku的默认图片
  71. String defaultImag = "";
  72. for (Images image : item.getImages()) {
  73. // 每个Images对象中有一个defaultImg属性,如果为1则表示该图片为默认图片
  74. if (image.getDefaultImg() == 1) {
  75. defaultImag = image.getImgUrl();
  76. }
  77. }
  78. skuInfoEntity.setSkuDefaultImg(defaultImag); // 默认图片从sku的images中获取
  79. //skuInfoService.save(skuInfoEntity);
  80. skuInfoService.saveSkuInfo(skuInfoEntity); // 保存SKU信息,这样sku的自增主键就出来了
  81. //6.2 保存sku的图片信息 pms_sku_images
  82. // sku_id img_url default_img
  83. Long skuId = skuInfoEntity.getSkuId();
  84. // 必须要先保存sku,获得skuId后,才能保存图片,因为 pms_sku_images表中需要用到skuId
  85. List<Images> skuImages = item.getImages(); // 从当前sku中获取图片集
  86. // 每个sku图片集中的每个图片Url都会构成pms_sku_images表中的一条记录
  87. List<SkuImagesEntity> skuImagesEntityList = skuImages.stream().map((im) -> {
  88. SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
  89. skuImagesEntity.setSkuId(skuId);
  90. skuImagesEntity.setImgUrl(im.getImgUrl());
  91. skuImagesEntity.setDefaultImg(im.getDefaultImg());
  92. return skuImagesEntity;
  93. }).collect(Collectors.toList());
  94. skuImagesService.saveBatch(skuImagesEntityList);
  95. //6.3 保存sku的销售属性信息 pms_sku_sale_attr_value
  96. // sku_id attr_id attr_name attr_value attr_sort
  97. List<Attr> attr = item.getAttr();
  98. List<SkuSaleAttrValueEntity> attrValueEntities = attr.stream().map(a -> {
  99. SkuSaleAttrValueEntity saleAttrValue = new SkuSaleAttrValueEntity();
  100. BeanUtils.copyProperties(a, saleAttrValue);
  101. saleAttrValue.setSkuId(skuId);
  102. return saleAttrValue;
  103. }).collect(Collectors.toList());
  104. skuSaleAttrValueService.saveBatch(attrValueEntities);
  105. //6.4 保存sku的优惠、满减等信息 gulimall_sms->sms_sku_ladder/sms_sku_full_reduction/sms_member_price
  106. // 这里需要远程调用 gulimall-coupon服务
  107. });
  108. }
  109. }
  110. /**
  111. * 保存spu的基本信息
  112. *
  113. * @param spuInfo
  114. */
  115. @Override
  116. public void saveBaseInfo(SpuInfoEntity spuInfo) {
  117. this.baseMapper.insert(spuInfo);
  118. }
  119. }
  1. /**
  2. * 保存spu的描述信息
  3. * @param descEntity
  4. */
  5. @Override
  6. public void saveSpuInfoDesc(SpuInfoDescEntity descEntity) {
  7. this.baseMapper.insert(descEntity);
  8. }
  1. /**
  2. * 保存spu的图片信息
  3. * @param id
  4. * @param images
  5. */
  6. @Override
  7. public void saveImages(Long id, List<String> images) {
  8. if (!CollectionUtils.isEmpty(images)) {
  9. List<SpuImagesEntity> spuImagesEntityList = images.stream().map((image) -> {
  10. SpuImagesEntity spuImagesEntity = new SpuImagesEntity();
  11. spuImagesEntity.setSpuId(id);
  12. spuImagesEntity.setImgName(image);
  13. return spuImagesEntity;
  14. }).collect(Collectors.toList());
  15. this.saveBatch(spuImagesEntityList);
  16. }
  17. }
  1. @Override
  2. public void saveProductAttr(List<ProductAttrValueEntity> attrValueEntityList) {
  3. this.saveBatch(attrValueEntityList);
  4. }
  1. @Override
  2. public void saveSkuInfo(SkuInfoEntity skuInfoEntity) {
  3. this.baseMapper.insert(skuInfoEntity);
  4. }

远程调用回顾

可以回看之前远程调用的笔记:https://www.yuque.com/mrlinxi/pxvr4g/rdcgap#ijC15

  1. 调用方Service编写一个接口,告诉SpringCloud这个接口需要调用远程服务(一般会放在feign这个包下),会使用到@FeignClient(“需要调用的微服务名”)注解
    1. 这里定义方法接口的方法签名一定要(不一样也可以)和微服务提供者的Controller中调用的方法签名(最好直接复制controller里面的方法)一致。
  • 如果需要传递参数,那么@RequestParam@RequestBody @PathVariable 等不能省略,必需加。
  1. Controller层定义一个与Service层对应的方法
  2. 调用方在主启动类开启远程调用功能 @EnableFeignClient(basePackages=”包路径”)—默认扫描默认会扫描注解所在包的当前包以及子包下的@FeignCilent

将所有需要远程调用的Service接口都写在feign包下。
product主启动类加上@EnableFeignClients注解,并指明包路径

  1. @SpringBootApplication
  2. @EnableDiscoveryClient
  3. @MapperScan(value = "com.atguigu.gulimall.gulimallproduct.dao")
  4. @EnableFeignClients(basePackages = "com.atguigu.gulimall.gulimallproduct.feign")
  5. public class GulimallProductApplication {
  6. public static void main(String[] args) {
  7. SpringApplication.run(GulimallProductApplication.class, args);
  8. }
  9. }

保存spu积分信息远程调用

我们需要将spu_id grow_bounds buy_bounds 传输到gulimall-coupon服务,让其存储到gulimall_sms->sms_spu_bounds表中。
image.png
现在product服务要给coupon传输数据,我们可以将这些数据封装成一个对象。在SpringCloud中,会默认把封装的这个对象转成JSON数据进行传输,那么coupon服务会收到一个JSON数据。
那么我们可以在common的to包下中定义一个TO(数据传输对象——用于不同的应用程序之间传输)

  1. @Data
  2. public class SpuBoundsTo {
  3. private Long spuId;
  4. /**
  5. * 成长积分
  6. */
  7. private BigDecimal growBounds;
  8. /**
  9. * 购物积分
  10. */
  11. private BigDecimal buyBounds;
  12. }

修改gulimall-coupon的SpuBoundsController,将/save请求对应的方法改成@PostMapping

  1. /**
  2. * 保存
  3. */
  4. @PostMapping("/save")
  5. //@RequiresPermissions("gulimallcoupon:spubounds:save")
  6. public R save(@RequestBody SpuBoundsEntity spuBounds){
  7. spuBoundsService.save(spuBounds);
  8. return R.ok();
  9. }

gulimall-product的feign包下,创建一个Service接口,用于远程调用coupon服务。
注意:@PostMapping注解中一定要写完整的请求路径(SpuBoundsController的类路径+方法路径)

  1. package com.atguigu.gulimall.gulimallproduct.feign;
  2. import com.atguigu.common.to.SpuBoundsTo;
  3. import com.atguigu.common.utils.R;
  4. import org.springframework.cloud.openfeign.FeignClient;
  5. import org.springframework.web.bind.annotation.PostMapping;
  6. import org.springframework.web.bind.annotation.RequestBody;
  7. @FeignClient("gulimall-coupon")
  8. public interface CouponFeignService {
  9. /**
  10. * CouponFeignService.saveSpuBounds(spuBoundsTo) 调用方法,传了一个对象
  11. * 1)有@RequestBody注解 会将这个对象转为Json
  12. * 2)找到gulimall-coupon服务,给服务发送/gulimallcoupon/spubounds/save,将上一步转的Json放在请求体位置,发送请求
  13. * 3)对方服务收到请求,收到了请求体中的Json数据
  14. * (@RequestBody SpuBoundsEntity spuBounds) :将请求体中的Json转成SpuBoundsEntity
  15. * 前提是spuBoundsTo中的属性名与SpuBoundsEntity中属性名能对应(spuBoundsTo的属性名是SpuBoundsEntity属性名的子集)
  16. * 只要Json数据模型时兼容的,双方服务无需使用同一个to入参
  17. * @param spuBoundsTo
  18. * @return
  19. */
  20. @PostMapping("/gulimallcoupon/spubounds/save")
  21. R saveSpuBounds(@RequestBody SpuBoundsTo spuBoundsTo);
  22. }

这里我们发现CouponFeignService中方法的入参与SpuBoundsController中对应的方法名以及入参不一致。
方法名不一致其实并不影响调用,只是平时为了方便,直接将需要调用的额方法签名复制过来。
这里着重讲一下,为什么入参可以不同:
CouponFeignService.saveSpuBounds(spuBoundsTo) 调用方法,传了一个对象,这个对象是SpuBoundsTo类,传输流程:

  1. 有@RequestBody注解 会将这个对象转为Json
  2. 找到gulimall-coupon服务,给服务发送/gulimallcoupon/spubounds/save,将上一步转的Json放在请求体位置,发送请求
  3. 对方服务收到请求,收到了请求体中的Json数据
    1. (@RequestBody SpuBoundsEntity spuBounds) :将请求体中的Json转成SpuBoundsEntity
    2. a的前提是spuBoundsTo中的属性名与SpuBoundsEntity中属性名能对应(spuBoundsTo的属性名是SpuBoundsEntity属性名的子集)

总结:只要Json数据模型时兼容的,双方服务无需使用同一个to入参
SpuInfoServiceImpl中调用(这里只展示了代码片段,完整版看后面)

  1. //5、保存spu的积分信息 gulimall_sms->sms_spu_bounds 与需要远程调用gulimall-coupon服务
  2. // coupon有一个SpuBoundsController
  3. // 查看数据库 我们需要传 spu_id grow_bounds buy_bounds过去
  4. Bounds bounds = vo.getBounds(); // Bounds类中有 grow_bounds buy_bounds过去
  5. SpuBoundsTo spuBoundsTo = new SpuBoundsTo();
  6. BeanUtils.copyProperties(bounds, spuBoundsTo);
  7. spuBoundsTo.setSpuId(spuInfo.getId());
  8. couponFeignService.saveSpuBounds(spuBoundsTo);

保存sku的优惠、满减等信息

common中新建一个SkuReductionTo to类

  1. @Data
  2. public class SkuReductionTo {
  3. private Long skuId;
  4. // 打折信息
  5. private int fullCount;
  6. private BigDecimal discount;
  7. private int countStatus;
  8. private BigDecimal fullPrice;
  9. private BigDecimal reducePrice;
  10. private int priceStatus;
  11. private List<MemberPrice> memberPrice;
  12. }

CouponFeignService,声明调用gulimall-coupon的方法

  1. @PostMapping("/gulimallcoupon/skufullreduction/saveinfo")
  2. R saveSkuReduction(@RequestBody SkuReductionTo skuReductionTo);

gulimall-coupon SkuFullReductionController中创建对应方法

  1. @PostMapping("/saveinfo")
  2. //@RequiresPermissions("gulimallcoupon:skufullreduction:list")
  3. public R saveInfo(@RequestBody SkuReductionTo skuReductionTo){
  4. skuFullReductionService.saveSkuReduction(skuReductionTo);
  5. return R.ok();
  6. }

声明&实现

  1. @Autowired
  2. SkuLadderService skuLadderService;
  3. @Autowired
  4. MemberPriceService memberPriceService;
  5. @Override
  6. public void saveSkuReduction(SkuReductionTo skuReductionTo) {
  7. // 6.4 保存sku的优惠、满减、会员价格等信息 gulimall_sms->sms_sku_ladder/sms_sku_full_reduction/sms_member_price
  8. // 1、保存数量满减打折优惠信息 sms_sku_ladder (sku_id full_count discount price add_other)
  9. SkuLadderEntity skuLadderEntity = new SkuLadderEntity();
  10. skuLadderEntity.setSkuId(skuReductionTo.getSkuId()); // skuId
  11. skuLadderEntity.setFullCount(skuReductionTo.getFullCount()); //满几件
  12. skuLadderEntity.setDiscount(skuReductionTo.getDiscount()); // 打几折
  13. skuLadderEntity.setAddOther(skuReductionTo.getCountStatus()); // 是否与其他优惠叠加
  14. skuLadderService.save(skuLadderEntity);
  15. // 2、保存 满多少金额,减多少钱 优惠信息
  16. // sms_sku_full_reduction (sku_id full_price reduce_price add_other)
  17. SkuFullReductionEntity skuFullReductionEntity = new SkuFullReductionEntity();
  18. BeanUtils.copyProperties(skuReductionTo, skuFullReductionEntity); // 传过来的对象包含了金额满减的信息,且属性名对应直接copy
  19. this.save(skuFullReductionEntity);
  20. // 3、保存 会员价格
  21. // sms_member_price (sku_id member_level_id member_level_name member_price add_other)
  22. List<MemberPrice> memberPrice = skuReductionTo.getMemberPrice(); // 获取当前sku不同会员价格信息
  23. List<MemberPriceEntity> memberPriceEntities = memberPrice.stream().map(member -> {
  24. MemberPriceEntity memberPriceEntity = new MemberPriceEntity();
  25. memberPriceEntity.setSkuId(skuReductionTo.getSkuId()); // 获取skuId
  26. memberPriceEntity.setMemberLevelId(member.getId()); // 获取会员等级Id
  27. memberPriceEntity.setMemberLevelName(member.getName()); // 获取会员等级名
  28. memberPriceEntity.setMemberPrice(member.getPrice()); // 会员价格
  29. memberPriceEntity.setAddOther(1); // 是否可与其他优惠叠加
  30. return memberPriceEntity;
  31. }).collect(Collectors.toList());
  32. memberPriceService.saveBatch(memberPriceEntities);
  33. }

在SpuInfoServiceImpl中调用,这里只展示了针对当前业务的代码片段,最终完整代码看后面

  1. //6.4 保存sku的优惠、满减会员价格等信息 gulimall_sms->sms_sku_ladder/sms_sku_full_reduction/sms_member_price
  2. // 这里需要远程调用 gulimall-coupon服务
  3. SkuReductionTo skuReductionTo = new SkuReductionTo();
  4. BeanUtils.copyProperties(item, skuReductionTo); // 直接把当前遍历的Sku拷贝过去
  5. skuReductionTo.setSkuId(skuInfoEntity.getSkuId()); // 先前保存了sku,生成了一个skuId,设置skuId
  6. couponFeignService.saveSkuReduction(skuReductionTo);

其他改动

远程调用之后我们需要验证一下是否成功。在R中新增一个获得code的方法(R继承了HashMap)

  1. public Integer getCode() {
  2. return Integer.parseInt((String) this.get("code"));
  3. }

分别在SpuInfoServiceImpl里两个远程调用的地方判断一下是否成功。

SpuInfoServiceImpl全部实现

  1. @Transactional
  2. @Override
  3. public void saveSpuInfo(SpuSaveVo vo) {
  4. //1、保存spu基本信息 pms_spu_info
  5. SpuInfoEntity spuInfo = new SpuInfoEntity();
  6. BeanUtils.copyProperties(vo, spuInfo);
  7. spuInfo.setCreateTime(new Date()); // mybatis-plus设置自动填充注解 @TableField(fill = FieldFill.INSERT)
  8. spuInfo.setUpdateTime(new Date()); // mybatis-plus设置自动填充注解 @TableField(fill = FieldFill.INSERT_UPDATE)
  9. //this.save(spuInfo); // 为啥不直接使用自带的save方法?
  10. this.saveBaseInfo(spuInfo);
  11. //2、保存spu的描述图片 pms_spu_info_desc
  12. List<String> decript = vo.getDecript();
  13. SpuInfoDescEntity descEntity = new SpuInfoDescEntity();
  14. descEntity.setSpuId(spuInfo.getId()); // 保存后,id会自动封装到实体类中
  15. descEntity.setDecript(String.join(",", decript));
  16. // infoDescService.save(descEntity); //为啥不直接用infoDescService的save方法。。。
  17. infoDescService.saveSpuInfoDesc(descEntity);
  18. //3、保存spu的图片集 pms_spu_images
  19. List<String> images = vo.getImages(); // 获取SpuSaveVo里的图片集
  20. spuImagesService.saveImages(spuInfo.getId(), images); // 保存图片集
  21. //4、保存spu的规格参数 pms_product_attr_value
  22. List<BaseAttrs> baseAttrs = vo.getBaseAttrs(); // 获取spu的规格参数
  23. List<ProductAttrValueEntity> attrValueEntityList = baseAttrs.stream().map((item) -> {
  24. ProductAttrValueEntity productAttrValueEntity = new ProductAttrValueEntity();
  25. productAttrValueEntity.setAttrId(item.getAttrId());
  26. AttrEntity attrEntity = attrService.getById(item.getAttrId());
  27. productAttrValueEntity.setAttrName(attrEntity.getAttrName());
  28. productAttrValueEntity.setAttrValue(item.getAttrValues());
  29. productAttrValueEntity.setQuickShow(item.getShowDesc());
  30. productAttrValueEntity.setSpuId(spuInfo.getId());
  31. return productAttrValueEntity;
  32. }).collect(Collectors.toList());
  33. // attrValueService.saveBatch(attrValueEntityList); // 这里直接saveBatch就行
  34. attrValueService.saveProductAttr(attrValueEntityList); // 创建新方法也是在新方法中调用saveBatch。。
  35. //5、保存spu的积分信息 gulimall_sms->sms_spu_bounds 与需要远程调用gulimall-coupon服务
  36. // coupon有一个SpuBoundsController
  37. // 查看数据库 我们需要传 spu_id grow_bounds buy_bounds过去
  38. Bounds bounds = vo.getBounds(); // Bounds类中有 grow_bounds buy_bounds过去
  39. SpuBoundsTo spuBoundsTo = new SpuBoundsTo();
  40. BeanUtils.copyProperties(bounds, spuBoundsTo);
  41. spuBoundsTo.setSpuId(spuInfo.getId());
  42. R r = couponFeignService.saveSpuBounds(spuBoundsTo);
  43. if (r.getCode() != 0) {
  44. log.error("远程调用gulimall-coupon保存spu的积分信息失败...............");
  45. }
  46. //6、保存当前spu对应的所有sku信息
  47. // 从vo中获取提交的所有sku
  48. List<Skus> skus = vo.getSkus();
  49. if (!CollectionUtils.isEmpty(skus)) { // 一定要判断不为空
  50. skus.forEach(item -> { // 遍历每个skuVo对象,将其中的信息保存
  51. //6.1 保存sku的基本信息 pms_sku_info
  52. SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
  53. // 只有skuName、skuTitle、skuSubtitle、price可以直接拷贝
  54. BeanUtils.copyProperties(item, skuInfoEntity);
  55. skuInfoEntity.setBrandId(spuInfo.getBrandId()); // brandId
  56. skuInfoEntity.setCatalogId(spuInfo.getCatalogId()); //catelogId
  57. skuInfoEntity.setSaleCount(0L); // saleCount
  58. skuInfoEntity.setSpuId(spuInfo.getId()); // spuId
  59. // 寻找每个sku的默认图片
  60. String defaultImag = "";
  61. for (Images image : item.getImages()) {
  62. // 每个Images对象中有一个defaultImg属性,如果为1则表示该图片为默认图片
  63. if (image.getDefaultImg() == 1) {
  64. defaultImag = image.getImgUrl();
  65. }
  66. }
  67. skuInfoEntity.setSkuDefaultImg(defaultImag); // 默认图片从sku的images中获取
  68. //skuInfoService.save(skuInfoEntity);
  69. skuInfoService.saveSkuInfo(skuInfoEntity); // 保存SKU信息,这样sku的自增主键就出来了
  70. //6.2 保存sku的图片信息 pms_sku_images
  71. // sku_id img_url default_img
  72. Long skuId = skuInfoEntity.getSkuId();
  73. // 必须要先保存sku,获得skuId后,才能保存图片,因为 pms_sku_images表中需要用到skuId
  74. List<Images> skuImages = item.getImages(); // 从当前sku中获取图片集
  75. // 每个sku图片集中的每个图片Url都会构成pms_sku_images表中的一条记录
  76. List<SkuImagesEntity> skuImagesEntityList = skuImages.stream().map((im) -> {
  77. SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
  78. skuImagesEntity.setSkuId(skuId);
  79. skuImagesEntity.setImgUrl(im.getImgUrl());
  80. skuImagesEntity.setDefaultImg(im.getDefaultImg());
  81. return skuImagesEntity;
  82. }).collect(Collectors.toList());
  83. skuImagesService.saveBatch(skuImagesEntityList);
  84. //6.3 保存sku的销售属性信息 pms_sku_sale_attr_value
  85. // sku_id attr_id attr_name attr_value attr_sort
  86. List<Attr> attr = item.getAttr();
  87. List<SkuSaleAttrValueEntity> attrValueEntities = attr.stream().map(a -> {
  88. SkuSaleAttrValueEntity saleAttrValue = new SkuSaleAttrValueEntity();
  89. BeanUtils.copyProperties(a, saleAttrValue);
  90. saleAttrValue.setSkuId(skuId);
  91. return saleAttrValue;
  92. }).collect(Collectors.toList());
  93. skuSaleAttrValueService.saveBatch(attrValueEntities);
  94. //6.4 保存sku的满减(数量满减&金额满减)、会员价格等信息 gulimall_sms->sms_sku_ladder/sms_sku_full_reduction/sms_member_price
  95. // 这里需要远程调用 gulimall-coupon服务
  96. SkuReductionTo skuReductionTo = new SkuReductionTo();
  97. BeanUtils.copyProperties(item, skuReductionTo); // 直接把当前遍历的Sku拷贝过去
  98. skuReductionTo.setSkuId(skuInfoEntity.getSkuId()); // 先前保存了sku,生成了一个skuId,设置skuId
  99. R r1 = couponFeignService.saveSkuReduction(skuReductionTo);
  100. if (r1.getCode() != 0) {
  101. log.error("远程调用gulimall-coupon保存sku的满减(数量满减&金额满减)、会员价格失败...............");
  102. }
  103. });
  104. }
  105. }

1.4.3 测试

因为微服务很多,所以可以设置一下每个服务的内存占用。
image.png
image.png创建一个Compound,将需要频繁重启的服务加进去,就可以批量重启。再设置每个微服务最大占用内存
image.png
image.png
以debug模式启动product服务,前端提交数据
image.png
先报存spu的基本信息,查看数据库,发现并没有保存。这是因为我们开启了事务,而Mysql的默认事务隔离级别是可重复读。
我们设置一下mysql的隔离界别为读未提交:
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
现在pms_spu_info表中可以看到spu的信息
image.png

视频里在pms_spu_info_desc表中新建记录的时候报错(我实操没有报错),因为pms_spu_info_desc表中的spuId不是自增主键,而是手动进行输入的,所以需要修改SpuInfoDescEntity的spuId属性:
image.png
因为我用的nacos2.0.3,注册跟配置都没有问题,结果在远程调用的时候报错。这个没有找到解决方法(重启nacos就好了。。。。)

ERROR 24636 —- [t.remote.worker] c.a.n.c.remote.client.grpc.GrpcClient : Server check fail, please check server localhost ,port 9848 is available , error ={}

远程超时问题:在product设置一下超时时间

  1. #设置feign客户端超时时间(OpenFeign默认支持ribbon)
  2. ribbon:
  3. #指的是建立连接后从服务器读取到可用资源所用的时间 ms
  4. ReadTimeout: 5000
  5. #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间 ms
  6. ConnectTimeout: 5000

sku_images中保存了没有选中的图片:(TODO没有图片路径的无须保存)
image.png
同样,满减信息里面满0元减0元,满0件不打折也都不需要存储。
image.png
image.png

image.png
出现这个错误是因为我们在后台debug的时间太长,超时了。
spu_bounds表没有回滚

sku_images不保存没有图片路径的信息

通过filter函数式接口过滤

  1. //6.2 保存sku的图片信息 pms_sku_images
  2. // sku_id img_url default_img
  3. Long skuId = skuInfoEntity.getSkuId();
  4. // 必须要先保存sku,获得skuId后,才能保存图片,因为 pms_sku_images表中需要用到skuId
  5. List<Images> skuImages = item.getImages(); // 从当前sku中获取图片集
  6. // 每个sku图片集中的每个图片Url都会构成pms_sku_images表中的一条记录
  7. List<SkuImagesEntity> skuImagesEntityList = skuImages.stream().map((im) -> {
  8. SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
  9. skuImagesEntity.setSkuId(skuId);
  10. skuImagesEntity.setImgUrl(im.getImgUrl());
  11. skuImagesEntity.setDefaultImg(im.getDefaultImg());
  12. return skuImagesEntity;
  13. }).filter(emtity -> {
  14. // filter中,返回true就是保留,返回false就是剔除
  15. return !StringUtils.isEmpty(emtity.getImgUrl());
  16. }).collect(Collectors.toList());
  17. skuImagesService.saveBatch(skuImagesEntityList);

满减信息过滤

在保存sku优惠信息的时候,只需要保存存在的件数折扣、金额满减、会员价格。所以需要一个判断。(视频里面没有hashMemberPrice,会导致当没有件数折扣和金额满减时无法保存会员信息)
最开是我给hashMemberPrice传的是skuReductionTo.getMemberPrice() 但是一直报类型转换异常,没办法只能传Item的MemberPrice了。

  1. //6.4 保存sku的满减(数量满减&金额满减)、会员价格等信息 gulimall_sms->sms_sku_ladder/sms_sku_full_reduction/sms_member_price
  2. // 这里需要远程调用 gulimall-coupon服务
  3. SkuReductionTo skuReductionTo = new SkuReductionTo();
  4. BeanUtils.copyProperties(item, skuReductionTo); // 直接把当前遍历的Sku拷贝过去
  5. skuReductionTo.setSkuId(skuInfoEntity.getSkuId()); // 先前保存了sku,生成了一个skuId,设置skuId
  6. // 当存在多件打折信息或者金额满减信息时,满减信息才会保存,同时需要考虑没有满减信息但存在会员价格的情况
  7. if (hasMemberPrice(item.getMemberPrice()) || skuReductionTo.getFullCount() > 0 || skuReductionTo.getFullPrice().compareTo(BigDecimal.ZERO) > 0) {
  8. R r1 = couponFeignService.saveSkuReduction(skuReductionTo);
  9. if (r1.getCode() != 0) {
  10. log.error("远程调用gulimall-coupon保存sku的满减(数量满减&金额满减)、会员价格失败...............");
  11. }
  12. }
  13. /**
  14. * 判断会员价格是否存在
  15. * @param memberPrices
  16. * @return
  17. */
  18. private boolean hasMemberPrice(List<com.atguigu.gulimall.gulimallproduct.vo.spu.MemberPrice> memberPrices) {
  19. for (com.atguigu.gulimall.gulimallproduct.vo.spu.MemberPrice memberPrice : memberPrices) {
  20. if (memberPrice.getPrice().compareTo(BigDecimal.ZERO) > 0) return true;
  21. }
  22. return false;
  23. }

修改后的代码

这里修改主要是针对优惠信息的bug进行修改。

  1. @Transactional
  2. @Override
  3. public void saveSpuInfo(SpuSaveVo vo) {
  4. //1、保存spu基本信息 pms_spu_info
  5. SpuInfoEntity spuInfo = new SpuInfoEntity();
  6. BeanUtils.copyProperties(vo, spuInfo);
  7. spuInfo.setCreateTime(new Date()); // mybatis-plus设置自动填充注解 @TableField(fill = FieldFill.INSERT)
  8. spuInfo.setUpdateTime(new Date()); // mybatis-plus设置自动填充注解 @TableField(fill = FieldFill.INSERT_UPDATE)
  9. //this.save(spuInfo); // 为啥不直接使用自带的save方法?
  10. this.saveBaseInfo(spuInfo);
  11. //2、保存spu的描述图片 pms_spu_info_desc
  12. List<String> decript = vo.getDecript();
  13. SpuInfoDescEntity descEntity = new SpuInfoDescEntity();
  14. descEntity.setSpuId(spuInfo.getId()); // 保存后,id会自动封装到实体类中
  15. descEntity.setDecript(String.join(",", decript));
  16. // infoDescService.save(descEntity); //为啥不直接用infoDescService的save方法。。。
  17. infoDescService.saveSpuInfoDesc(descEntity);
  18. //3、保存spu的图片集 pms_spu_images
  19. List<String> images = vo.getImages(); // 获取SpuSaveVo里的图片集
  20. spuImagesService.saveImages(spuInfo.getId(), images); // 保存图片集
  21. //4、保存spu的规格参数 pms_product_attr_value
  22. List<BaseAttrs> baseAttrs = vo.getBaseAttrs(); // 获取spu的规格参数
  23. List<ProductAttrValueEntity> attrValueEntityList = baseAttrs.stream().map((item) -> {
  24. ProductAttrValueEntity productAttrValueEntity = new ProductAttrValueEntity();
  25. productAttrValueEntity.setAttrId(item.getAttrId());
  26. AttrEntity attrEntity = attrService.getById(item.getAttrId());
  27. productAttrValueEntity.setAttrName(attrEntity.getAttrName());
  28. productAttrValueEntity.setAttrValue(item.getAttrValues());
  29. productAttrValueEntity.setQuickShow(item.getShowDesc());
  30. productAttrValueEntity.setSpuId(spuInfo.getId());
  31. return productAttrValueEntity;
  32. }).collect(Collectors.toList());
  33. // attrValueService.saveBatch(attrValueEntityList); // 这里直接saveBatch就行
  34. attrValueService.saveProductAttr(attrValueEntityList); // 创建新方法也是在新方法中调用saveBatch。。
  35. //5、保存spu的积分信息 gulimall_sms->sms_spu_bounds 与需要远程调用gulimall-coupon服务
  36. // coupon有一个SpuBoundsController
  37. // 查看数据库 我们需要传 spu_id grow_bounds buy_bounds过去
  38. Bounds bounds = vo.getBounds(); // Bounds类中有 grow_bounds buy_bounds过去
  39. SpuBoundsTo spuBoundsTo = new SpuBoundsTo();
  40. BeanUtils.copyProperties(bounds, spuBoundsTo);
  41. spuBoundsTo.setSpuId(spuInfo.getId());
  42. R r = couponFeignService.saveSpuBounds(spuBoundsTo);
  43. if (r.getCode() != 0) {
  44. log.error("远程调用gulimall-coupon保存spu的积分信息失败...............");
  45. }
  46. //6、保存当前spu对应的所有sku信息
  47. // 从vo中获取提交的所有sku
  48. List<Skus> skus = vo.getSkus();
  49. if (!CollectionUtils.isEmpty(skus)) { // 一定要判断不为空
  50. skus.forEach(item -> { // 遍历每个skuVo对象,将其中的信息保存
  51. //6.1 保存sku的基本信息 pms_sku_info
  52. SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
  53. // 只有skuName、skuTitle、skuSubtitle、price可以直接拷贝
  54. BeanUtils.copyProperties(item, skuInfoEntity);
  55. skuInfoEntity.setBrandId(spuInfo.getBrandId()); // brandId
  56. skuInfoEntity.setCatalogId(spuInfo.getCatalogId()); //catelogId
  57. skuInfoEntity.setSaleCount(0L); // saleCount
  58. skuInfoEntity.setSpuId(spuInfo.getId()); // spuId
  59. // 寻找每个sku的默认图片
  60. String defaultImag = "";
  61. for (Images image : item.getImages()) {
  62. // 每个Images对象中有一个defaultImg属性,如果为1则表示该图片为默认图片
  63. if (image.getDefaultImg() == 1) {
  64. defaultImag = image.getImgUrl();
  65. }
  66. }
  67. skuInfoEntity.setSkuDefaultImg(defaultImag); // 默认图片从sku的images中获取
  68. //skuInfoService.save(skuInfoEntity);
  69. skuInfoService.saveSkuInfo(skuInfoEntity); // 保存SKU信息,这样sku的自增主键就出来了
  70. //6.2 保存sku的图片信息 pms_sku_images
  71. // sku_id img_url default_img
  72. Long skuId = skuInfoEntity.getSkuId();
  73. // 必须要先保存sku,获得skuId后,才能保存图片,因为 pms_sku_images表中需要用到skuId
  74. List<Images> skuImages = item.getImages(); // 从当前sku中获取图片集
  75. // 每个sku图片集中的每个图片Url都会构成pms_sku_images表中的一条记录
  76. List<SkuImagesEntity> skuImagesEntityList = skuImages.stream().map((im) -> {
  77. SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
  78. skuImagesEntity.setSkuId(skuId);
  79. skuImagesEntity.setImgUrl(im.getImgUrl());
  80. skuImagesEntity.setDefaultImg(im.getDefaultImg());
  81. return skuImagesEntity;
  82. }).filter(emtity -> {
  83. // filter中,返回true就是保留,返回false就是剔除
  84. return !StringUtils.isEmpty(emtity.getImgUrl());
  85. }).collect(Collectors.toList());
  86. skuImagesService.saveBatch(skuImagesEntityList);
  87. //6.3 保存sku的销售属性信息 pms_sku_sale_attr_value
  88. // sku_id attr_id attr_name attr_value attr_sort
  89. List<Attr> attr = item.getAttr();
  90. List<SkuSaleAttrValueEntity> attrValueEntities = attr.stream().map(a -> {
  91. SkuSaleAttrValueEntity saleAttrValue = new SkuSaleAttrValueEntity();
  92. BeanUtils.copyProperties(a, saleAttrValue);
  93. saleAttrValue.setSkuId(skuId);
  94. return saleAttrValue;
  95. }).collect(Collectors.toList());
  96. skuSaleAttrValueService.saveBatch(attrValueEntities);
  97. //6.4 保存sku的满减(数量满减&金额满减)、会员价格等信息 gulimall_sms->sms_sku_ladder/sms_sku_full_reduction/sms_member_price
  98. // 这里需要远程调用 gulimall-coupon服务
  99. SkuReductionTo skuReductionTo = new SkuReductionTo();
  100. BeanUtils.copyProperties(item, skuReductionTo); // 直接把当前遍历的Sku拷贝过去
  101. skuReductionTo.setSkuId(skuInfoEntity.getSkuId()); // 先前保存了sku,生成了一个skuId,设置skuId
  102. // 当存在多件打折信息或者金额满减信息时,满减信息才会保存,同时需要考虑没有满减信息但存在会员价格的情况
  103. if (hasMemberPrice(item.getMemberPrice()) || skuReductionTo.getFullCount() > 0 || skuReductionTo.getFullPrice().compareTo(BigDecimal.ZERO) > 0) {
  104. R r1 = couponFeignService.saveSkuReduction(skuReductionTo);
  105. if (r1.getCode() != 0) {
  106. log.error("远程调用gulimall-coupon保存sku的满减(数量满减&金额满减)、会员价格失败...............");
  107. }
  108. }
  109. });
  110. }
  111. }
  1. @Override
  2. public void saveSkuReduction(SkuReductionTo skuReductionTo) {
  3. // 6.4 保存sku的优惠、满减、会员价格等信息 gulimall_sms->sms_sku_ladder/sms_sku_full_reduction/sms_member_price
  4. // 1、保存数量满减打折优惠信息 sms_sku_ladder (sku_id full_count discount price add_other)
  5. SkuLadderEntity skuLadderEntity = new SkuLadderEntity();
  6. if (skuReductionTo.getFullCount() > 0) { // 存在数量满减才保存
  7. skuLadderEntity.setSkuId(skuReductionTo.getSkuId()); // skuId
  8. skuLadderEntity.setFullCount(skuReductionTo.getFullCount()); //满几件
  9. skuLadderEntity.setDiscount(skuReductionTo.getDiscount());
  10. skuLadderEntity.setAddOther(skuReductionTo.getCountStatus()); // 是否与其他优惠叠加
  11. skuLadderService.save(skuLadderEntity);
  12. }
  13. // 2、保存 满多少金额,减多少钱 优惠信息
  14. // sms_sku_full_reduction (sku_id full_price reduce_price add_other)
  15. SkuFullReductionEntity skuFullReductionEntity = new SkuFullReductionEntity();
  16. if (skuReductionTo.getFullPrice().compareTo(BigDecimal.ZERO) > 0) { // 存在金额满减才保存
  17. BeanUtils.copyProperties(skuReductionTo, skuFullReductionEntity); // 传过来的对象包含了金额满减的信息,且属性名对应直接copy
  18. this.save(skuFullReductionEntity);
  19. }
  20. // 3、保存 会员价格
  21. // sms_member_price (sku_id member_level_id member_level_name member_price add_other)
  22. List<MemberPrice> memberPrice = skuReductionTo.getMemberPrice(); // 获取当前sku不同会员价格信息
  23. List<MemberPriceEntity> memberPriceEntities = memberPrice.stream().map(member -> {
  24. MemberPriceEntity memberPriceEntity = new MemberPriceEntity();
  25. memberPriceEntity.setSkuId(skuReductionTo.getSkuId()); // 获取skuId
  26. memberPriceEntity.setMemberLevelId(member.getId()); // 获取会员等级Id
  27. memberPriceEntity.setMemberLevelName(member.getName()); // 获取会员等级名
  28. memberPriceEntity.setMemberPrice(member.getPrice()); // 会员价格
  29. memberPriceEntity.setAddOther(1); // 是否可与其他优惠叠加
  30. return memberPriceEntity;
  31. }).filter(memberPriceEntity -> memberPriceEntity.getMemberPrice().compareTo(BigDecimal.ZERO) == 1).collect(Collectors.toList());
  32. memberPriceService.saveBatch(memberPriceEntities);
  33. }

暂未解决的问题

sms_spu_bounds表无法回滚,分布式事务的问题有待解决。// 高级部分完善
视频中没有判断MemberPrice,导致当没有件数折扣和金额满减时无法保存会员信息(我这里修复了这个bug)

二、spu管理

2.1 spu检索

image.png
https://easydoc.net/s/78237135/ZUqEdvA4/9LISLvy7 spu检索接口文档

  1. /**
  2. * 列表
  3. */
  4. @RequestMapping("/list")
  5. //@RequiresPermissions("gulimallproduct:spuinfo:list")
  6. public R list(@RequestParam Map<String, Object> params){
  7. // PageUtils page = spuInfoService.queryPage(params);
  8. PageUtils page = spuInfoService.queryPageByCondition(params);
  9. return R.ok().put("page", page);
  10. }

声明&实现

  1. @Override
  2. public PageUtils queryPageByCondition(Map<String, Object> params) {
  3. QueryWrapper<SpuInfoEntity> wrapper = new QueryWrapper<>();
  4. String key = (String) params.get("key");
  5. // SELECT * FROM pms_spu_info WHERE
  6. if (!StringUtils.isEmpty(key)) {
  7. wrapper.and((w) -> {
  8. w.eq("id", key).or().like("spu_name", key);
  9. });
  10. }
  11. // status = 1 and (id = 1 or spu_name like xxx)
  12. String status = (String) params.get("status");
  13. if (!StringUtils.isEmpty(status)) {
  14. wrapper.eq("publish_status", status);
  15. }
  16. String brandId = (String) params.get("brandId");
  17. if (!StringUtils.isEmpty(key) && !"0".equalsIgnoreCase(brandId)) { // 判断不为0,为保证初始化状态下能查到所有数据
  18. wrapper.eq("brand_id", brandId);
  19. }
  20. String catelogId = (String) params.get("catelogId");
  21. if (!StringUtils.isEmpty(key) && !"0".equalsIgnoreCase(brandId)) { // 判断不为0,为保证初始化状态下能查到所有数据
  22. wrapper.eq("catalog_id", catelogId); // 这里数据库是catalog_id 可能是打错了
  23. }
  24. IPage<SpuInfoEntity> page = this.page(
  25. new Query<SpuInfoEntity>().getPage(params), wrapper);
  26. return new PageUtils(page);
  27. }

检索成功实现,但是可以发现时间戳的格式不符合规范。
image.png
想要符合规范,可以通过配置文件中配置spring.jackson.date-format,这样我们写出的日期数据,均会按照指定的格式进行格式化

  1. spring:
  2. jackson:
  3. date-format: yyyy-MM-dd HH:mm:ss

image.png

2.2 spu规格维护

这里视频P100才讲 跳转:https://www.yuque.com/mrlinxi/pxvr4g/zsn9l9#aKisn

三、商品管理

https://easydoc.net/s/78237135/ZUqEdvA4/ucirLq1D 商品管理检索的是sku的信息

  1. /**
  2. * 列表 按照检索条件对sku进行分页查询
  3. */
  4. @RequestMapping("/list")
  5. //@RequiresPermissions("gulimallproduct:skuinfo:list")
  6. public R list(@RequestParam Map<String, Object> params){
  7. // PageUtils page = skuInfoService.queryPage(params);
  8. PageUtils page = skuInfoService.queryPageByCondition(params);
  9. return R.ok().put("page", page);
  10. }
  1. /**
  2. * 按照检索条件对sku进行分页查询
  3. *
  4. * @param params
  5. * @return
  6. */
  7. @Override
  8. public PageUtils queryPageByCondition(Map<String, Object> params) {
  9. QueryWrapper<SkuInfoEntity> wrapper = new QueryWrapper<>();
  10. /**
  11. * key: 华为
  12. * catelogId: 225
  13. * brandId: 9
  14. * min: 500
  15. * max: 10000
  16. */
  17. String key = (String) params.get("key");
  18. if (!StringUtils.isEmpty(key)) {
  19. wrapper.and(w -> {
  20. w.eq("sku_id", key).or().like("sku_name", key);
  21. });
  22. }
  23. String catelogId = (String) params.get("catelogId");
  24. if (!StringUtils.isEmpty(catelogId) && !"0".equalsIgnoreCase(catelogId)) { // 判断不为0,为保证初始化状态下能查到所有数据
  25. wrapper.eq("catalog_id", catelogId);
  26. }
  27. String brandId = (String) params.get("brandId");
  28. if (!StringUtils.isEmpty(brandId) && !"0".equalsIgnoreCase(brandId)) { // 判断不为0,为保证初始化状态下能查到所有数据
  29. wrapper.eq("brand_id", brandId);
  30. }
  31. String min = (String) params.get("min");
  32. if (!StringUtils.isEmpty(min)) {
  33. wrapper.ge("price", min); // ge表示大于等于
  34. }
  35. String max = (String) params.get("max");
  36. if (!StringUtils.isEmpty(max)) {
  37. try {
  38. BigDecimal maxPrice = new BigDecimal(max);
  39. if (maxPrice.compareTo(BigDecimal.ZERO) > 0) {
  40. wrapper.le("price", max); // le表示小于等于
  41. }
  42. } catch (Exception e) {
  43. e.printStackTrace();
  44. }
  45. }
  46. IPage<SkuInfoEntity> page = this.page(
  47. new Query<SkuInfoEntity>().getPage(params),
  48. wrapper
  49. );
  50. return new PageUtils(page);
  51. }