SPU和SKU
SPU:standard product unit(标准化产品单元):是商品信息聚合的最小单位,是一组可复用、易检索的标准化信息的集合,该集合描述了一个产品的特性。如iphone13是SPU,它是一个产品的集合
**SKU:stock keeping unit(库存量单位):**库存进出计量的基本单元,可以是件/盒/托盘等单位。
SKU是对于大型连锁超市DC配送中心物流管理的一个必要的方法。现在已经被引申为产品统一编号的简称,每种产品对应有唯一的SKU号。如iphone13ProMax 1T 蓝色 是SKU,包子店中肉包子是SKU,素包子是SKU,水煎包是SKU…
规格参数和销售属性
像这里的商品介绍,规格与包装都是属于SPU的属性。它们都属于是规格参数
像版本,颜色等都属是SKU的销售属性
表的关系理解
(1)属性关系-规格参数-销售属性-三级分类 关联关系
每个三级分类下有各自的属性分组表通过id和catelogid关联,能查出每个分类下的属性分组
属性分组表和属性表通过一个属性&属性关联表进行关联,能查出每个属性分组下的属性
最终这样的关系我们可以查出每个分类的属性分组和每个属性分组对应的属性
(2)通过思维导图来理解
手机是一级分类,它下面又有属性组,每个属性组又有各自的属性
(3)SPU-SKU属性表
商品属性表和属性表通过attrid和id进行关联,能查出每个spu的属性
sku销售属性表是为了表示spu下不同sku,比如1号spu在此表有两个sku,这两个sku有不同的销售属性,是通过和属性表关联获取的
(4)通过思维导图来理解
像网络、像素一般是固定不可选的所以是SPU属性
而内存、容量、颜色等可选的就为SKU销售属性
导入前端代码
(1)重新执行“sys_menus.sql”,完善菜单。
正常我们是在系统管理里自定义添加,步骤都是一样的,其实在前端页面添加就是把数据提交到mall_admin表中,这里我们直接把提供的sql语句导入即可!
如下结果:
(2)实现点击菜单的左边,能够实现在右边展示数据
这个页面就是三级分类和一个表格显示在一块对吧,属于是父子组件交互
前端不具体写了,我们直接导入代码,效果如下:
因为数据库没数据,所以这里不显示
完善后端接口
接口开发流程
什么是开发接口?
开发接口就是开发Controller、service、dao
在线接口文档如下https://easydoc.net/s/78237135/ZUqEdvA4/OXTgKobR
别人告诉你需要什么功能,需要返回什么样的数据,你就通过接口的形式把他们呢实现出来即可!
以后工作了也是这种形式,主要是开发接口为多,前端其实不用写太多,能看懂即可!!!
开发思路
思路:
- 根据接口文档写接口
- 代码中大部分接口已自动生成(MBG),所以我们在前端页面看哪个请求失败
- 后端改接口
这一部分都是CRUD相关的代码,所以要好好练好好写!!!
属性分组详情
显示属性分组
接口如下:
controller
@RequestMapping("/list/{catelogId}") public R list(@RequestParam Map<String, Object> params, @PathVariable("catelogId") Long catelogId){ // PageUtils page = attrGroupService.queryPage(params); PageUtils page = attrGroupService.queryPage(params, catelogId); return R.ok().put("page", page); }
service
这里注意,前端有两个查询按钮
查询和查询全部
这两个都要有模糊查询的功能!
PageUtils queryPage(Map<String, Object> params, Long catelogId); @Override public PageUtils queryPage(Map<String, Object> params, Long catelogId) { //多条件查询 String key = (String) params.get("key"); QueryWrapper<AttrGroupEntity> wrapper = new QueryWrapper<>(); if (!StringUtils.isEmpty(key)) { wrapper.and((obj) -> { obj.eq("attr_group_id",key).or().like("attr_group_name",key); }); } if (catelogId == 0) { //如果是默认的是查全部的一级分类 IPage<AttrGroupEntity> page = this.page( new Query<AttrGroupEntity>().getPage(params), wrapper); return new PageUtils(page); } else { wrapper.eq("catelog_id", catelogId); IPage<AttrGroupEntity> page = this.page( new Query<AttrGroupEntity>().getPage(params), wrapper); return new PageUtils(page); } }
测试
属性分组回显
这一部分主要是做属性分组的数据回显的
接口如下:
前端这里省略,需要去elementui找组件,改数据
controller
/** * 信息 */ @RequestMapping("/info/{attrId}") public R info(@PathVariable("attrId") Long attrId){ AttrEntity attr = attrService.getById(attrId); Long catelogId = attr.getCatelogId(); Long[] path = categoryService.findCatelogPath(catelogId); attr.setCatelogPath(path); return R.ok().put("attr", attr); }
service
获取分类路径id
通过递归操作完成
过程
给一个分类id,不断的查它的父类id直到查不到为止,最后把查询到的id到放到一个集合里
怎样写好递归?
- 确定参数值和返回值
- 确定终止条件
- 递归逻辑
三者缺一不可!!!
//找到catelogId的完整路径:[父/子/孙] @Override public Long[] findCatelogPath(Long catelogId) { ArrayList<Long> list = new ArrayList<>(); List<Long> parentPath = findParentPath(catelogId, list);//1.确定递归参数和返回值 Collections.reverse(parentPath); return (Long[]) list.toArray(new Long[parentPath.size()]); } private List<Long> findParentPath(Long catelogId,ArrayList<Long> list){ //3.递归逻辑 list.add(catelogId); CategoryEntity entity = this.getById(catelogId); if (entity.getParentCid()!=0){//2.递归终止条件 findParentPath(entity.getParentCid(),list); } return list; }
测试
返回属性的父路径id