上半部分:商品微服务(上)
文章目录
1 实现商品新增
即点击 新增商品 出现如下弹窗,填写设置参数完毕之后保存
1.1 controller
可以看出
请求方式:get
请求路径:/cid
请求参数:cid
返回结果:当前分类下的所有Brand,是一个List集合
@GetMapping("cid/{cid}")
public ResponseEntity<List<Brand>> queryBrandByCid(@PathVariable("cid")Long cid){
return ResponseEntity.ok(brandService.queryBrandByCid(cid));
}
1.2 service
public List<Brand> queryBrandByCid(Long cid) {
List<Brand> brands = brandMapper.queryByCategoryId(cid);
if(CollectionUtils.isEmpty(brands)){
throw new LyException(ExceptionEnum.BRAND_NOT_FOUND);
}
return brands;
}
1.3 mapper
因为传过来的是cid,但是Brand中没有cid字段,所以无法通过setCid()来查询非空字段,此外品牌和分类有一张中间表,需要自己编写sql语句。
@Select("SELECT b.* FROM tb_brand b LEFT JOIN tb_category_brand cb ON b.id = cb.brand_id WHERE cb.category_id = #{cid}")
List<Brand> queryByCategoryId(@Param("cid")Long cid);
运行代码,实现:
2 富文本编辑器——用来填写商品描述信息
上一步填写完品牌类别标题等信息,我们该点击下一页填写下一页的信息了,商品描述信息比较复杂,而且图文并茂,甚至包括视频。
这样的内容,一般都会使用富文本编辑器。
富文本编辑器,内嵌于浏览器,是一种所见即所得的文本编辑器。普通的框只能输入文字,而富文本还能给文字加颜色样式等,功能很丰富。富文本编辑器有很多,例如:KindEditor、Ueditor。
我们采用的是一款支持Vue的富文本编辑器:vue-quill-editor
原始图片的上传直接上传了整个图片的数据,无法直接上传到后台,因此我们对其进行了封装,支持了图片的上传,并且图片存储方式一个img标签,节省了空间。
3 添加商品规格参数
当上传了商品的描述信息以后点击下一步,下一步就需要填充商品的规格参数信息了,但是点击下一步没有出现填写的文本框下拉菜单等选项,这是为什么呢?
当我们在 “基本信息” 选择了商品分类时会发出两条查询请求,一条是之前已经实现过的根据分类id查询品牌集合,另外一条就是根据分类id查询规格参数,但是我们之前实现过根据组id查询参数的请求,因此我们需要完善一下这条请求——考虑到以后可能还会根据是否搜索、是否为通用属性等条件过滤,我们多添加几个过滤条件。
3.1 controller
如果param中有属性为null,则不会吧属性作为查询条件,因此该方法具备通用性,即可根据gid查询,也可根据cid查询
@GetMapping("/params")
public ResponseEntity<List<SpecParam>> querySpecParams(@RequestParam(value = "gid",required = false)Long gid,
@RequestParam(value = "cid",required = false)Long cid,
@RequestParam(value = "searching",required = false)Boolean searching){
return ResponseEntity.ok(specificationService.querySpecParams(gid,cid,searching));
}
3.2 service
public List<SpecParam> querySpecParams(Long gid, Long cid, Boolean searching) {
SpecParam param = new SpecParam();
param.setGroupId(gid);
param.setCid(cid);
param.setSearching(searching);
List<SpecParam> params = paramMapper.select(param);
if(CollectionUtils.isEmpty(params)){
throw new LyException(ExceptionEnum.GROUP_PARAM_NOT_FOUND);
}
return params;
}
刷新页面之后:
4 页面表单提交
填写一些属性后,会在页面下方生成一个sku表格
点击保存完成上述功能,接下来我们去实现。
4.1 实体类
spu、spudetail、sku、stock四个实体类,见笔记五。
4.2 controller
@PostMapping("goods")
public ResponseEntity<Void> saveGoods(@RequestBody Spu spu){
goodsService.saveGoods(spu);
return ResponseEntity.status(HttpStatus.CREATED).build();//没有返回值
}
4.3 service
@Transactional
public void saveGoods(Spu spu) {
//新增spu
spu.setId(null);
spu.setSaleable(true);
spu.setValid(false);
spu.setCreateTime(new Date());
spu.setLastUpdateTime(spu.getCreateTime());
int count = spuMapper.insert(spu);
if (count != 1) {
throw new LyException(ExceptionEnum.GOODS_SAVE_ERROR);
}
//新增spu_detail
SpuDetail spuDetail = spu.getSpuDetail();
spuDetail.setSpuId(spu.getId());
spuDetailMapper.insert(spuDetail);
//新增sku和库存
saveSkuAndStock(spu);
//发送mq消息
//amqpTemplate.convertAndSend("item.insert",spu.getId());
}
private void saveSkuAndStock(Spu spu) {
int count;//新增sku
List<Sku> skus = spu.getSkus();
List<Stock> stockList = new ArrayList<>();
for (Sku sku : skus) {
sku.setCreateTime(new Date());
sku.setLastUpdateTime(sku.getCreateTime());
sku.setSpuId(spu.getId());
count = skuMapper.insert(sku);
if(count!=1)
throw new LyException(ExceptionEnum.GOODS_SAVE_ERROR);
//新增库存
Stock stock = new Stock();
stock.setSkuId(sku.getId());
stock.setStock(sku.getStock());
stockList.add(stock);
}
//批量新增库存
count = stockMapper.insertList(stockList);
if(count!=stockList.size())
throw new LyException(ExceptionEnum.GOODS_SAVE_ERROR);
}
5 修改商品信息
修改之前要先查找,除了查找spu信息还要查找sku信息
5.1 controller
@GetMapping("/spu/detail/{id}")
public ResponseEntity<SpuDetail> querySpuDetailById(@PathVariable("id")Long id){
return ResponseEntity.ok(goodsService.queryDetailById(id));
}
@GetMapping("/sku/list")
public ResponseEntity<List<Sku>> querySkuBySpuId(@RequestParam("id") Long spuId){
return ResponseEntity.ok(goodsService.querySkuBySpuId(spuId));
}
5.2 service
public SpuDetail queryDetailById(Long spuId) {
SpuDetail spuDetail = spuDetailMapper.selectByPrimaryKey(spuId);
if(spuDetail==null)
throw new LyException(ExceptionEnum.GOODS_SAVE_ERROR);
return spuDetail;
}
public List<Sku> querySkuBySpuId(Long spuId) {
//查询sku
Sku sku = new Sku();
sku.setSpuId(spuId);
List<Sku> skuList = skuMapper.select(sku);
if(CollectionUtils.isEmpty(skuList))
throw new LyException(ExceptionEnum.SKU_NOT_FOUND);
//查询库存
List<Long> ids = skuList.stream().map(Sku::getId).collect(Collectors.toList());
List<Stock> stockList = stockMapper.selectByIdList(ids);
if(CollectionUtils.isEmpty(stockList))
throw new LyException(ExceptionEnum.STOCK_NOT_FOUND);
//把stock变成一个map,其key:skuId,值:库存值
Map<Long, Integer> stockMap = stockList.stream().collect(Collectors.toMap(Stock::getSkuId, Stock::getStock));
skuList.forEach(s ->s.setStock(stockMap.get(s.getId())));
return skuList;
}
6 修改后商品的提交
保存按钮与新增其实是同一个,因此提交的逻辑也是一样的。但是也有一点区别,spu数据可以修改,但是SKU数据无法修改,因为有可能之前存在的SKU现在已经不存在了,或者以前的sku属性都不存在了。比如以前内存有4G,现在没了,因此这里直接删除以前的SKU,然后新增即可。
6.1 controller
@PutMapping("goods")
public ResponseEntity<Void> updateGoods(@RequestBody Spu spu){
goodsService.updateGoods(spu);
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();//没有返回值
}
6.2 service
@Transactional
public void updateGoods(Spu spu) {
if(spu.getId() == null)
throw new LyException(ExceptionEnum.GOODS_UPDATE_ERROR);
Sku sku = new Sku();
sku.setSpuId(spu.getId());
//查询sku
List<Sku> skuList = skuMapper.select(sku);
if(!CollectionUtils.isEmpty(skuList)){
//删除sku
skuMapper.delete(sku);
//删除库存
List<Long> ids = skuList.stream().map(Sku::getId).collect(Collectors.toList());
stockMapper.deleteByIdList(ids);
}
//修改spu
spu.setValid(null);
spu.setSaleable(null);
spu.setCreateTime(null);
spu.setLastUpdateTime(new Date());
int count = spuMapper.updateByPrimaryKeySelective(spu);
if(count!=1)
throw new LyException(ExceptionEnum.GOODS_UPDATE_ERROR);
//修改detail
spuDetailMapper.updateByPrimaryKeySelective(spu.getSpuDetail());
if(count!=1)
throw new LyException(ExceptionEnum.GOODS_UPDATE_ERROR);
//新增sku和库存
saveSkuAndStock(spu);
//发送mq消息
//amqpTemplate.convertAndSend("item.update",spu.getId());
}
ok!