• javaee之黑马乐优商城5


    分析一下spu与sku的数据结构

    再来说一下什么是spu

    standard product unit 标准产品单元 :SPU级别的规格参数通常是与整个产品类型或产品系列相关的通用参数。比如华为手机下面的p系列、荣耀系列,都可以标识为spu级别规格参数

    sku

    stock keeping unit 库存保管单位:SKU级别的规格参数是具体到每个独立的产品变种(SKU)的特有参数。它们描述了每个SKU的唯一特性,如颜色、型号、配置等。

    比如对于同一个spu,下面不同的颜色名称,内存大小,内核数,都构成了不同的sku参数

    那么spu表是整个产品的相关通用信息,具体我们要设计什么样的字段

    我们大致想一下,id,title有个标题,sub_title子标题可能有,可能没有,然后我们还要考虑与分类的关系,我们之前是通过手机这个分类,找到它相关的参数组,然后通过参数组,又去找它具体的子参数,具体的子参数找到了,然后我们就要去找它具体的值,这个值在什么地方存在?我们这里只是简单的设想,这个值是分为了通用参数值,也就是这个参数值大家一起共用,肯定是存放在tb_spu这张表里面,那如果是特殊的值,那就是在sku里面获取。

    上面的大致思想就可以用下面这张图来表示

    回过头来,继续分析字段,那里面还需要有cid,也就是分类的id,只有拿到分类id,才能找到参数组

    然后这个表和品牌表brand表的关系,一个品牌会有多个spu ,比如华为,华为下面有x1系列,x2系列......系列的手机,他每一个手机系列都是一个spu,所以应该有一个brand_id,另外可能就是一些杂七杂八的东西,比如saleable是否上架,valid是否还有效,创建时间和最后修改的时间

    那么我们下面就把这个tb_spu表给创建出来

    但是再去仔细分析一下这张表,也就是说,这张表有没有什么缺漏

    ,似乎没有商品的描述,也没有我们通用规格参数的部分,还有一些共用的,比如包装清单啊,比如售后服务啊之类的

    这些的数据比较大,为了不影响主表的查询效率,我们就把这些数据拆分了出来

    这张表的名字就叫tb_spu_detail,这个表其实就是tb_spu的里面的内容,那我们分析一下字段,上面就是简单的分析了一把

    spu_id这个必有嘛,因为它本身就是spu里面的东西

    description text 存放的是商品的描述信息

    text这个字段我来解释一下

    packing_list varchar(3000) 这些字段设计的都是比较大的,这个是包装清单

    after_service varchar(3000) 售后服务

    下面重点说一下下面两个字段

     generic_spec里面保存的是什么?保存的其实就是通用规格参数数据,这些数据就是每一个spu都会固定的东西,就是说,你不管点哪一个spu,这个通用规格参数都一样

    我们先来看一下这个generic_spec这样一个字段,它保存的是什么样的信息

    说一下,通用规格参数这个参数名是放在tb_spec_param这张表里面的,所以这里设定的是通用值 ,那么如果说,仅仅存放值,没有键的话,他知道是哪一个参数的值吗?很明显不知道,所以这里左边给了tb_spec_param这个表里面的键,右边是值

    下面我们再去看一下special_spec这个字段是怎么样的,这个是保存的sku的特有属性,你在spu里面不具备这样的属性。比如内存,颜色,这就是sku,比如下面这一段参数

     这里面为什么上面每一个参数,它对应的值都是数组类型的呢?

    因为很简单哪怕就是说,同一个spu下面每一个sku,其值都不一样,所以值会有很多,形成数组

    上面说了,说special_spec这个字段,存放的是sku特有的属性,所以这个special_spec里面存放的是规格参数对应的内容数组选项,前者为什么是规格参数,因为具体的参数还是放到tb_spec_param里面,你要给它赋值,就对应tb_spec_param里面的id,然后值呢,是一个数组类型,可供选择。下面我们看一下格式

    下面我们要把从spu拆分出来的细节表tb_spu_detail给做出来

     下面我们就要去分析sku表了

    这张表是特有属性信息,那简单来分析一下它的字段

    id,spu_id(它是哪一个商品下面的sku啊),title'存放商品的标题',images存放图片,这里可能要存放图片的地址,还有price价格,enable这个商品是否有效啊这样一个判定,创建时间,最后修改时间

    还是那句话,重点关注下面两个字段

    这个indexes一看名字就是一个索引的表示?你说它怎么来表示首先我们刚刚分析了一下spu表,我们是在spu表里面插入了特有属性的,这个特有属性它是键值对

    我们查询spu的时候,根据不同的sku组合,我们需要取出这些特殊的键值对 ,那么这里的设计就是,我们选择上面各自分组当中的哪一个值,也就是下面这些组合当中,我们从中怎么去抽取

    继续往下

     先来贴一张他实际存放的值吧

     因此这里存放的就是

     

     下面再来讲own_spec字段

     下面我们要向上面的表插入信息,先向tb_spu表插入数据

    看一下数据库

    在向tb_spu_detail这张表插入商品信息

    看一下这张表的大致内容

     下面向tb_sku里面插入一些信息

     

     下面我们去实现商品查询的部分

    先去分析一下前端页面,首先点击下面这个位置

    就直接会走一个查询

    很明显上面就是spu表的一个查询

    这个商品查询需要实现的效果是如下

     下面分析页面

    找到Goods.vue组件

     

     上面看路径我们就知道,很明显这是对spu表进行的一个查询

    在写具体的业务逻辑之前,先来看一下其他方面的基础知识

     1.PageHelper怎么使用

    首先我们必须知道它是Mybiitas中实现分页的插件,它的原理是通过拦截Mybatis执行sql语句

    我们只需要在服务端,比如service这个地方,就是写业务代码的地方,,在真正的sql实现之前去开启

     注意它这时候给我们只是拼接了sql语句,没有做别的

    类似于下面的拼接

    他会在前端每一次比如点击当前页面显示多少数据,比如下一页,他又会传进来进行执行上面的语句

    在说回来,那我们要给前端一个什么呢?我们就必须传过去关于分页的信息数据,前端才可以获取使用,同时还有实际对象数据

    所以必须传过去PageResult对象 

    2.采用Stream流里面的map方法,把一种流变成另外一种流

    下面直接拿出一个实际案例来讲一下

    3.下面说几个开发过程中的常用工具

    1.BeanUtils工具类 

     

     这个是Spring给我们提供的操作对象的工具

    上面就是把一个对象的数据复制给另外一个对象

    2.StringUtils工具类

     

     下面说一下商品查询的完整思路

    首先,我们分析一下页面需要的数据

    再去看一下spu表

     也就是在数据库中查询的字段就只有id,title在spu表里面存在,那么我们这里就想着在开发中间去扩展一下这个对象

    去对外接口模块里面添加一个supbo对象,生产开发中产生的对象,临时对象,单独放一个包

    我发现我还没创建sup对象,我先把sup这个对象给创建出来

    1. package com.leyou.item.pojo;
    2. import lombok.Data;
    3. import javax.persistence.GeneratedValue;
    4. import javax.persistence.GenerationType;
    5. import javax.persistence.Id;
    6. import javax.persistence.Table;
    7. import java.util.Date;
    8. @Data
    9. @Table(name = "tb_spu")
    10. public class Sup {
    11. @Id
    12. @GeneratedValue(strategy = GenerationType.IDENTITY)
    13. private Long id;
    14. private Long brandId;
    15. private Long cid1;
    16. private Long cid2;
    17. private Long cid3;
    18. private String title;// 标题
    19. private String subTitle;// 子标题
    20. private Boolean saleable;// 是否上架
    21. private Boolean valid;// 是否有效,逻辑删除用
    22. private Date createTime;// 创建时间
    23. private Date lastUpdateTime;// 最后修改时间
    24. }

    下面在去创建SpuBo对象,这个对象需要继承它,然后新增两个查询字段

    目前来讲,我们只需要一下的值

    上面就把我们额外需要的一个对象创建出来了,下面我们把这个查询对象需要的mapper给创建出来

    下面去写controller层面的代码

     我们先去拿到请求路径

     

     这个是操作商品相关的内容,所以控制器就直接是GoodsController,我们去新创建一下这个控制器

    下面我们去goodsService里面实现业务方法

     在完整的代码展示之前,我先贴上在过程中,我们需要调用的方法

    在我们查询三集分类的分类名称的时候,我们要去categoryService里面去实现下面这个方法

    这个方法是调用了通用Mapper的一个根据一个List结合来返回相应数据的Lis集合的这样一个方法

    但这个方法有一个要求就是,你的通用Mapper必须继承下面这个类

     问题报错来了

    因为上面我怎么改都有点问题,于是我把这些步骤拆分了出来

     

    下面在继续去写主干代码

    这里贴上主干代码

    GoodsController

    1. package com.leyou.item.web;
    2. import com.leyou.common.pojo.PageResult;
    3. import com.leyou.item.bo.SpuBo;
    4. import com.leyou.item.service.GoodsService;
    5. import org.springframework.beans.factory.annotation.Autowired;
    6. import org.springframework.http.ResponseEntity;
    7. import org.springframework.web.bind.annotation.GetMapping;
    8. import org.springframework.web.bind.annotation.RequestParam;
    9. import org.springframework.web.bind.annotation.RestController;
    10. @RestController
    11. public class GoodsController {
    12. @Autowired
    13. private GoodsService goodsService;
    14. //下面我们要做的是通过分页查询商品信息
    15. @GetMapping("/spu/page")
    16. public ResponseEntity> querySpuBoByPage (
    17. @RequestParam(value = "page", defaultValue = "1") Integer page,
    18. @RequestParam(value = "rows", defaultValue = "5") Integer rows,
    19. @RequestParam(value = "key",required = false) String key,
    20. @RequestParam(value = "saleable", required = false) Boolean saleable
    21. ) {
    22. //分页查询spu信息
    23. PageResult result = goodsService.querySpuByPageAndSort(page, rows, key, saleable);
    24. if (result == null || result.getItems().size() == 0) {
    25. return ResponseEntity.notFound().build();
    26. }
    27. //正常返回创建成功
    28. return ResponseEntity.ok(result);
    29. }
    30. }

     下面贴上业务层的代码

    GoodsService

    1. package com.leyou.item.service;
    2. import com.github.pagehelper.Page;
    3. import com.github.pagehelper.PageHelper;
    4. import com.leyou.common.pojo.PageResult;
    5. import com.leyou.item.bo.SpuBo;
    6. import com.leyou.item.mapper.BrandMapper;
    7. import com.leyou.item.mapper.SpuMapper;
    8. import com.leyou.item.pojo.Brand;
    9. import com.leyou.item.pojo.Spu;
    10. import org.apache.commons.lang.StringUtils;
    11. import org.springframework.beans.BeanUtils;
    12. import org.springframework.beans.factory.annotation.Autowired;
    13. import org.springframework.stereotype.Service;
    14. import tk.mybatis.mapper.entity.Example;
    15. import java.util.Arrays;
    16. import java.util.List;
    17. import java.util.stream.Collectors;
    18. @Service
    19. public class GoodsService {
    20. //先不考虑引入什么样的mapper
    21. //要查spu,所以要引入spu的mapper对象
    22. @Autowired
    23. private SpuMapper spuMapper;
    24. //我们在想找分类字段的时候,我们必须用到CategoryService里面相应的通过id找到分类的方法
    25. @Autowired
    26. private CategoryService categoryService;
    27. //我们在考虑通过spu里面的商品id去找,直接引入mapper一键搞定
    28. @Autowired
    29. private BrandMapper brandMapper;
    30. public PageResult querySpuByPageAndSort(Integer page, Integer rows, String key, Boolean saleable) {
    31. //这里是查询spu
    32. //返回一个带有分页的结果集
    33. PageHelper.startPage(page,rows);//这个分页会拼到后面的所有sql语句里面
    34. //我们利用通用Mapper来查,我们要设置通用条件
    35. Example example = new Example(Spu.class);
    36. Example.Criteria criteria = example.createCriteria();
    37. //查询上下架
    38. if (saleable != null) {
    39. criteria.orEqualTo("saleable",saleable);
    40. }
    41. //模糊查询如果有key的话
    42. if (StringUtils.isNotBlank(key)) {
    43. criteria.andLike("title","%" + key + "%");
    44. }
    45. //下面通过spuMapper查Spu对象,这个需要一个集合类型的对象
    46. //通过上面的
    47. Page pageInfo = (Page) spuMapper.selectByExample(example);
    48. //上面是得到了一个spu,我们的目的是得到一个List
    49. List list = pageInfo.getResult().stream().map(spu -> {
    50. //处理每一个查寻到的spu对象
    51. //我们要把spu对象变成SpuBo对象
    52. SpuBo spuBo = new SpuBo();//每个对象一进来都会实例一个这个对象
    53. //我们把每一个spu的属性给拷贝一下
    54. BeanUtils.copyProperties(spu,spuBo);
    55. //下面考虑一下问题:1.我们的cname怎么取,也就是这个spu关联的分类
    56. //怎么取?是不是要通过spu里面的cid来取,这是个List
    57. //我们要把它变成字符串集合对象打印
    58. //这个是category表里面的操作,调用categoryService里面的具体方法
    59. //这里面针对这个品牌来讲是三级目录
    60. List names = categoryService.queryNameByIds(Arrays.asList(spu.getCid1(),spu.getCid2(),spu.getCid3()));
    61. //上面我们就先去把这个queryNameByIds这个方法给写出来
    62. //上面就查询到了商品的所属分类
    63. //把分类赋值给Bo对象
    64. spuBo.setCname(StringUtils.join(names,"/"));//格式化一下
    65. //上面查了分类,下面就要去查找品牌
    66. //品牌的查找我们就考虑要引入品牌的servcie还是mapper
    67. //考虑到这里如果mapper能一下给我们找出来,就直接mapper
    68. //如果不能一下找出来,还要经过业务处理,那么就走service
    69. //这里我们通过Brand的Mapper中的主键查询就能找出来,并且没有业务转换,直接引入mapper
    70. Brand brand = brandMapper.selectByPrimaryKey(spu.getBrandId());
    71. spuBo.setBname(brand.getName());
    72. return spuBo;
    73. }).collect(Collectors.toList());//变成了List这样一个集合对象
    74. //注意要给前端返回一个分页对象,并把结果给带过去
    75. //现在就是上面的结果集数据全部都封装到了spuBo这个对象里面
    76. return new PageResult<>(pageInfo.getTotal(),list);
    77. }
    78. }

    然后查看展示效果

  • 相关阅读:
    【二十四】springboot使用EasyExcel和线程池实现多线程导入Excel数据
    MATLAB环境下简单的基于双向长短时记忆网络的时间序列预测
    高速DSP系统设计参考指南(一)高速DSP设计面临的挑战
    JavaScript中的特殊数据类型和其具体用法
    【MySQL】22-MySQL数据类型超详细汇总
    使用VScode调试与编写bash脚本
    linux syslog日志转发服务端、客户端配置
    阿里在开源领域又有哪些新动向?来首届阿里开源开放周找答案!
    联动枚举设计
    CF - C. Card Game(博弈,递推)
  • 原文地址:https://blog.csdn.net/Pxx520Tangtian/article/details/133044522