【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【16】商品详情_商品上架_商品检索

【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【16】商品详情_商品上架_商品检索 持续学习持续更新中…守破离【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【16】商品详情_商品上架_商品检索Feign调用流程(重试机制)商品上架分析商品上架在 es 中是存 sku 还是 spu上架细节数据一致性代码实现商品检索商品详情参考Feign调用流程(重试机制)Feign调用流程可以DEBUG查看 1、构造请求数据将对象转为json RequestTemplate template buildTemplateFromArgs.create(argv); 2、发送请求进行执行执行成功会解码响应数据 executeAndDecode(template); 3、执行请求会有重试机制 while(true){ try{ executeAndDecode(template); }catch(){ try{retryer.continueOrPropagate(e);}catch(){throw ex;} continue; } }商品上架将MySQL中的商品数据从数据库中保存到ES的整个过程我们成为“商品上架”上架的商品才可以在网站展示。上架的商品需要可以被检索。ES所有东西保存在内存中而内存是一种珍贵资源所以我们应该只给ES保存有用的数据分析商品上架在 es 中是存 sku 还是 spu需要保存到ES的数据有很多比如sku/spu/规格参数/三级分类/品牌…分析 /** * 1、方便检索 * { * skuId:1 * spuId:11 * skuTitle:华为xx * price:998 * saleCount:99 * attrs:[ * {尺寸5寸}, * {CPU高通945}, * {分辨率全高清} * ] * } * 冗余同一个spu的规格参数是一样的直接存sku会有冗余信息不过问题不大 * 100万*201000000*2KB2000MB2G 20 * * 2、 * sku索引{ * skuId:1 * spuId:11 * xxxxx * } * * attr索引{ * spuId:11, * attrs:[ * {尺寸5寸}, * {CPU高通945}, * {分辨率全高清} * ] * } * * 虽然没有冗余数据但是 * * 搜索 小米 * 粮食类/手机类/电器类都有小米 * 10000个带小米两字的商品涉及到了4000个spu * * 此时我们会分步找4000个spu对应的所有可能属性 * * esClient不说别的光spuId:[4000个spuidid都是long数据] 4000*832000byte32kb 【一个请求32kb数据】 * * 32kb*10000个人32000mb;32GB */ /** * 空间与时间不可兼得 */最终决定这样存储PUTproduct{mappings:{properties:{skuId:{type:long},spuId:{type:keyword},skuTitle:{type:text,analyzer:ik_smart},skuPrice:{type:keyword},skuImg:{type:keyword,index:false,doc_values:false},saleCount:{type:long},hasStock:{type:boolean},hotScore:{type:long},brandId:{type:long},catalogId:{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}}}}}}对应的JavaBeanDatapublicclassSkuEsModel{privateLongskuId;privateLongspuId;privateStringskuTitle;privateBigDecimalskuPrice;privateStringskuImg;privateLongsaleCount;privateBooleanhasStock;privateLonghotScore;privateLongbrandId;privateLongcatalogId;privateStringbrandName;privateStringbrandImg;privateStringcatalogName;privateListAttrsattrs;DatapublicstaticclassAttrs{privateLongattrId;privateStringattrName;privateStringattrValue;}}上架细节数据一致性商品无库存的时候需要更新 es 的库存信息商品有库存也要更新 es 的信息实时更新库存是一件很消耗资源的事代码实现/**商品上架 POST * /product/spuinfo/{spuId}/up */PostMapping(/{spuId}/up)publicRspuUp(PathVariable(spuId)LongspuId){spuInfoService.up(spuId);returnR.ok();}Overridepublicvoidup(LongspuId){//1、查出当前spuid对应的所有sku信息ListSkuInfoEntityskusskuInfoService.listSkusBySpuId(spuId);ListLongskuIdListskus.stream().map(SkuInfoEntity::getSkuId).collect(Collectors.toList());// 查询当前sku的所有可以被用来检索的规格属性ListProductAttrValueEntitybaseAttrsproductAttrValueService.listSpuSpec(spuId);ListLongattrIdsbaseAttrs.stream().map(ProductAttrValueEntity::getAttrId).collect(Collectors.toList());ListLongsearchAttrIdsattrService.selectSearchAttrIds(attrIds);SetLongidSetnewHashSet(searchAttrIds);ListSkuEsModel.AttrsattrsListbaseAttrs.stream().filter(item-idSet.contains(item.getAttrId())).map(item-{SkuEsModel.Attrsattrs1newSkuEsModel.Attrs();BeanUtils.copyProperties(item,attrs1);returnattrs1;}).collect(Collectors.toList());//发送远程调用库存系统查询是否有库存MapLong,BooleanstockMapnull;try{RrwareFeignService.getSkusHasStock(skuIdList);TypeReferenceListSkuHasStockTotypeReferencenewTypeReferenceListSkuHasStockTo(){};stockMapr.getData(typeReference).stream().collect(Collectors.toMap(SkuHasStockTo::getSkuId,item-item.getHasStock()));}catch(Exceptione){log.error(库存服务查询异常:原因{},e);}//2、封装每个sku的信息MapLong,BooleanfinalStockMapstockMap;ListSkuEsModelupProductsskus.stream().map(sku-{//组装需要的数据SkuEsModelesModelnewSkuEsModel();BeanUtils.copyProperties(sku,esModel);//skuPrice,skuImg,esModel.setSkuPrice(sku.getPrice());esModel.setSkuImg(sku.getSkuDefaultImg());//hasStock,hotScore//设置库存信息if(finalStockMapnull){// 出异常默认有库存esModel.setHasStock(true);}else{esModel.setHasStock(finalStockMap.get(sku.getSkuId()));}//TODO 热度评分。默认0esModel.setHotScore(0L);//查询品牌和分类的名字信息BrandEntitybrandbrandService.getById(esModel.getBrandId());esModel.setBrandName(brand.getName());esModel.setBrandImg(brand.getLogo());CategoryEntitycategorycategoryService.getById(esModel.getCatalogId());esModel.setCatalogName(category.getName());//设置检索属性esModel.setAttrs(attrsList);returnesModel;}).collect(Collectors.toList());// 将数据发送给es进行保存gulimall-searchRrsearchFeignService.productStatusUp(upProducts);if(r.getCode()0){//远程调用成功// 修改当前spu的状态baseMapper.updateSpuStatus(spuId,ProductConstant.StatusEnum.SPU_UP.getCode());}else{//远程调用失败//TODO 重复调用(接口幂等性)重试机制/** Feign调用流程可以DEBUG查看 1、构造请求数据将对象转为json RequestTemplate template buildTemplateFromArgs.create(argv); 2、发送请求进行执行执行成功会解码响应数据 executeAndDecode(template); 3、执行请求会有重试机制 while(true){ try{ executeAndDecode(template); }catch(){ try{retryer.continueOrPropagate(e);}catch(){throw ex;} continue; } } */}}OverridepublicbooleanproductStatusUp(ListSkuEsModelskuEsModels)throwsIOException{//保存到es//1、给es中建立索引。product建立好映射关系。//2、给es中保存这些数据//BulkRequest bulkRequest, RequestOptions optionsBulkRequestbulkRequestnewBulkRequest();for(SkuEsModelmodel:skuEsModels){//1、构造保存请求IndexRequestindexRequestnewIndexRequest(EsConstant.PRODUCT_INDEX);indexRequest.id(model.getSkuId().toString());StringsJSON.toJSONString(model);indexRequest.source(s,XContentType.JSON);bulkRequest.add(indexRequest);}BulkResponsebulkrestHighLevelClient.bulk(bulkRequest,ElasticSearchConfig.COMMON_OPTIONS);//TODO 1、如果批量错误booleanbbulk.hasFailures();ListStringcollectArrays.stream(bulk.getItems()).map(item-{returnitem.getId();}).collect(Collectors.toList());log.info(商品上架完成{}返回数据{},collect,bulk.toString());returnb;}商品检索Windows host文件192.168.56.10 gulimall.com 192.168.56.10 search.gulimall.comNginx配置网关spring:cloud:gateway:routes:-id:gulimall_product_routeuri:lb://gulimall-productpredicates:-Hostgulimall.com-id:gulimall_search_routeuri:lb://gulimall-searchpredicates:-Hostsearch.gulimall.comNginx转发效果ControllerpublicclassSearchController{GetMapping({/,/list.html})publicStringsearchIndexPage(){returnlist;}}商品检索三个入口商品详情Windows host文件# gulimall192.168.56.10gulimall.com192.168.56.10search.gulimall.com192.168.56.10item.gulimall.comNginx不用变/mydata/nginx/conf/conf.d/gulimall.confserver { listen 80; server_name gulimall.com *.gulimall.com; location /static/ { root /usr/share/nginx/html; } location / { proxy_pass http://gulimall; proxy_set_header Host $host; } }网关-id:gulimall_product_routeuri:lb://gulimall-productpredicates:-Hostgulimall.com,item.gulimall.com-id:gulimall_search_routeuri:lb://gulimall-searchpredicates:-Hostsearch.gulimall.comNginx动静分离ControllerpublicclassItemController{AutowiredprivateSkuInfoServiceskuInfoService;// 测试GetMapping(/shangpinxiangqing.html)publicStringitemPage(){returnshangpinxiangqing;}/** * 展示当前sku的详情 * param skuId * return */GetMapping(/{skuId}.html)publicStringskuItem(PathVariable(skuId)LongskuId,Modelmodel)throwsExecutionException,InterruptedException{System.out.println(准备查询skuId详情);SkuItemVovoskuInfoService.item(skuId);model.addAttribute(item,vo);returnitem;}}自定义线程池!-- 自定义配置有提示信息 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-configuration-processor/artifactIdoptionaltrue/optional/dependencythread:core-pool-size:20maximum-pool-size:200keep-alive-time:10queue-capacity:10000ConfigurationProperties(thread)ComponentDatapublicclassThreadPoolConfigProperties{privateintcorePoolSize;privateintmaximumPoolSize;privatelongkeepAliveTime;privateintqueueCapacity;}ConfigurationpublicclassMyThreadConfig{BeanpublicThreadPoolExecutorthreadPoolExecutor(ThreadPoolConfigPropertiespool){returnnewThreadPoolExecutor(pool.getCorePoolSize(),pool.getMaximumPoolSize(),pool.getKeepAliveTime(),TimeUnit.SECONDS,newLinkedBlockingDeque(pool.getQueueCapacity()),Executors.defaultThreadFactory(),newThreadPoolExecutor.AbortPolicy());}}AutowiredThreadPoolExecutorexecutor;OverridepublicSkuItemVoitem(LongskuId){SkuItemVoskuItemVonewSkuItemVo();CompletableFutureSkuInfoEntityinfoFutureCompletableFuture.supplyAsync(()-{//1、sku基本信息获取 pms_sku_infoSkuInfoEntityinfogetById(skuId);skuItemVo.setInfo(info);returninfo;},executor);CompletableFutureVoidsaleAttrFutureinfoFuture.thenAcceptAsync((res)-{//3、获取spu的销售属性组合。ListSkuItemSaleAttrVosaleAttrVosskuSaleAttrValueService.getSaleAttrsBySpuId(res.getSpuId());skuItemVo.setSaleAttr(saleAttrVos);},executor);CompletableFutureVoiddescFutureinfoFuture.thenAcceptAsync(res-{//4、获取spu的介绍 pms_spu_info_descSpuInfoDescEntityspuInfoDescEntityspuInfoDescService.getById(res.getSpuId());skuItemVo.setDesp(spuInfoDescEntity);},executor);CompletableFutureVoidbaseAttrFutureinfoFuture.thenAcceptAsync(res-{//5、获取spu的规格参数信息。ListSpuItemAttrGroupVoattrGroupVosattrGroupService.getAttrGroupWithAttrsBySpuId(res.getSpuId(),res.getCatalogId());skuItemVo.setGroupAttrs(attrGroupVos);},executor);//2、sku的图片信息 pms_sku_imagesCompletableFutureVoidimageFutureCompletableFuture.runAsync(()-{ListSkuImagesEntityimagesimagesService.getImagesBySkuId(skuId);skuItemVo.setImages(images);},executor);// //等到所有任务都完成CompletableFuture.allOf(saleAttrFuture,descFuture,baseAttrFuture,imageFuture).get();returnskuItemVo;}参考雷丰阳: Java项目《谷粒商城》Java架构师 | 微服务 | 大型电商项目.本文完感谢您的关注支持