# 商品服务 ## 1.新增商品 ### 1.1 品牌的关联 #### 1.1.1 PubSub依赖缺失 打开新增商品页面的时候会出现的错误提示: ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/b1b4a6b9a7624e849280d6828ed4f9a1.png) 原因是缺少:PubSub相关依赖 解决办法 * 使用npm添加依赖:npm install --save pubsub-js(失败的话使用此命令:cnpm install --save pubsub-js) * 在src下的main.js中引用: import PubSub from 'pubsub-js' Vue.prototype.PubSub = PubSub![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/af8c6d863ec5448dbd4e564ccc6dd9dd.png) * 在.eslintrc.js中添加一下配置 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/0e7110b3ace442beb044dd53ce811d9e.png) #### 1.1.2 品牌关联 拷贝对应的前端页面文件 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/5e4dda5ba51943e3b1e8fa969511af85.png) 添加后端对应的服务 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/b1e7a45389ef4957a99e79433a45847c.png) 然后service中查询处理 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/d758f664510c4149b5f801a7b4a2d330.png) 最后的显示效果 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/5b390464bebb46ba89a51033cd58dbd8.png) #### 1.1.3 会员等级   首先我们需要启动会员模块,并且配置对应的网关路由信息 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/5fdec2527ef1499ca8215f99d6121cb5.png) ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/7f823adb394b48199bdd6254dedfa765.png) #### 1.1.4 规格参数   在新增商品的第二步我们就需要设置对应的规格参数,而这些规格参数是根据前面一步选择的三级分类来查询出来的。 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/7d77b5be10e54253bacdbe8d009ae7a9.png)   响应对应的数据,我们需要先创建对应的VO对象。 ```java package com.msb.mall.product.vo; import com.baomidou.mybatisplus.annotation.TableId; import com.msb.mall.product.entity.AttrEntity; import lombok.Data; import java.util.List; @Data public class AttrGroupWithAttrsVo { /** * 分组id */ @TableId private Long attrGroupId; /** * 组名 */ private String attrGroupName; /** * 排序 */ private Integer sort; /** * 描述 */ private String descript; /** * 组图标 */ private String icon; /** * 所属分类id */ private Long catelogId; // 关联对应的属性信息 private List attrs; } ```   然后创建对应的controller ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/a7078b97cb0544c5ba05408de08c6a3e.png)   然后创建对应的service ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/912bae3485214766b660912fdaa357b6.png) ### 1.2 发布商品 #### 1.2.1 VO 接收数据   前端页面提交的JSON数据非常复杂,我们需要在后端服务通过对应的VO对象来接收这些相关的数据。 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/1b4838b74d2d49a0af05e47fa0275b00.png) 然后通过在线的json格式处理工具生成对应的VO工具类 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/7712c743b6de438db49f84571b20272f.png) #### 1.2.2 保存对应的数据   需要保存的数据拆解为一下六个部分。 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/25915127d4964ad587fc50dab643a71f.png) #### 1.2.3 保存商品基本信息 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/1490f95f6356461f9a151b0387b66b79.png) #### 1.2.4 保存商品描述 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/0c0c13e1dc694bb7b668c85e8687b2f3.png) 需要注意的地方: ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/6d55a77633d942608a8c459c717f27ab.png) #### 1.2.4 保存图集信息 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/84b916fc4fd34b1aa5e3cb4f96836cc8.png) #### 1.2.5 保存规格参数 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/fd340ae1bcb44af59bc88b35e2dc03b5.png) #### 1.2.6 SKU基本信息存储 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/d1ad9f46ad974fcfb160e5e8b30f359b.png) #### 1.2.7 SKU的图集 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/ba052a777a8541c28c0e98ea4e650b82.png) #### 1.2.8 SKU的销售属性 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/fa003c96fe4c4632ba5ca6b95c3b3426.png) ### 1.3 远程服务调用 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/656b476ec82841438e38a72ee644711e.png) ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/84ddf4367c2d4abe92ee60aa92a3a862.png) ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/ce1a0bc63e914fe3a1600af93b03ccf5.png) ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/0acf26569cb84342bdf5cb7d7a7e75b9.png) #### 1.3.1 满减,折扣,会员价保存 在coupon服务中定义相关的接口及处理的service ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/322260877ab446ceaaa2b742881ee0c5.png) ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/47a6923ff4464172aaadb54d17b51698.png) 然后我们在Product服务中来处理接口的调用 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/e062594520f94b3db2855d5818b75450.png) 然后在商品的service中完成服务的调用 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/0bed55cbbbbf4f8fb07d9406d63aed00.png) 完成满减折扣和会员价的service存储 ```java public void saveSkuReduction(SkuReductionDTO dto) { // 5.3 保存满减信息,折扣,会员价 // mall_sms: sms_sku_ladder sms_full_reduction sms_member_price // 1.折扣 SkuLadderEntity ladderEntity = new SkuLadderEntity(); ladderEntity.setSkuId(dto.getSkuId()); ladderEntity.setFullCount(dto.getFullCount()); ladderEntity.setDiscount(dto.getDiscount()); ladderEntity.setAddOther(dto.getCountStatus()); if(ladderEntity.getFullCount() > 0){ ladderService.save(ladderEntity); } // 2.满减 SkuFullReductionEntity fullReductionEntity = new SkuFullReductionEntity(); BeanUtils.copyProperties(dto,fullReductionEntity); if(fullReductionEntity.getFullPrice().compareTo(new BigDecimal(0)) == 1){ this.save(fullReductionEntity); } // 3.会员价 List memberPriceEntities = dto.getMemberPrice().stream().map(item -> { MemberPriceEntity priceEntity = new MemberPriceEntity(); priceEntity.setSkuId(dto.getSkuId()); priceEntity.setMemberLevelId(item.getId()); priceEntity.setMemberPrice(item.getPrice()); priceEntity.setAddOther(1); // 是否可叠加 return priceEntity; }).collect(Collectors.toList()); memberPriceService.saveBatch(memberPriceEntities); } ``` #### 1.3.2 会员积分存储 会员积分信息也是存储在Coupon服务中,我们同样需要通过Fegin来调用。 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/530b79035bb74453a9cec99f279f3152.png) ## 2.SPU管理   提供不同条件的检索,分类,品牌,状态,关键字检索。 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/ab5431c1b87a42f5a101c95692d1f37e.png)   后台我们需要在Service中完成对应的操作。 ```java /** * SPU信息检索 * 分页查询 * 分类 品牌 状态 关键字查询 * @param params * @return */ @Override public PageUtils queryPageByCondition(Map params) { QueryWrapper wrapper = new QueryWrapper<>(); // 设置对应的检索条件 // 1. 关键字查询 String key = (String) params.get("key"); if(!StringUtils.isEmpty(key)){ // 需要添加关键字查询 wrapper.and((w)->{ w.eq("id",key) .or().like("spu_name",key) .or().like("spu_description",key); }); } // status String status = (String) params.get("status"); if(!StringUtils.isEmpty(status)){ wrapper.eq("publish_status",status); } // catalogId String catalogId = (String) params.get("catalogId"); if(!StringUtils.isEmpty(catalogId) && !"0".equalsIgnoreCase(catalogId)){ wrapper.eq("catalog_id",catalogId); } // brandId String brandId = (String) params.get("brandId"); if(!StringUtils.isEmpty(brandId) && !"0".equalsIgnoreCase(brandId)){ wrapper.eq("brand_id",brandId); } IPage page = this.page( new Query().getPage(params), wrapper ); return new PageUtils(page); } ```   然后解决页面显示数据的问题,比如类别和品牌显示的编号,创建时间和更新时间显示格式问题。 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/a949bc1846e94773bb167cfb165f81da.png) 重启服务 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/f2380f63f30741039528bbcd6b6f56db.png) 上面的是设置全局的格式化方式,如果我也特殊设置,这时我们可以在对应的entity对象的属性上通过@JsonFormat 来指定,此处指定的会覆盖掉全局的设置。 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/50a4c0fa699941f2bed16c0485464a92.png) ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/b41d0c1e59f04fdda0a0a62780e93c10.png) 针对显示的分类和品牌显示id的问题,我们需要通过对应的vo对象来传输,同时我们需要在service中完成对应的逻辑 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/8f2a4b71785d41dc945b1d90532ad9b6.png) 显示的效果 ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/5d798daf16ab4ae5b951be8abf4e9962.png) ## 3.商品管理   商品管理也就是我们讲的SKU管理。实现多条件的检索,比如 类别,品牌,价格区间。关键字等查询。 ```java /** * SKU 信息检索的方法 * 类别 * 品牌 * 价格区间 * 检索的关键字 * 分页查询 * * @param params * @return */ @Override public PageUtils queryPageByCondition(Map params) { QueryWrapper wrapper = new QueryWrapper<>(); // 检索关键字 String key = (String) params.get("key"); if(!StringUtils.isEmpty(key)){ wrapper.and(w->{ w.eq("sku_id",key).or().like("sku_name",key); }); } // 分类 String catalogId = (String)params.get("catalogId"); if(!StringUtils.isEmpty(catalogId) && !"0".equalsIgnoreCase(catalogId)){ wrapper.eq("catalog_id",catalogId); } // 品牌 String brandId = (String)params.get("brandId"); if(!StringUtils.isEmpty(brandId) && !"0".equalsIgnoreCase(brandId)){ wrapper.eq("brand_id",brandId); } // 价格区间 String min = (String) params.get("min"); if(!StringUtils.isEmpty(min)){ wrapper.ge("price",min); } String max = (String) params.get("max"); if(!StringUtils.isEmpty(max)){ try { // 如果max=0那么我们也不需要加这个条件 BigDecimal bigDecimal = new BigDecimal(max); if(bigDecimal.compareTo(new BigDecimal(0)) == 1){ // 说明 max > 0 wrapper.le("price",max); } }catch (Exception e){ e.printStackTrace(); } } IPage page = this.page( new Query().getPage(params), wrapper ); return new PageUtils(page); } ``` ![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1641455939000/36ef14929a21484bb5937bc6fbcb88c7.png)