谷粒商城高级篇商品服务 & 商品上架

Posted 愿你满腹经纶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了谷粒商城高级篇商品服务 & 商品上架相关的知识,希望对你有一定的参考价值。

谷粒商城笔记合集

分布式基础篇分布式高级篇高可用集群篇
===简介&环境搭建======Elasticsearch===
项目简介与分布式概念(第一、二章)Elasticsearch:全文检索(第一章)
基础环境搭建(第三章)===商品服务开发===
===整合SpringCloud===商品服务 & 商品上架(第二章)
整合SpringCloud、SpringCloud alibaba(第四、五章)===商城首页开发===
===前端知识===商城业务:首页整合、Nginx 域名访问、性能优化与压力测试 (第三、四、五章)
前端开发基础知识(第六章)缓存与分布式锁(第六章)
===商品服务开发======商城检索开发===
商品服务开发:基础概念、三级分类(第七、八章)商城业务:商品检索(第七章)
商品服务开发:品牌管理(第九章)
商品服务开发:属性分组、平台属性(第十、十一章)
商品服务:商品维护(第十二、十三章)
===仓储服务开发===
仓储服务:仓库维护(第十四章)
基础篇总结(第十五章)

二、商品服务 & 商品上架

2.1 存储模型分析

  • 上架的商品才可以在网站展示

  • 上架的商品需要可以检索

Elasticsearch:用于检索数据

logstach:存储数据

Kiban:视图化查看数据

2.2 商品Mapping

分析:商品上架在 es 中是存入 sku 还是 spu ?

  1. 检索的时候输入名字,是需要按照 sku 的 title进行全文检索的
  2. 检索使用商品规格,规格是 spu 的公共属性,每个 spu 是一样的
  3. 按照分类 id 进去的 都是直接列出 spu的,还可以切换
  4. 我们如果将 sku 的 全量信息 保存在 es 中 (包括 spu 属性),就太多量字段了
  5. 如果我们将 spu 以及他包含的 sku 信息保存到 es 中,也可以方
PUT product

  "mappings":
    "properties":
      "skuId":
        "type":"long"
      ,
       "spuId":
        "type":"keyword"
      ,
       "skuTitle":
        "type":"text",
        "analyzer": "ik_smart"
      ,
       "skuPrice":
        "type":"keyword"
      ,
       "skuImg":
        "type":"text",
        "analyzer": "ik_smart"
      ,
       "saleCount":
        "type":"long"
      ,
       "hasStock":
        "type":"boolean"
      ,
      "hotScore":
        "type":"long"
      ,
      "brandId":
        "type":"long"
      ,
      "catelogId":
        "type":"long"
      ,
      "brandName":
        "type":"keyword",
        "index": false,
        "doc_values": false
      ,
      "brandImg":
        "type":"keyword",
         "index": false,
        "doc_values": false
      ,
      "catalogName":
        "type":"keyword",
         "index": false,
         "doc_values": false
      ,
      "attrs":
        "type":"nested",
        "properties": 
          "attrId":
            "type":"long"
          ,
          "attrName":
            "type":"keyword",
            "index":false,
            "doc_values":false
          ,
          "attrValue": 
            "type":"keyword"
          
        
      
    
  

2.3 API:商品上架⚠️💡

2.3.1 业务流程

上架前

上架后

业务流程

前端点击上架后,发送请求并带上参数 spuid

  • 根据 spuid 查询 pms_sku_info 表得到商品相关属性

  • 根据 spuid 查询 pms_product_attr_value 表得到可以用来检索的规格属性

  • ProductAttrValueEntity 中拿到所有的 attrId,根据 attrId 查询 pms_attr 查询检索的属性

  • x根据 pms_attr 查询到检索属性后,用检索属性和 原先根据 spuid 查询 pms_sku_info 表得到商品相关属性进行比较,pms_sku_info 包含 从 pms_attr 字段attr_id 则数据保存否则过滤

  • 根据 skuIds 去查询远程仓库中是否有库存 SELECT SUM(stock-stock_locked) FROM wms_ware_sku WHERE sku_id = 1

  • 组装数据 设置 SkuEsModel

  • 发送给 es 保存

2.3.1 公共服务⚠️

  1. 创建用于传输sku库存信息的TO,用于商品上架过程中远程获取库存信息:cn/lzwei/common/to/SkuHasStockTo.java

    @Data
    public class SkuHasStockTo 
        private Long skuId;
        private Boolean hasStock;
    
    
  2. 修改公共返回类R,用于商品上架过程中远程获取库存信息:cn/lzwei/common/utils/R.java

    public class R<T> extends HashMap<String, Object> 
        
    	public <T> T  getData(TypeReference<T> typeReference) 
    		Object data = get("data");
    		String jsonString = JSON.toJSONString(data);
    		T t = JSON.parseObject(jsonString, typeReference);
    		return t;
    	
    	public R setData(Object data) 
    		put("data",data);
    		return this;
    	
    
    
  3. 创建用于传输sku上架信息的TO,用于商品上架过程中远程保存sku信息到elasticsearch:cn/lzwei/common/to/search/SpuUpTo.java

    @Data
    public class SpuUpTo 
        private Long skuId;
        private Long spuId;
        private String skuTitle;
        private BigDecimal skuPrice;
        private String skuImg;
        private Long saleCount;
        private Boolean hasStock;
        private Long hotScore;
        private Long brandId;
        private Long catalogId;
        private String brandName;
        private String brandImg;
        private String catalogName;
        private List<Attr> attrs;
        @Data
        public static class Attr
            private Long attrId;
            private String attrName;
            private String attrValue;
        
    
    
  4. 新增商品上架过程中批量请求elasticsearch失败、商品上架异常的状态枚举对象:cn/lzwei/common/exception/BizCodeEnume.java

    public enum BizCodeEnume 
        PRODUCT_UP_EXCEPTION(11000,"商品上架异常");
    
    
  5. 新增商品状态的枚举常量类,用于商品上架成功后的状态更新:cn.lzwei.common.constant.ProductConstant.StatusEnum

    public class ProductConstant 
        public enum StatusEnum
            NEW_SPU(0,"新建"),SPU_UP(1,"商品上架"),SPU_DOWN(2,"商品下架");
            private Integer code;
            private String msg;
            StatusEnum(Integer code,String msg)
                this.code=code;
                this.msg=msg;
            
    
            public Integer getCode() 
                return code;
            
    
            public String getMsg() 
                return msg;
            
        
    
    

2.3.2 仓储服务⚠️

  1. 创建封装sku库存状态的VO,封装商品上架远程调用通过skuId列表获取sku对应的库存状态:cn/lzwei/bilimall/ware/vo/SkuHasStockVo.java

    @Data
    public class SkuHasStockVo 
        private Long skuId;
        private Boolean hasStock;
    
    
  2. WareSkuController:商品上架远程调用:通过skuId列表获取sku对应的库存信息

    @RestController
    @RequestMapping("ware/waresku")
    public class WareSkuController 
        @Autowired
        private WareSkuService wareSkuService;
    
        /**
         * 商品上架远程调用:通过skuId列表获取sku对应的库存信息
         */
        @PostMapping("/getSkusWareInfoBySkuIds")
        public R getSkusWareInfoBySkuIds(@RequestBody List<Long> skuIds)
            List<SkuHasStockVo> wareSkuEntities=wareSkuService.getSkusWareInfoBySkuIds(skuIds);
            return R.ok().setData(wareSkuEntities);
        
    
    
  3. WareSkuService:商品上架远程调用:通过skuId列表获取sku对应的库存信息

    public interface WareSkuService extends IService<WareSkuEntity> 
        /**
         * 商品上架远程调用:通过skuId列表获取sku对应的库存信息
         */
        List<SkuHasStockVo> getSkusWareInfoBySkuIds(List<Long> skuIds);
    
    
  4. WareSkuServiceImpl:商品上架远程调用:通过skuId列表获取sku对应的库存信息

    @Service("wareSkuService")
    public class WareSkuServiceImpl extends ServiceImpl<WareSkuDao, WareSkuEntity> implements WareSkuService 
        /**
         * 商品上架远程调用:通过skuId列表获取sku对应的库存信息
         */
        @Override
        public List<SkuHasStockVo> getSkusWareInfoBySkuIds(List<Long> skuIds) 
            List<SkuHasStockVo> collect = skuIds.stream().map(skuId -> 
                SkuHasStockVo skuHasStockVo = new SkuHasStockVo();
                //1.设置skuId
                skuHasStockVo.setSkuId(skuId);
                //2.通过skuId获取剩余库存:库存量-锁定库存量
                Long count = baseMapper.getStock(skuId);
                skuHasStockVo.setHasStock(count==null?false:count > 0);
                return skuHasStockVo;
            ).collect(Collectors.toList());
            return collect;
        
    
    
  5. WareSkuDao.java:获取sku剩余库存:库存量-锁定库存量

    @Mapper
    public interface WareSkuDao extends BaseMapper<WareSkuEntity> 
        //通过skuId获取剩余库存:库存量-锁定库存量
        Long getStock(Long skuId);
    
    
  6. WareSkuDao.xml:获取sku剩余库存:库存量-锁定库存量

    <mapper namespace="cn.lzwei.bilimall.ware.dao.WareSkuDao">
        <!--通过skuId获取剩余库存:库存量-锁定库存量-->
        <select id="getStock" resultType="java.lang.Long">
            SELECT SUM(stock-stock_locked) FROM `wms_ware_sku` WHERE sku_id=#skuId
        </select>
    </mapper>
    

2.3.3 检索服务⚠️

  1. 创建常量类,保存商品索引常量:cn/lzwei/bilimall/search/constant/EsConstant.java

    public class EsConstant 
        //商品索引
        public static final String PRODUCT_INDEX="product";
    
    
  2. ProductSaveController

    @RequestMapping("/search/save")
    @RestController
    @Slf4j
    public class ProductSaveController 
        @Resource
        ProductSaveService productSaveService;
    
        /**
         * 保存商品信息
         */
        @PostMapping("/product")
        public R productStatusUp(@RequestBody List<SpuUpTo> spuUpTo)
            boolean b=false;
            try 
                b = productSaveService.productStatusUp(spuUpTo);
             catch (IOException e) 
                log.error("ProductSaveController商品上架错误:",e);
                return R.error(BizCodeEnume.PRODUCT_UP_EXCEPTION.getCode(),BizCodeEnume.PRODUCT_UP_EXCEPTION.getMessage());
            
            if (!b)
                return R.ok();
            else 
                return R.error(BizCodeEnume.PRODUCT_UP_EXCEPTION.getCode(),BizCodeEnume.PRODUCT_UP_EXCEPTION.getMessage());
            
        
    
    
  3. ProductSaveService

    public interface ProductSaveService 
        /**
         * 保存商品信息
         */
        boolean productStatusUp(List<SpuUpTo> spuUpTo) throws IOException;
    
    
  4. ProductSaveServiceImpl

    @Service("productSaveService")
    @Slf4j
    public class ProductSaveServiceImpl implements ProductSaveService 
        @Resource
        RestHighLevelClient restHighLevelClient;
    
        /**
         * 保存商品信息
         */
        @Override
        public boolean productStatusUp(List<SpuUpTo> spuUpTo) throws IOException 
            //1.构造批量请求
            BulkRequest bulkRequest = new BulkRequest();
            for (SpuUpTo upTo : spuUpTo) 
                //1.1、构造请求 指定es索引
                IndexRequest indexRequest = new IndexRequest(EsConstant.PRODUCT_INDEX);
                //1.2、设置id
                indexRequest.id(String.valueOf(upTo.getSkuId()));
                //1.3、设置数据
                String s = JSON.toJSONString(upTo);
                indexRequest.source(s, XContentType.JSON);
                //1.4、添加请求
                bulkRequest.add(indexRequest);
            
            //2.执行批量请求
            BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, BilimallElasticsearchConfig.COMMON_OPTIONS);
            boolean b = bulk.hasFailures();
            //获取上架的skuId
            List<String> collect = Arrays.stream(bulk.getItems()).map(item -> 
                return item.getId();
            ).collect(Collectors.toList());
            //3.如果批量错误
            //TODO 商品上架错误
            if (b)
                log.error("商品上架错误:",collect);
            else 
                log.info("商品上架成功的打印:",collect);
            
            return b;
        
    
    

2.3.4 商品服务💡

  1. SpuInfoController:将所属的sku信息保存到elasticsearch中

    @RestController
    @RequestMapping("product/spuinfo")
    public class SpuInfoController 
        @Autowired
        private SpuInfoService spuInfoService;
    
        /**
         * 商品上架:将所属的sku信息保存到elasticsearch中
         */
        @PostMapping("/spuId/up")
        public R up(@PathVariable(value = "spuId") Long spuId)
            R r=spuInfoService.up(spuId);
            return r;
        
    
    
  2. SpuInfoService:将所属的sku信息保存到elasticsearch中

    public interface SpuInfoService extends IService<SpuInfoEntity> 
        /**
         * 商品上架:将所属的sku信息保存到elasticsearch中
         */
        R up(Long spuId);
    
    
  3. SpuInfoServiceImpl:将所属的sku信息保存到elasticsearch中

    @Service("spuInfoService")
    public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService 
        @Resource
        ProductAttrValueService productAttrValueService;
        @Resource
        AttrService attrService;
        @Resource
        SkuInfoService skuInfoService;
        @Resource
        BrandService brandService;
        @Resource
        CategoryService categoryService;
        @Resource
        WareFeignService wareFeignService;
        @Resource
        SearchFeignService searchFeignService;
    
        /**
         * 商品上架:将所属的sku信息保存到elasticsearch中
         */
        @Transactional
        @Override
        public R up(Long spuId) 
            //1.准备spu的品牌信息、分类信息:通过spuId获取品牌信息、分类信息
            SpuInfoEntity spuInfo = this.getById(spuId);
            Long brandId = spuInfo.getBrandId();
            Long catalogId = spuInfo.getCatalogId();
            BrandEntity brandInfo = brandService.getById(brandId);
            CategoryEntity categoryInfo = categoryService.getById(catalogId);
            //2.准备spu的所有可检索的规格参数
            //获取商品的所有规格参数
            List<ProductAttrValueEntity> productAttrValueEntities = productAttrValueService.list(new QueryWrapper<ProductAttrValueEntity>().eq("spu_id", spuId));
            List<Long> productAttrIds = productAttrValueEntities.stream().map(item -> item.getAttrId()).collect(Collectors.toList());
            //获取可用于检索的规格参数
            List<Long> searchAttrIds = attrService.getSearchAttr(productAttrIds);
            HashSet<Long> searchAttrIdsSet=new HashSet<>(searchAttrIds);
            //过滤出商品的所有可用于检索的规格参数
            List<SpuUpTo.Attr> searchAttrs = productAttrValueEntities.stream().filter(item -> 
                return searchAttrIdsSet.contains(item.getAttrId());
            ).map(item -> 
                SpuUpTo.Attr attr = new SpuUpTo.Attr();
                BeanUtils.copyProperties(item, attr);
                return attr;
            ).collect(Collectors.toList());
            //3.查出所有的sku
            List<SkuInfoEntity> skuInfoEntities = skuInfoService.list(new QueryWrapper<SkuInfoEntity>().eq("spu_id", spuId));
            //4.准备所有sku的库存信息:传递skuId列表获取对应的库存信息,使用map封装。(远程调用库存服务)
            List以上是关于谷粒商城高级篇商品服务 & 商品上架的主要内容,如果未能解决你的问题,请参考以下文章

    Day409.商品上架 -谷粒商城

    谷粒商城笔记+踩坑——上架商品spu到ES索引库

    谷粒商城--整合Elasticsearch和商品的上架

    谷粒商城商品服务API

    谷粒商城商品服务API

    Day400&401&402.商品服务 -谷粒商城