进行上架操作

一. 业务思路

  1. 根据es mapping创建java entity
  2. 根据spuId 查询到sku列表 根据查询到的sku列表 将sku值映射到 第一步创建的java entity中
  3. 设置商品热度 热度服务hotScore 先初始化为0 之后再拓展
  4. 第三步查询到的sku中有保存brandId 根据brandId 查询到brandName 将brandId和brandName映射到java entity中
  5. 第三步查询中的sku也有保存categoryId 根据categoryId 查询到categoryName 将categoryId和categoryName映射到java entity中
  6. 根据spuId查询出attrs 然后过滤出可以查询的attr属性 并设置java entity
  7. 远程查询库存 若库存大于0 啧表示有库存
  8. 2 - 7 步已经构造出整个es enttiy了 远程调用search服务进行上架操作
  9. 根据远程调用的结果判断是否上架成功

二. 具体实现

2.1 构造java entity

根据json构造java entity

{
  "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"
      },
      "notScore": {
        "type": "long"
      },
      "brandId": {
        "type": "long"
      },
      "catelogI": {
        "type": "long"
      },
      "brandName": {
        "type": "keyword",
        "index": false,
        "doc_values": false
      },
      "brandImg": {
        "type": "keyword",
        "index": false,
        "doc_values": false
      },
      "catelogName": {
        "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"
          }
        }
      }
    }
  }
}

这里存储属性使用了静态内部类
静态内部类和普通内部类的区别是 静态内部类可以独立与外部类存在的 而普通内部类必须是以外部类为前提存在

public class SkuESEntity {
    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;

    public Long getSkuId() {
        return skuId;
    }

    public void setSkuId(Long skuId) {
        this.skuId = skuId;
    }

    public Long getSpuId() {
        return spuId;
    }

    public void setSpuId(Long spuId) {
        this.spuId = spuId;
    }

    public String getSkuTitle() {
        return skuTitle;
    }

    public void setSkuTitle(String skuTitle) {
        this.skuTitle = skuTitle;
    }

    public BigDecimal getSkuPrice() {
        return skuPrice;
    }

    public void setSkuPrice(BigDecimal skuPrice) {
        this.skuPrice = skuPrice;
    }

    public String getSkuImg() {
        return skuImg;
    }

    public void setSkuImg(String skuImg) {
        this.skuImg = skuImg;
    }

    public Long getSaleCount() {
        return saleCount;
    }

    public void setSaleCount(Long saleCount) {
        this.saleCount = saleCount;
    }

    public Boolean getHasStock() {
        return hasStock;
    }

    public void setHasStock(Boolean hasStock) {
        this.hasStock = hasStock;
    }

    public Long getHotScore() {
        return hotScore;
    }

    public void setHotScore(Long hotScore) {
        this.hotScore = hotScore;
    }

    public Long getBrandId() {
        return brandId;
    }

    public void setBrandId(Long brandId) {
        this.brandId = brandId;
    }

    public Long getCatalogId() {
        return catalogId;
    }

    public void setCatalogId(Long catalogId) {
        this.catalogId = catalogId;
    }

    public String getBrandName() {
        return brandName;
    }

    public void setBrandName(String brandName) {
        this.brandName = brandName;
    }

    public String getBrandImg() {
        return brandImg;
    }

    public void setBrandImg(String brandImg) {
        this.brandImg = brandImg;
    }

    public String getCatalogName() {
        return catalogName;
    }

    public void setCatalogName(String catalogName) {
        this.catalogName = catalogName;
    }

    public List<Attr> getAttrs() {
        return attrs;
    }

    public void setAttrs(List<Attr> attrs) {
        this.attrs = attrs;
    }

    private List<Attr> attrs;

    public static class Attr {
        private Long attrId;
        private String attrName;
        private String attrValue;

        public Long getAttrId() {
            return attrId;
        }

        public void setAttrId(Long attrId) {
            this.attrId = attrId;
        }

        public String getAttrName() {
            return attrName;
        }

        public void setAttrName(String attrName) {
            this.attrName = attrName;
        }

        public String getAttrValue() {
            return attrValue;
        }

        public void setAttrValue(String attrValue) {
            this.attrValue = attrValue;
        }
    }
}

2.2 根据spuId查询到基本信息并映射到java entity中

这没什么好说的调用mapper查询sku列表 然后編列sku列表可以 直接使用copyProperties复制bean的直接复制 不可以使用copyProperties手动复制即可

// 查询sku列表
        List<PmsSkuInfo> skuInfoList = this.getSkuInfoById(spuId);
		        List<SkuESEntity> skuESEntityList = skuInfoList.stream().map((skuInfo) -> {
            SkuESEntity skuESEntity = new SkuESEntity();

            BeanUtils.copyProperties(skuInfo, skuESEntity);
            skuESEntity.setSkuPrice(skuInfo.getPrice());
            skuESEntity.setSkuImg(skuInfo.getSkuDefaultImg());

            return skuESEntity;
        }).collect(Collectors.toList());

2.3 设置热度操作

直接初始化为0即可

           skuESEntity.setHotScore(0L);

2.4 设置brand信息

这个sku中都有保存 直接查询设置即可

            PmsBrand brand = null;
            if (brandId != null) {
                brand = brandService.getById(brandId);
            }

            if (brand != null) {
                skuESEntity.setBrandImg(brand.getLogo());
                skuESEntity.setBrandName(brand.getName());
            }

2.5 设置category信息

这一步和上一部基本相同 sku中也有保存

            PmsCategory category = categoryService.getById(skuInfo.getCatalogId());
            skuESEntity.setCatalogName(category.getName());

2.6 查询并设置商品属性

表关系如下
image
image

2.6.1首先根据spuid查询到spu中关联的所有属性

        // 查询attrs
        List<PmsProductAttrValue> attrValues = pmsProductAttrValueService.attrValueList(spuId);

2.6.2 拿到属性id查询attrs表中 searcType为1的的id返回 属性id列表

        // 过滤出可以被检索出的属性id
        List<Long> attrsIdList = attrValues.stream().map(PmsProductAttrValue::getAttrId).collect(Collectors.toList());
        List<Long> searchableAttrIds = attrService.getSearchableAttrIds(attrsIdList);

过滤attr的mapper
image
使用in语法为查出in列表范围中的值
image

2.6.3 可以list.contains()可以查询id是否存在在list中 然后根据这个条件过滤attr即可 最后组装成es java 内部类 返回

        List<SkuESEntity.Attr> skuEsEntityAttrs = attrValues.stream().filter((attr) -> {
            return searchableAttrIds.contains(attr.getAttrId());
        }).map((attr) -> {
            SkuESEntity.Attr skuEsEntityAttr = new SkuESEntity.Attr();
            BeanUtils.copyProperties(attr, skuEsEntityAttr);
            return skuEsEntityAttr;
        }).collect(Collectors.toList());

2.6.4 最后设置到es entity中

            // 设置检索属性
            skuESEntity.setAttrs(skuEsEntityAttrs);

2.7 远程调用库存服务

创建一个to to中保存skuId和是否有库存
image
判断是否有库存可以根据库存数来判断 若大于0表示有库存 否则无 因为有不同的仓库存放不同的sku 将所有仓库的库存数 - 减去所有仓库的被锁定的库存即可算出库存数
image
将传入的skuid列表遍历查询返回即可

    public List<WareSkuHasStockTO> skuIdsHasStock(List<Long> skuIds) {
        return skuIds.stream().map((skuId) -> {
            WareSkuHasStockTO wareSkuHasStockTO = new WareSkuHasStockTO();
            Long skuCount = wmsWareSkuMapper.getSkuStockCount(skuId);
            wareSkuHasStockTO.setSkuId(skuId);
            // 如果搜不到代表没库存
            if (skuCount == null) {
                wareSkuHasStockTO.setHasStock(false);
            } else {
                wareSkuHasStockTO.setHasStock(skuCount > 0);
            }

            return wareSkuHasStockTO;
        }).collect(Collectors.toList());
    }

创建fign接口

@FeignClient(value = "ware-service")
@RequestMapping("/wms-ware-sku")
public interface WareFeignService {
    @PostMapping("/hasStock")
    public Result hasStock(@RequestBody List<Long> skuIds);
}

调用feign接口 将data转换为map 根据map 设置库存

            Result result = wareFeignService.hasStock(skuIdList);
            List<Map<String, Object>> wareSkuHasStockTOMaps = (List<Map<String, Object>>) result.getData();

            wareSkuHasStockMap = new HashMap<>();
            Map<Long, Boolean> finalWareSkuHasStockMap1 = wareSkuHasStockMap;
            wareSkuHasStockTOMaps.forEach((map) -> {
                finalWareSkuHasStockMap1.put(Long.valueOf(String.valueOf(map.get("skuId"))), (Boolean) map.get("hasStock"));
            });

若map = 0 则表示无库存 然后根据id获取是否有库存即可

            if (finalWareSkuHasStockMap == null && finalWareSkuHasStockMap.size() <= 0) {
                skuESEntity.setHasStock(false);
            } else {
                skuESEntity.setHasStock(finalWareSkuHasStockMap.get(skuInfo.getSkuId()));
            }

2.8 原创调用es

创建一个constract用于保存常量 这里先保存个index名称

public class ElasticSearchContract {
    public static final String PRODUCT_INDEX = "product";
}

然后拼装批量上传请求 这个很简单 根据文档设置index id document即可

        List<BulkOperation> bulkOperations = new ArrayList<>();

        skuESEntities.forEach((sku) -> {
            BulkOperation bulkOperation = new BulkOperation.Builder().create((doc) -> doc.index(ElasticSearchContract.PRODUCT_INDEX)
                    .document(sku)
                    .id(sku.getSkuId().toString())).build();
            bulkOperations.add(bulkOperation);
        });

进行批量操作


        BulkRequest bulkRequest = new BulkRequest.Builder()
                .index(ElasticSearchContract.PRODUCT_INDEX).operations(bulkOperations).build();
        BulkResponse bulkResponse = elasticsearchClient.bulk(bulkRequest);

如果 item.error() 中不为空 则表示该商品上架失败
bulkResponse.errors(); 可以获取是否有上架失败的列
可以记录上架失败的日志进行输出

        List<BulkResponseItem> items = bulkResponse.items();
        List<BulkResponseItem> upErrorSkuList = items.stream().filter((item) -> {
            return item.error() != null;
        }).collect(Collectors.toList());

        if (upErrorSkuList.size() > 0) {
            logger.error("上架失败{}", upErrorSkuList);
        }

        return bulkResponse.errors();

若有异常或若有上架失败的 则直接返回

    @PostMapping("/product")
    public Result saveProduct(@RequestBody List<SkuESEntity> skuESEntities) {

        Boolean result = true;
        try {
            result = elasticSearchProductSaveService.productUpToEs(skuESEntities);
        } catch (IOException e) {
            logger.error("上架失败{}", e.getMessage());
            return new Result(ResponseStatusEnum.PRODUCT_UP_ERROR.getCode(), ResponseStatusEnum.PRODUCT_UP_ERROR.getMessage(), false);
        }

        if (result) {
            return new Result(ResponseStatusEnum.PRODUCT_UP_ERROR.getCode(), ResponseStatusEnum.PRODUCT_UP_ERROR.getMessage(), false);
        } else {
            return Result.ok();
        }
    }

2.9 进行上架操作

        Result result = elasticSearchSaveFeignService.saveProduct(skuESEntityList);
        if (result.getSuccess()) {
            // 如果上架成功 啧修改spu 状态为上架
            spuInfoMapper.changeSpuStatusUp(spuId, ProductConstruct.SpuStatus.UP_STATUS.getCode());
        } else {
            // todo 接口反复调用幂等性问题 上架失败重试操作
        }
posted @   RainbowMagic  阅读(114)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示