文章目录
一,131-商城业务-商品上架-构造sku检索属性
1,开发目标
这一节的主要内容是完成获取规格属性信息的功能:
- 从数据库中获取与 SPU 关联的所有规格属性。
- 筛选出可被用于搜索的属性,并转换为 ES 所需的格式。
- 注意点1:SPU的规格参数是这个SPU下所有SKU公用的,查询一次即可。
- 注意点2:规程参数分为两类,一类是可搜索的,一类是不可搜索的。这里需要的是可搜索的规格参数。
2,详细设计
- ① 从
pms_product_attr_value
表中根据spu_id
查出这个spu
下所有的属性。 - ② 根据属性Id从属性表中
pms_attr
查询属性是否可搜索。 - ③ 将可搜索的属性信息封装到Es的Java模型中。
2.1,根据spu_id获取所有的规格参数
List<ProductAttrValueEntity> baseAttrs = productAttrValueService.baseAttrList4Spu(spuId);
对应的Service实现非常简单。
public List<ProductAttrValueEntity> baseAttrList4Spu(Long spuId) {
List<ProductAttrValueEntity> attrValueEntityList = this.baseMapper.selectList(
new QueryWrapper<ProductAttrValueEntity>().eq("spu_id", spuId));
return attrValueEntityList;
}
2.2,根据上一步中查询结果进一步确认是否可搜索
汇总所有属性Id,一次性查询出其中所有可搜索的属性Id。
List<Long> attrIds = baseAttrs.stream().map(ProductAttrValueEntity::getAttrId).collect(Collectors.toList());
// 查询可搜索的规格属性
List<Long> searchAttrIds = attrService.selectSearchableAttrs(attrIds);
对应的Service实现如下。
List<Long> selectSearchableAttrs(List<Long> attrIds) {
List<Long> searchAttrIds = this.baseMapper.selectSearchAttrIds(attrIds);
return searchAttrIds;
}
public
对应的Sql如下。
<select id="selectSearchAttrIds" resultType="java.lang.Long">
SELECT attr_id FROM pms_attr WHERE attr_id IN
<foreach collection="attrIds" item="id" separator="," open="(" close=")">
#{id}
</foreach>
AND search_type = 1
</select>
注意,search_type = 1
表示这个属性可搜索。
2.3,将可搜索的属性封装到Java模型中
将前两步的结果结合起来,把spu下所有可搜索的属性封装到Java模型中。
Set<Long> idSet = new HashSet<>(searchAttrIds);
List<SkuEsModel.Attrs> attrsList = baseAttrs
.stream().
filter(item -> idSet.contains(item.getAttrId()))
.map(item -> {
SkuEsModel.Attrs attrs = new SkuEsModel.Attrs();
BeanUtils.copyProperties(item, attrs);
return attrs;
}).collect(Collectors.toList());
二,132-商城业务-商品上架-远程查询库存&泛型结果封装
1,开发目标
获取库存信息:
- 通过远程调用库存服务,获取每个 SKU 的库存状态。
- 库存状态用于确定 SKU 是否有货。
2,详细设计
- ① 调用库存服务的接口
- ② 库存服务根据sku_id查询库存量
- ③ 根据查询结果填充模型
2.1 调用库存服务的接口
通过Feign调用库存服务的接口,并处理返回结果。
List<Long> skuIdList = skuInfoEntities.stream()
.map(SkuInfoEntity::getSkuId)
.collect(Collectors.toList());
R skuHasStock = wareFeignService.getSkuHasStock(skuIdList);
TypeReference<List<SkuHasStockVo>> typeReference = new TypeReference<List<SkuHasStockVo>>() {};
stockMap = skuHasStock.getData(typeReference).stream()
.collect(Collectors.toMap(SkuHasStockVo::getSkuId, item -> item.getHasStock()));
通过Feign将spu下所有的sku_id传递给库存服务。
2.2,库存服务根据sku_id查询库存量
① ware服务WareSkuController中定义供调用的接口。
(value = "/hasStock")
public R getSkuHasStock( List<Long> skuIds) {
//skuId stock
List<SkuHasStockVo> vos = wareSkuService.getSkuHasStock(skuIds);
return R.ok().setData(vos);
}
对应的Service实现如下。
List<SkuHasStockVo> getSkuHasStock(List<Long> skuIds) {
List<SkuHasStockVo> skuHasStockVos = skuIds.stream().map(item -> {
Long count = this.baseMapper.getSkuStock(item);
SkuHasStockVo skuHasStockVo = new SkuHasStockVo();
skuHasStockVo.setSkuId(item);
skuHasStockVo.setHasStock(count == null?false:count > 0);
return skuHasStockVo;
}).collect(Collectors.toList());
return skuHasStockVos;
}
public
对应的Dao层Sql如下,逻辑非常简单,查询可用库存大于0的sku_id。
<select id="listWareIdHasSkuStock" resultType="java.lang.Long">
SELECT
ware_id
FROM
wms_ware_sku
WHERE
sku_id = #{skuId}
AND stock - stock_locked > 0
</select>
2.3,根据查询结果填充模型
调用库存接口查询到结果之后,从响应R中取出数据,注意因为R本质是一个Map,所以需要将Map中的数据序列化为我们需要的类型,这里使用了阿里的FastJson工具包中的TypeReference完成这个任务。
R skuHasStock = wareFeignService.getSkuHasStock(skuIdList);
TypeReference<List<SkuHasStockVo>> typeReference = new TypeReference<List<SkuHasStockVo>>() {};
stockMap = skuHasStock.getData(typeReference).stream()
.collect(Collectors.toMap(SkuHasStockVo::getSkuId, item -> item.getHasStock()));
public <T> T getData(TypeReference<T> typeReference) {
Object data = get("data"); //默认是map
String jsonString = JSON.toJSONString(data);
T t = JSON.parseObject(jsonString, typeReference);
return t;
}
拿到结果之后,在遍历Sku的循环体中填充库存信息。
// 4.2 设置库存信息
if (finalStockMap == null) {
esModel.setHasStock(true);
} else {
esModel.setHasStock(finalStockMap.get(sku.getSkuId()));
}
这样注意从响应中取得结果的方式,是开发中常用的技巧。