谷粒商城-商品上架

1.sku在es中的存储模型分析(spring整和es)

es中所有数据存在内存中,内存产品贵,能节省就节省,只保存有用的信息

两种保存方法:(空间换时间,时间换空间):

我们选空间换时间

ES中放这些东西:

 "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"
          }
        }
      }
    }
  }
}

 //nested嵌入式的数据类型,

因为数组类型不标记nested的数据处理时会被扁平化处理(如下图),所以检索时就会出现问题,当我们查询first包含Alice且last包含Smith时是会查到结果的,因为被扁平化处理,first数组里查到了Alice,而且last数组里也查到了smith,所以当数组中的每个单元是对象的时候我们就可以用nested的数据类型,这样就不会出现扁平化处理这个错误 

2.构造基本数据(商品上架功能编写)

根据接口文档,来到product的spuinfo下:

因为es里存的是我们挑出来的有用的信息而且需要product服务和search服务通信,正常开发权限问题有可能需要在product和search里都建立一个esModel的TO类,但是我们为了方便开发,可以直接在common里建这个TO:

然后来到实现类里来写方法体:(业务逻辑,我们不仅要查是否有库存,也要把可检索的规格属性一起存进es里,方便检索)

1.查出当前spuid对应的所有sku信息,再通过sku信息拿到所有的skuId组成数组,我们用这个数组去查这些sku是否都有库存(发送远程调用gulimall-ware服务),查出来的结果,用了一个map来装(Long,Boolean)这里用到了fastjson进行逆转(把R里的数据转成我们想要的对象),然后把是否有库存和skuid设置进 esModel 这个TO类里.

2.通过brandService和esModel的brandId查出品牌相关的name和img,通过catalogService和esModel的catalogId查出三级分类相关的name,放进 esModel

3.通过spuid查出所有sku的规格属性,把规格属性的id组成一个数组,遍历数组找到可检索的规格属性,通过过滤和映射把所有可检索的规格属性放进SkuEsModel类的内部类Attrs里,组成attrList的List,然后设置进esModel里

4.通过上述流程esModel里数据就充足了,我们通过远程调用gulimall-search服务,来将数据发给es保存

5.保存成功,修改当前spu的状态为 已上架

以下是部分代码:

SpuInfoServiceImpl:主方法体:
    @Overridepublic void up(Long spuId) {//1.1查出当前spuid对应的所有sku信息,品牌的名字List<SkuInfoEntity> skus=skuInfoService.getSkusBySpuId(spuId);List<Long> skuIdList = skus.stream().map(SkuInfoEntity::getSkuId).collect(Collectors.toList());//拿到所有的skuId ,方便我们用id去查库存//TODO 4.查询当前SkU的所有可以被用来检索的规格属性List<ProductAttrValueEntity> baseAttrs = productAttrValueService.baseAttrListForSpu(spuId);//查出SKU的所有规格属性List<Long> attrIds = baseAttrs.stream().map(attr -> {return attr.getAttrId();}).collect(Collectors.toList());//把这些规格属性的ID组成一个数组List<Long> searchAttrIds= attrService.selectSearchAttrs(attrIds);//通过遍历这个规格属性的Id,找到 可检索 的 规格属性的IdSet<Long> idSet=new HashSet<>(searchAttrIds);//这里转成Set不是为了去重是因为set的查找操作时间复杂度是 O(1),而 List 的查找操作时间复杂度是 O(n)List<SkuEsModel.Attrs> attrsList = baseAttrs.stream().filter(item -> {//baseAttrs 里放的是规格属性的实体类,我们通过之前的查到的可检索的规格属性的ID,把实体类其中不可检索的过滤掉return idSet.contains(item.getAttrId());}).map(item -> {//再把 可检索的规格属性 映射成为SkuEsModel的内部类Attrs,方便我们底下的setSkuEsModel.Attrs attrs = new SkuEsModel.Attrs();BeanUtils.copyProperties(item, attrs);return attrs;}).collect(Collectors.toList());//这个stream流的功能是找出 baseAttrs 里的可检索的规格属性,装进 SkuEsModel的内部类Attrs(attrs) 里//TODO 1.发送远程调用,库存系统查询是否有库存 因为是批量所以拿出来Map<Long, Boolean> stockMap=null;try {R r = wareFeignService.getSkusHasStock(skuIdList);TypeReference<List<SkuHasStockVo>> typeReference = new TypeReference<>() {};stockMap = r.getData(typeReference).stream().collect(Collectors.toMap(SkuHasStockVo::getSkuId, item -> item.getHasStock()));}catch (Exception e){log.error("库存查询服务异常:原因{}",e);}//1.2封装每个sku的信息Map<Long, Boolean> finalStockMap = stockMap;List<SkuEsModel> upProducts = skus.stream().map(sku -> {//组装需要的数据SkuEsModel esModel = new SkuEsModel();BeanUtils.copyProperties(sku,esModel);esModel.setSkuPrice(sku.getPrice());esModel.setSkuImg(sku.getSkuDefaultImg());//TODO 1.发送远程调用,库存系统查询是否有库存//设置库存信息if (finalStockMap ==null){esModel.setHasStock(true);}else {esModel.setHasStock(finalStockMap.get(sku.getSkuId()));}//TODO 2.热度评分,默认刚上架为0后续可能有复杂的热度算法,后续再说esModel.setHotScore(0L);//TODO 3.查询品牌和分类信息BrandEntity brand = brandService.getById(esModel.getBrandId());esModel.setBrandName(brand.getName());esModel.setBrandImg(brand.getLogo());CategoryEntity category = categoryService.getById(esModel.getCatalogId());esModel.setCatalogName(category.getName());//设置检索属性esModel.setAttrs(attrsList);return esModel;}).collect(Collectors.toList());//TODO 5.将数据发给es进行保存  gulimall-search服务R r = searchFeignService.productStatusUp(upProducts);if(r.getCode()==0){//远程调用成功//TODO 6.修改当前SPU的状态baseMapper.updateSpuStatus(spuId, ProductConstant.StatusEnum.UP_SPU.getCode());}else {//远程调用失败//TODO 7.重复调用? 接口幂等性;重试机制?//feign的调用流程/*** 1.构造请求数据,将对象转为json* 2.发送请求进行执行(执行成功会解码相应的数据)* 3.执行请求会有重试机制*/}}

wear查询是否有库存:

   public List<SkuHasStockVo> getSkusHasStock(List<Long> skuIds) {List<SkuHasStockVo> collect = skuIds.stream().map(skuId -> {SkuHasStockVo vo = new SkuHasStockVo();//查询当前sku的总库存量Long count= baseMapper.getSkuStock(skuId);vo.setSkuId(skuId);vo.setHasStock(count==null?false:count>0);return vo;}).collect(Collectors.toList());return collect;}

统一返回类R里新增的方法:

//利用fastjson进行逆转public <T> T getData(TypeReference<T> typeReference){Object data = get("data");String s = JSON.toJSONString(data);T t = JSON.parseObject(s, typeReference);return t;}public R setData(Object data){put("data",data);return this;}

gulimall-search的controller类:

 //上架商品@PostMapping("/product")public R  productStatusUp(@RequestBody List<SkuEsModel> skuEsModels){boolean b=false;try {b=productSaveService.productStatusUp(skuEsModels);}catch (Exception e){log.error("ElasticSaveController商品上架错误:{}",e);return R.error(BizCodeEnume.PRODUCT_UP_EXCEPTION.getCode(),BizCodeEnume.PRODUCT_UP_EXCEPTION.getMsg());}if (!b){return R.ok();}else {return R.error(BizCodeEnume.PRODUCT_UP_EXCEPTION.getCode(),BizCodeEnume.PRODUCT_UP_EXCEPTION.getMsg());}}

方法的实现:

    @Overridepublic Boolean productStatusUp(List<SkuEsModel> skuEsModels) throws IOException {//保存进es//1.给ES中建立索引: product,建立好映射关系//2.给ES中保存数据:批量操作bulkBulkRequest bulkRequest = new BulkRequest();for (SkuEsModel skuEsModel : skuEsModels) {//构造保存请求IndexRequest indexRequest = new IndexRequest(EsConstant.PRODUCT_INDEX);indexRequest.id(skuEsModel.getSkuId().toString());String s = JSON.toJSONString(skuEsModel);indexRequest.source(s, XContentType.JSON);bulkRequest.add(indexRequest);}BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, GulimallElasticSearchConfig.COMMON_OPTIONS);//TODO 如果批量错误 可以处理错误Boolean b=bulk.hasFailures();List<String> collect = Arrays.stream(bulk.getItems()).map(item -> {return item.getId();}).collect(Collectors.toList());log.info("商品上架完成:{}",collect);return b;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/48835.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++】deque以及优先级队列

容器适配器 deque的介绍deque的原理介绍 priority_queue的介绍与使用priority_queue的介绍priority_queue的使用constructor&#xff08;构造函数&#xff09;emptypushpoptopsize priority_queue的模拟实现 仿函数何为适配器容器适配器deque的缺陷选择deque作为适配器的理由ST…

使用element UI Cascader 级联选择器实现省/市/区选择

<template><div><label>位置</label><el-cascader:options"pcaTextArr"v-model"selectedOptions"change"handleChangeAddress":props"{expandTrigger: hover,multiple: true,checkStrictly: true,emitPath: fal…

mailcow搭建安装教程:如何搭建专属邮箱!

mailcow搭建安装教程怎么用&#xff1f;怎么有效搭建邮箱服务器&#xff1f; 随着电子邮件在工作和生活中的重要性日益增加&#xff0c;拥有一个专属的电子邮件服务器变得越来越有吸引力。AokSend将详细介绍如何通过mailcow搭建一个专属邮箱&#xff0c;为你提供全方位的邮件管…

看起来很炫酷的科技感登录页面模板HTML

代码下载地址&#xff1a; 炫酷科技感登录页面模板带动画 (bootstrapmb.com)https://www.bootstrapmb.com/item/11891

Mailspring搭建安装教程:打造个性邮件体验

Mailspring搭建安装教程步骤&#xff01;如何选择电子邮件服务商&#xff1f; Mailspring作为一款功能强大、界面友好的邮件客户端&#xff0c;成为了许多用户的首选。AokSend将为大家提供详细的Mailspring搭建安装教程&#xff0c;帮助您打造个性化的邮件体验。 Mailspring搭…

Mybatis<collection>实现一对多

时隔多年又用到这样的查询方式了,提前声明一下分页最后返回的数据会小于每页条数&#xff0c;废话不多说直接上代码&#xff01; Data public class PbcUserTargetTaskPageVO {ApiModelProperty("个人绩效指标id")private Long id;ApiModelProperty("月份"…

uniapp判断h5/微信小程序/app端+实战展示

文章目录 导文使用条件编译的基本语法常见的平台标识符示例实战展示使用场景举例注意事项 导文 这里是导文 当你在开发Uni-app时&#xff0c;需要根据不同的平台&#xff08;比如App端、H5端、微信小程序等&#xff09;来执行不同的代码逻辑&#xff0c;可以使用条件编译来实现…

使用Fiddler进行Android和IOS抓包

Android抓包 要使用Telerik Fiddler Classic捕获Android设备的网络流量&#xff0c;您需要执行以下步骤&#xff1a; 在Fiddler Classic上进行设置&#xff1a; 确保已安装并使用BouncyCastle作为证书生成器。较新的Android版本会拒绝有效期超过两年的证书&#xff0c;目前只…

微信小程序开发--点击圆圈小问号弹注解tip 点击其他区域关闭(组件 w-tip 弹框在小圆圈的 上下左右 可以自己控制 )

引言 在微信小程序开发中&#xff0c;实现用户交互的多样性是提升用户体验的关键之一。本文将详细介绍如何在微信小程序中实现点击圆圈小问号弹出注解&#xff08;Tip&#xff09;的功能。这种功能常见于帮助信息、提示说明等场景&#xff0c;能够为用户提供即时的帮助和反馈。…

C语言迷宫

目录 开头程序程序的流程图程序输入与输出的效果结尾 开头 大家好&#xff0c;我叫这是我58。今天&#xff0c;我要来看我用C语言编译出来的迷宫游戏。 程序 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <Windows.h> void printmaze(char s…

若依前后端获取当前用户

后端 Autowired private TokenService tokenService;LoginUser loginUser tokenService.getLoginUser(); sysInquiry.setCreateBy(loginUser.getUsername()); sysInquiry.setCreateTime(DateUtils.getNowDate()); 前端 获取使用 const nickName this.$store.state.user.nick…

每日OJ_牛客_DD5 进制转换

目录 牛客_DD5 进制转换 解析代码 牛客_DD5 进制转换 进制转换_牛客题霸_牛客网 解析代码 本题题目很简单&#xff0c;题目的本意就是将10进制的数转换成N进制。N(2 ≤ N ≤ 16)可以看出进制最多可以到16进制。 首先想清楚原理&#xff1a;N进制数&#xff0c;每个进制位的值…

【Js】获取当前日期时间

日期基本数据&#xff1a; var myDate new Date(); //Date 对象会自动把当前日期和时间保存为其初始值 myDate.getYear(); //返回当前年份(2位)&#xff1b;请使用 getFullYear() 方法代替 myDate.getFullYear(); //返回完整的年份(4位,1970-????) myDate.getMonth();…

Hands-On 基于 Flagchip FC7300 MCAL-PWM 驱动 RGB

本文将详细介绍如何使用 EB 工具配置 Flagchip FC7300 MCAL PWM 驱动 RGB&#xff0c;并重点强调了配置 pwm 模块的过程以及对pwm 模块的详细解释。本次示例演示将会使用 FTU1_CH1、FTU1_CH3、 FTU1_CH5 通道来驱动 RBG 灯点亮。 查看原文请点此&#xff1a; 硬件平台&…

STM32测测速---编码电机读取速度的计算

1、首先先了解一下计算的公式 速度计算&#xff1a; 轮胎每转一圈的脉冲数取决于编码器的分辨率&#xff0c;可由下面公式进行计算&#xff1a; PPR是电机的线数 以GA25-370电机为例。 图片来源&#xff1a;第四节&#xff1a;STM32定时器&#xff08;4.JGA25-370霍尔编码器…

XGBoost算法—Python实现

XGBoost&#xff08;eXtreme Gradient Boosting&#xff09;是一个优化的分布式梯度增强库&#xff0c;旨在实现高效、灵活和便携的机器学习算法。以下是关于XGBoost的详细解析&#xff1a; 一、定义与背景 定义&#xff1a;XGBoost是一个在梯度提升&#xff08;Gradient Boo…

【Linux网络】套接字编程

本篇博客整理了 socket 套接字编程的相关内容&#xff0c;包括 socket 网络通信原理、socket 相关的系统调用接口等&#xff0c;分别演示了基于UDP协议、TCP协议的 socket 网络编程&#xff0c;旨在让读者更加深入理解网络通信原理和设计&#xff0c;对网络编程有初步的认识和掌…

OpenAI发布“最具性价比”模型 GPT-4o mini,GPT-3.5 Turbo 已成过去式

GPT-4o mini 相较于 GPT 3.5 在多个方面实现了显著的性能提升&#xff1a; 得分率提升&#xff1a;GPT-4o mini 在 MMLU&#xff08;一个涉及多种语言理解任务的基准测试&#xff09;上的得分率为 82%&#xff0c;优于 GPT-4&#xff0c;并且明显高于 GPT-3.5 2。 成本效益&am…

SpringBoot3 + Vue3 学习 Day 1

springboot 基础 和 注册接口的开发 学习视频基础SpringBoot 概述快速启动配置文件基本使用① application.properties② application.yml &#xff08;更好&#xff09; yml 配置信息的书写和获取yml 配置信息书写与获取 1 - Valueyml 配置信息书写与获取 2 - ConfigurationPr…

docker的学习(二):docker常用的高级技术总结

简介 docker的一些知识点的总结 UnionFS 分层&#xff0c;轻量级&#xff0c;高性能的文件系统&#xff0c;支持一层层的叠加功能来修改文件系统。 一次同时加载多个文件系统&#xff0c;把各层文件系统叠加起来&#xff0c;最终文件系统会包含所有底层的文件和目录&#xf…