十二、商品服务&新增商品
2023年7月30日大约 6 分钟
上一级页面:index-la
十二、商品服务&新增商品
12.1 获取分类关联的品牌
前端发送请求
后端编写:
Controller
/**
* 获取分类关联的品牌
* @param catId
* @return
*/
@GetMapping("/brands/list")
public R relationBrandList(@RequestParam(value = "catId",required = true) Long catId) {
List<BrandEntity> vos = categoryBrandRelationService.getBrandCatId(catId);
//拿到 品牌对象数据后 从中抽取除 品牌姓名和id
List<BrandVo> collect = vos.stream().map(item -> {
BrandVo brandVo = new BrandVo();
brandVo.setBrandId(item.getBrandId());
brandVo.setBrandName(item.getName());
return brandVo;
}).collect(Collectors.toList());
return R.ok().put("data",collect);
}
Service实现
@Override
public List<BrandEntity> getBrandCatId(Long catId) {
// 根据分类id查询出 分类和品牌的关系表
List<CategoryBrandRelationEntity> catelogId = categoryBrandRelationDao.selectList(new QueryWrapper<CategoryBrandRelationEntity>().eq("catelog_id", catId));
List<BrandEntity> collect = catelogId.stream().map(item -> {
//根据品牌id查询出品牌对象
BrandEntity brandEntity = brandDao.selectById(item.getBrandId());
return brandEntity;
}).collect(Collectors.toList());
return collect;
}
总结:
业务操作设计两个表
- pms_brand
- pms_category_brand_relation
请求参数是 CatId Long类型
- 先根据 CatId 在 pms_category_brand_relation表中查询到品牌 Id
- 拿到 brand_id 查询出 brand 的相关信息
- 组装成 BrandVo 后 返回
12.2 获取分类下所有分组以及属性
基本信息输入成功后,就会跳转到规格参数,
并根据分类id查询出对应数据
Controller
/**
* 获取分类下所有分组&关联属性
* @param catelogId
* @return
*/
@RequestMapping("/{catelogId}/withattr")
public R getAttrGroupWithAttrs(@PathVariable("catelogId") Long catelogId) {
List<AttrGroupWithAttrsVo> vos = attrGroupService.getAttrGroupWithAttrsByCatelogId(catelogId);
return R.ok().put("data",vos);
}
Service 实现
@Override
public List<AttrGroupWithAttrsVo> getAttrGroupWithAttrsByCatelogId(Long catelogId) {
// 1、根据分类id查询出 查询分组关系
List<AttrGroupEntity> attrgroupEntites = this.list(new QueryWrapper<AttrGroupEntity>().eq("catelog_id", catelogId));
List<AttrGroupWithAttrsVo> collect = attrgroupEntites.stream().map(group -> {
AttrGroupWithAttrsVo attrsVo = new AttrGroupWithAttrsVo();
// 2、将分组属性拷贝到 VO中
BeanUtils.copyProperties(group, attrsVo);
// 3、通过分组id查询出 商品属性信息
// 调用 getRelationAttr方法先根据 分组id去 中间关系表查询到商品属性id 然后根据商品属性id查询到商品信息
List<AttrEntity> relationAttr = attrService.getRelationAttr(attrsVo.getAttrGroupId());
attrsVo.setAttrs(relationAttr);
return attrsVo;
}).collect(Collectors.toList());
return collect;
}
12.3 商品 VO 抽取&商品新增业务流程
商品属性、销售属性、规格参数、基本信息都填好了后就会生成一串 JSON
我们将 json 放到 json解析网站上 并生成对应得实体类
12.3.4 封装 Vo 中,更改对应得属性
有些参与计算的属性 如 int price 将类型更改为 BigDecimal
12.3.5 分析业务流程
业务流程:
12.3.6 主要编码!
@Transactional
@Override
public void saveSpuInfo(SpuSaveVo vo) {
// 1、保存Spu基本信息 pms_spu_info
SpuInfoEntity spuInfoEntity = new SpuInfoEntity();
BeanUtils.copyProperties(vo,spuInfoEntity);
spuInfoEntity.setCreateTime(new Date());
spuInfoEntity.setUpdateTime(new Date());
this.saveBaseSpuInfo(spuInfoEntity);
// 2、保存Spu的描述信息 pms_spu_info_desc
List<String> decript = vo.getDecript();
SpuInfoDescEntity spuInfoDescEntity = new SpuInfoDescEntity();
// SpuInfoEntity保存到取得 spuId 设置到 Desc中
spuInfoDescEntity.setSpuId(spuInfoEntity.getId());
// 以逗号来拆分
spuInfoDescEntity.setDecript(String.join(",",decript));
spuInfoDescService.saveSpuInfoDesc(spuInfoDescEntity);
// 3、保存Spu的图片集 pms_spu_images
List<String> imageList = vo.getImages();
spuImagesService.saveImages(spuInfoEntity.getId(),imageList);
// 4、保存spu的规格参数 pms_product_attr_value
List<BaseAttrs> baseAttrs = vo.getBaseAttrs();
List<ProductAttrValueEntity> collect = baseAttrs.stream().map(attr -> {
// 设置 spu 属性值
ProductAttrValueEntity valueEntity = new ProductAttrValueEntity();
valueEntity.setAttrId(attr.getAttrId());
AttrEntity attrEntity = attrService.getById(attr.getAttrId());
valueEntity.setAttrName(attrEntity.getAttrName());
valueEntity.setSpuId(spuInfoEntity.getId());
valueEntity.setQuickShow(attr.getShowDesc());
valueEntity.setAttrValue(attr.getAttrValues());
return valueEntity;
}).collect(Collectors.toList());
attrValueService.saveProductAttr(collect);
// 5、保存SPU的积分信息 gulimall_sms sms => sms_spu_bounds
Bounds bounds = vo.getBounds();
SpuBoundTo spuBoundTo = new SpuBoundTo();
BeanUtils.copyProperties(bounds,spuBoundTo);
spuBoundTo.setSpuId(spuInfoEntity.getId());
// 远程服务调用
R r = couponFeignService.saveSpuBounds(spuBoundTo);
if (r.getCode() != 0) {
log.error("远程保存优惠信息失败");
}
// 5、保存当前Spu对应的所有SKU信息
List<Skus> skus = vo.getSkus();
if (skus != null && skus.size() > 0) {
// 遍历 skus 集合
skus.forEach(item ->{
String defaultImage = "";
// 遍历 skus 集合中的图片
for (Images image : item.getImages()) {
// 默认图片等于 1 该记录则是默认图片
if (image.getDefaultImg() == 1) {
defaultImage = image.getImgUrl();
}
}
// private String skuName;
// private String price;
// private String skuTitle;
// private String skuSubtitle;
// 只有上面4个属性相同
SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
BeanUtils.copyProperties(item,skuInfoEntity);
// 其他属性需要自己赋值
skuInfoEntity.setBrandId(spuInfoEntity.getBrandId());
skuInfoEntity.setCatalogId(spuInfoEntity.getCatalogId());
skuInfoEntity.setSaleCount(0L);
skuInfoEntity.setSpuId(spuInfoDescEntity.getSpuId());
skuInfoEntity.setSkuDefaultImg(defaultImage);
//5.1、SKU的基本信息 pms_sku_info
skuInfoService.saveSkuInfo(skuInfoEntity);
Long skuId = skuInfoEntity.getSkuId();
// 保存 sku 图片信息
List<SkuImagesEntity> imagesEntities = item.getImages().stream().map(img -> {
SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
skuImagesEntity.setSkuId(skuId);
skuImagesEntity.setImgUrl(img.getImgUrl());
skuImagesEntity.setDefaultImg(img.getDefaultImg());
return skuImagesEntity;
}).filter(entity ->{
//返回 true 需要 false 过滤
return !StringUtils.isEmpty(entity.getImgUrl());
}).collect(Collectors.toList());
// TODO 没有图片路径的无需保存
//5.2、SKU的图片信息 pms_sku_images
skuImagesService.saveBatch(imagesEntities);
List<Attr> attr = item.getAttr();
// 保存 sku 销售属性
List<SkuSaleAttrValueEntity> skuSaleAttrValueEntities = attr.stream().map(a -> {
SkuSaleAttrValueEntity skuSaleAttrValueEntity = new SkuSaleAttrValueEntity();
BeanUtils.copyProperties(a, skuSaleAttrValueEntity);
skuSaleAttrValueEntity.setSkuId(skuId);
return skuSaleAttrValueEntity;
}).collect(Collectors.toList());
//5.3、SKU的销售属性信息 pms_sku_sale_attr_value
saleAttrValueService.saveBatch(skuSaleAttrValueEntities);
//5.4、SKU的优惠、满减等信息 gulimall_sms ->sms_sku_ladder \sms_sku_full_reduction\sms_member_price
SkuReductionTo skuReductionTo = new SkuReductionTo();
BeanUtils.copyProperties(item,skuReductionTo);
skuReductionTo.setSkuId(skuId);
if (skuReductionTo.getFullCount() > 0 || skuReductionTo.getFullPrice().compareTo(new BigDecimal("0")) == 1) {
R r1 = couponFeignService.saveSkuReduction(skuReductionTo);
if (r1.getCode() != 0) {
log.error("远程保存sku优惠信息失败");
}
}
});
}
}
saveImages
@Override
public void saveImages(Long id, List<String> imageList) {
if (imageList == null || imageList.size() <=0) {
log.error("图片为空!!!!!!");
} else {
List<SpuImagesEntity> collect = imageList.stream().map(img -> {
SpuImagesEntity entity = new SpuImagesEntity();
// 设置主要属性
entity.setSpuId(id);
entity.setImgUrl(img);
return entity;
}).collect(Collectors.toList());
this.saveBatch(collect );
}
}
远程服务调用 对应方法
保存了 商品阶梯价格、商品满减信息、商品会员价格
@Override
public void saveSkuReduction(SkuReductionTo skuReductionTo) {
//5.4、SKU的优惠、满减等信息 gulimall_sms ->sms_sku_ladder \sms_sku_full_reduction\sms_member_price
//sms_sku_ladder
SkuLadderEntity skuLadderEntity = new SkuLadderEntity();
skuLadderEntity.setSkuId(skuReductionTo.getSkuId());
skuLadderEntity.setFullCount(skuReductionTo.getFullCount());
skuLadderEntity.setAddOther(skuReductionTo.getCountStatus());
skuLadderEntity.setDiscount(skuReductionTo.getDiscount());
if (skuLadderEntity.getFullCount() > 0) {
skuLadderService.save(skuLadderEntity);
}
//sms_sku_full_reduction
SkuFullReductionEntity skuFullReductionEntity = new SkuFullReductionEntity();
BeanUtils.copyProperties(skuReductionTo,skuFullReductionEntity);
// BigDecimal 用 compareTo来比较
if (skuFullReductionEntity.getFullPrice().compareTo(new BigDecimal("0")) == 1) {
this.save(skuFullReductionEntity);
}
//sms_member_price
List<MemberPrice> memberPrice = skuReductionTo.getMemberPrice();
List<MemberPriceEntity> collect = memberPrice.stream().map(item -> {
MemberPriceEntity priceEntity = new MemberPriceEntity();
priceEntity.setSkuId(skuReductionTo.getSkuId());
priceEntity.setMemberPrice(item.getPrice());
priceEntity.setMemberLevelName(item.getName());
priceEntity.setMemberLevelId(item.getId());
priceEntity.setAddOther(1);
return priceEntity;
}).filter(item -> {
// 会员对应价格等于0 过滤掉
return item.getMemberPrice().compareTo(new BigDecimal("0")) == 1;
}).collect(Collectors.toList());
memberPriceService.saveBatch(collect);
}
12.3.7 总结
- 电商系统中大表数据不做关联 宁可一点一点查询
- 商品新增业务,眨眼一看很多代码,但是如果把他们划分成几个功能点一一完成,业务也就不会变得很庞大
相关操作的表
12.3.8 商品保存后 Debug 调试
很少有一次写的代码能一次通过,所以我们要 一个功能点一个断点来调试程序是否正确
# 将当前会话等级设置成读为提交,当前窗口就能查看到没有提交的数据
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
具体 Debug 过程不在此叙述
12.3.9 商品保存其他问题处理
1、 sku_images
表中 img_url 字段为空
sku_images
中有很多图片都是为空,因此我们需要在程序中处理这个数据,空数据不写入到数据库中
解决思路:
skuImages
保存部分代码、如果 ImgUrl
为空则进行过滤
}).filter(entity ->{
//返回 true 需要 false 过滤
return !StringUtils.isEmpty(entity.getImgUrl());
}).collect(Collectors.toList());
2、sku 满减以及打折信息 数据出现错误
有部分数据 为0
解决思路:
在代码中过滤对应为0的数据
部分修改代码
// 满几件 大于0 可以添加 满多少钱 至少要大于0
if (skuReductionTo.getFullCount() > 0 || skuReductionTo.getFullPrice().compareTo(new BigDecimal("0")) == 1) {
R r1 = couponFeignService.saveSkuReduction(skuReductionTo);
if (r1.getCode() != 0) {
log.error("远程保存sku优惠信息失败");
}
}
远程服务中也进行对应修改
/**
保存 商品阶梯价格
件数 大于0才能进行修改
**/
if (skuLadderEntity.getFullCount() > 0) {
skuLadderService.save(skuLadderEntity);
}
/**
保存商品满减信息
**/
// BigDecimal 用 compareTo来比较
if (skuFullReductionEntity.getFullPrice().compareTo(new BigDecimal("0")) == 1) {
this.save(skuFullReductionEntity);
}
/**
保存商品会员价格
也进行了过滤数据
**/
}).filter(item -> {
// 会员对应价格等于0 过滤掉
return item.getMemberPrice().compareTo(new BigDecimal("0")) == 1;
}).collect(Collectors.toList());
3、程序中其他的异常
程序中总会出现一些其他的异常的,这个留到高级篇进行讲解